Repository: mtamer/python-rsi
Branch: master
Commit: 406e9f5223ea
Files: 7
Total size: 15.2 KB
Directory structure:
gitextract_1_kn1di5/
├── .gitignore
├── .vscode/
│ └── settings.json
├── README.md
└── src/
├── main.py
├── requirements.txt
├── stock.py
└── stocks.txt
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Taken from https://github.com/github/gitignore/blob/master/Python.gitignore
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
================================================
FILE: .vscode/settings.json
================================================
{
"python.pythonPath": "/usr/bin/python3"
}
================================================
FILE: README.md
================================================
# python-rsi
RSI (Relative Strength Index) written in Python

## About
Relative Strength Index written in Python. The whole point of this application is to be able to come up with a list of as many different types of stocks (stock tickers) that you want to screen and see if it meets the Relative Strength criteria. A combination of the RSI and the 20 and 200 day Moving Average (MA) tend to be strong and popular indicators to determine the future behavior of a stock.
At the end of pulling stock data, a table is shown displaying metrics of the stocks pulled along with a link to view the chart.

## To Install
1. Clone repo: `git clone https://github.com/mtamer/python-rsi.git`
2. `cd src`
3. `pip install -r requirements.txt`
4. Look inside the `main.py` file and put all the stocks you want to monitor in there or inside of `stocks.txt`
5. To run: `python main.py`
6. Enjoy!
## Disclaimer
This repository is only for educational purposes. The owner and contributors of this repository are not responsible for how you use this code and the gains/losses you accumulate.
================================================
FILE: src/main.py
================================================
#!/usr/bin/env python3
import datetime
import random
import time
from urllib.request import urlopen
import matplotlib
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np
import pandas_datareader.data as web
import pylab
from mplfinance.original_flavor import candlestick_ohlc
from pandas.core.common import flatten
from tabulate import tabulate
from stock import Stock
matplotlib.rcParams.update({'font.size': 9})
stocks = []
# If stocks array is empty, pull stock list from stocks.txt file
stocks = stocks if len(stocks) > 0 else [
line.rstrip() for line in open("stocks.txt", "r")]
# Time frame you want to pull data from
start = datetime.datetime.now()-datetime.timedelta(days=365)
end = datetime.datetime.now()
if __name__ == "__main__":
# Array of moving averages you want to get
MAarr = [20, 200]
allData = []
for ticker in stocks:
try:
data = []
print("Pulling data for " + ticker)
stock = Stock(ticker, start, end)
# Append data to array
data.append(ticker.upper())
data.append(stock.closes[-1])
for MA in MAarr:
computedSMA = stock.SMA(period=MA)
# print(computedSMA)
data.append(computedSMA[-1])
currentRsi = float("{:.2f}".format(stock.rsi[-1]))
if currentRsi > 70:
data.append(str(currentRsi) + " 🔥")
elif currentRsi < 30:
data.append(str(currentRsi) + " 🧊")
else:
data.append(currentRsi)
chartLink = "https://finance.yahoo.com/quote/" + ticker + "/chart?p=" + ticker
data.append(chartLink)
allData.append(data)
# Shows chart only if current RSI is greater than or less than 70 or 30 respectively
if currentRsi < 30 or currentRsi > 70:
stock.graph(MAarr)
except Exception as e:
print('Error: ', str(e))
print(tabulate(allData, headers=flatten([
'Stock', 'Price', [str(x) + " MA" for x in MAarr], "RSI", "chart"])))
================================================
FILE: src/requirements.txt
================================================
astroid==2.4.2
autopep8==1.5.3
certifi==2020.4.5.2
chardet==3.0.4
colorama==0.4.3
cycler==0.10.0
idna==2.9
isort==4.3.21
kiwisolver==1.2.0
lazy-object-proxy==1.4.3
lxml==4.5.1
matplotlib==3.2.2
mccabe==0.6.1
mplfinance==0.12.5a3
numpy==1.18.5
pandas==1.0.5
pandas-datareader==0.8.1
pycodestyle==2.6.0
pylint==2.5.3
pyparsing==2.4.7
python-dateutil==2.8.1
pytz==2020.1
requests==2.24.0
six==1.15.0
tabulate==0.8.7
toml==0.10.1
typed-ast==1.4.1
urllib3==1.25.9
wrapt==1.12.1
================================================
FILE: src/stock.py
================================================
#!/usr/bin/env python3
import datetime
import random
from urllib.request import urlopen
import matplotlib
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np
import pandas_datareader.data as web
import pylab
from mplfinance.original_flavor import candlestick_ohlc
matplotlib.rcParams.update({'font.size': 9})
class Stock:
ticker = None
dates = None
closes = None
highs = None
lows = None
opens = None
volumes = None
rsi = None
def __init__(self, ticker, start, end=datetime.datetime.now()):
self.ticker = ticker
"""
Different sources for pulling data can be found here:
https://readthedocs.org/projects/pandas-datareader/downloads/pdf/latest/
"""
stockData = web.DataReader(ticker, 'yahoo', start, end)
self.dates = [mdates.date2num(d) for d in stockData.index]
self.closes = stockData['Close']
self.highs = stockData['High']
self.lows = stockData['Low']
self.opens = stockData['Open']
self.volumes = stockData['Volume']
self.rsi = self.RSI(self.closes)
def RSI(self, prices, n=14):
deltas = np.diff(prices)
seed = deltas[:n+1]
up = seed[seed >= 0].sum()/n
down = -seed[seed < 0].sum()/n
rs = up/down
rsi = np.zeros_like(prices)
rsi[:n] = 100. - 100./(1.+rs)
for i in range(n, len(prices)):
delta = deltas[i-1] # The diff is 1 shorter
if delta > 0:
upval = delta
downval = 0.
else:
upval = 0.
downval = -delta
up = (up*(n-1) + upval)/n
down = (down*(n-1) + downval)/n
rs = up/down
rsi[i] = 100. - 100./(1.+rs)
return rsi
def SMA(self, period, values=None):
values = self.closes if values is None else values
"""
Simple Moving Average. Periods are the time frame. For example, a period of 50 would be a 50 day
moving average. Values are usually the stock closes but can be passed any values
"""
weigths = np.repeat(1.0, period)/period
smas = np.convolve(values, weigths, 'valid')
return smas # as a numpy array
def EMA(self, period, values=None):
values = self.closes if values is None else values
"""
Exponential Moving Average. Periods are the time frame. For example, a period of 50 would be a 50 day
moving average. Values are usually the stock closes but can be passed any values
"""
weights = np.exp(np.linspace(-1., 0., period))
weights /= weights.sum()
a = np.convolve(values, weights, mode='full')[:len(values)]
a[:period] = a[period]
return a
def MACD(self, x, slow=26, fast=12):
"""
Compute the MACD (Moving Average Convergence/Divergence) using a fast and slow exponential moving avg'
return value is emaslow, emafast, macd which are len(x) arrays
"""
emaslow = self.EMA(slow, x)
emafast = self.EMA(fast, x)
return emaslow, emafast, emafast - emaslow
def graph(self, movingAverageArr=[]):
try:
x = 0
y = len(self.dates)
newAr = []
while x < y:
appendLine = self.dates[x], self.opens[x], self.closes[x], self.highs[x], self.lows[x], self.volumes[x]
newAr.append(appendLine)
x += 1
# Fix this
SP = len(self.dates[200-1:])
fig = plt.figure(facecolor='#07000d')
ax1 = plt.subplot2grid(
(6, 4), (1, 0), rowspan=4, colspan=4, facecolor='#07000d')
candlestick_ohlc(ax1, newAr[-SP:], width=.6,
colorup='#53c156', colordown='#ff1717')
for MA in movingAverageArr:
computedSMA = self.SMA(MA, self.closes)
# Used to generate random hex color to put on graph
def r(): return random.randint(0, 255)
randomColor = '#%02X%02X%02X' % (r(), r(), r())
maLabel = str(MA) + ' SMA'
ax1.plot(self.dates[-SP:], computedSMA[-SP:], randomColor,
label=maLabel, linewidth=1.5)
ax1.grid(False, color='w')
ax1.xaxis.set_major_locator(mticker.MaxNLocator(10))
ax1.xaxis.set_major_formatter(
mdates.DateFormatter('%Y-%m-%d'))
ax1.yaxis.label.set_color("w")
ax1.spines['bottom'].set_color("#5998ff")
ax1.spines['top'].set_color("#5998ff")
ax1.spines['left'].set_color("#5998ff")
ax1.spines['right'].set_color("#5998ff")
ax1.tick_params(axis='y', colors='w')
plt.gca().yaxis.set_major_locator(mticker.MaxNLocator(prune='upper'))
ax1.tick_params(axis='x', colors='w')
plt.ylabel('Stock price and Volume')
maLeg = plt.legend(loc=9, ncol=2, prop={'size': 7},
fancybox=True, borderaxespad=0.)
maLeg.get_frame().set_alpha(0.4)
textEd = pylab.gca().get_legend().get_texts()
pylab.setp(textEd[0:5], color='w')
volumeMin = 0
ax0 = plt.subplot2grid(
(6, 4), (0, 0), sharex=ax1, rowspan=1, colspan=4, facecolor='#07000d')
rsiCol = '#c1f9f7'
posCol = '#386d13'
negCol = '#8f2020'
ax0.plot(self.dates[-SP:], self.rsi[-SP:],
rsiCol, linewidth=1.5)
ax0.axhline(70, color=negCol)
ax0.axhline(30, color=posCol)
ax0.fill_between(self.dates[-SP:], self.rsi[-SP:], 70, where=(self.rsi[-SP:]
>= 70), facecolor=negCol, edgecolor=negCol, alpha=0.5)
ax0.fill_between(self.dates[-SP:], self.rsi[-SP:], 30, where=(self.rsi[-SP:]
<= 30), facecolor=posCol, edgecolor=posCol, alpha=0.5)
ax0.set_yticks([30, 70])
ax0.yaxis.label.set_color("w")
ax0.spines['bottom'].set_color("#5998ff")
ax0.spines['top'].set_color("#5998ff")
ax0.spines['left'].set_color("#5998ff")
ax0.spines['right'].set_color("#5998ff")
ax0.tick_params(axis='y', colors='w')
ax0.tick_params(axis='x', colors='w')
plt.ylabel('RSI')
ax1v = ax1.twinx()
ax1v.fill_between(self.dates[-SP:], volumeMin,
self.volumes[-SP:], facecolor='#00ffe8', alpha=.4)
ax1v.axes.yaxis.set_ticklabels([])
ax1v.grid(False)
# Edit this to 3, so it's a bit larger
ax1v.set_ylim(0, 3*self.volumes.max())
ax1v.spines['bottom'].set_color("#5998ff")
ax1v.spines['top'].set_color("#5998ff")
ax1v.spines['left'].set_color("#5998ff")
ax1v.spines['right'].set_color("#5998ff")
ax1v.tick_params(axis='x', colors='w')
ax1v.tick_params(axis='y', colors='w')
ax2 = plt.subplot2grid(
(6, 4), (5, 0), sharex=ax1, rowspan=1, colspan=4, facecolor='#07000d')
fillcolor = '#00ffe8'
nslow = 26
nfast = 12
nema = 9
emaslow, emafast, macd = self.MACD(self.closes)
ema9 = self.EMA(nema, macd)
ax2.plot(self.dates[-SP:], macd[-SP:],
color='#4ee6fd', lw=2)
ax2.plot(self.dates[-SP:], ema9[-SP:],
color='#e1edf9', lw=1)
ax2.fill_between(self.dates[-SP:], macd[-SP:]-ema9[-SP:], 0,
alpha=0.5, facecolor=fillcolor, edgecolor=fillcolor)
plt.gca().yaxis.set_major_locator(mticker.MaxNLocator(prune='upper'))
ax2.spines['bottom'].set_color("#5998ff")
ax2.spines['top'].set_color("#5998ff")
ax2.spines['left'].set_color("#5998ff")
ax2.spines['right'].set_color("#5998ff")
ax2.tick_params(axis='x', colors='w')
ax2.tick_params(axis='y', colors='w')
plt.ylabel('MACD', color='w')
ax2.yaxis.set_major_locator(
mticker.MaxNLocator(nbins=5, prune='upper'))
for label in ax2.xaxis.get_ticklabels():
label.set_rotation(45)
plt.suptitle(self.ticker.upper(), color='w')
plt.setp(ax0.get_xticklabels(), visible=False)
plt.setp(ax1.get_xticklabels(), visible=False)
# ax1.annotate('Look Here!', (date[-1], Av1[-1]),
# xytext=(0.8, 0.9), textcoords='axes fraction',
# arrowprops=dict(facecolor='white', shrink=0.05),
# fontsize=14, color='w',
# horizontalalignment='right', verticalalignment='bottom')
plt.subplots_adjust(left=.09, bottom=.14,
right=.94, top=.95, wspace=.20, hspace=0)
plt.show()
fig.savefig('example.png', facecolor=fig.get_facecolor())
except Exception as e:
print('Error graphing data: ', str(e))
================================================
FILE: src/stocks.txt
================================================
baba
roku
msft
amzn
tqqq
nvda
vgt
twtr
dis
t
snap
tsla
gitextract_1_kn1di5/
├── .gitignore
├── .vscode/
│ └── settings.json
├── README.md
└── src/
├── main.py
├── requirements.txt
├── stock.py
└── stocks.txt
SYMBOL INDEX (7 symbols across 1 files)
FILE: src/stock.py
class Stock (line 19) | class Stock:
method __init__ (line 30) | def __init__(self, ticker, start, end=datetime.datetime.now()):
method RSI (line 49) | def RSI(self, prices, n=14):
method SMA (line 76) | def SMA(self, period, values=None):
method EMA (line 89) | def EMA(self, period, values=None):
method MACD (line 104) | def MACD(self, x, slow=26, fast=12):
method graph (line 114) | def graph(self, movingAverageArr=[]):
Condensed preview — 7 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (17K chars).
[
{
"path": ".gitignore",
"chars": 2113,
"preview": "# Taken from https://github.com/github/gitignore/blob/master/Python.gitignore\n\n# Byte-compiled / optimized / DLL files\n_"
},
{
"path": ".vscode/settings.json",
"chars": 47,
"preview": "{\n \"python.pythonPath\": \"/usr/bin/python3\"\n}"
},
{
"path": "README.md",
"chars": 1277,
"preview": "# python-rsi\n\nRSI (Relative Strength Index) written in Python\n\n. The extraction includes 7 files (15.2 KB), approximately 4.4k tokens, and a symbol index with 7 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.