Skip to content

Commit 449fe54

Browse files
Merge branch 'master' of github.com:AurumnPegasus/mplfinance
2 parents 328cf51 + ce83ee5 commit 449fe54

File tree

15 files changed

+377
-8
lines changed

15 files changed

+377
-8
lines changed
+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
name: mplfinance Checks
2+
on: [ push, pull_request ]
3+
jobs:
4+
Regression_Tests:
5+
runs-on: ubuntu-latest
6+
strategy:
7+
matrix:
8+
python-version: [3.6, 3.7, 3.8, 3.9]
9+
steps:
10+
- name: Preliminary Information
11+
run: |
12+
echo "The job was automatically triggered by a ${{ github.event_name }} event."
13+
echo "This job is now running on a ${{ runner.os }} server hosted by GitHub!"
14+
echo "The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
15+
echo " "
16+
echo "github.ref = ${{ github.ref }}"
17+
echo "github.sha = ${{ github.sha }}"
18+
echo "github.event.pull_request.head.ref = ${{ github.event.pull_request.head.ref }}"
19+
echo "github.event.pull_request.head.sha = ${{ github.event.pull_request.head.sha }}"
20+
echo "github.event.pull_request.base.ref = ${{ github.event.pull_request.base.ref }}"
21+
echo "github.event.pull_request.base.sha = ${{ github.event.pull_request.base.sha }}"
22+
echo " "
23+
24+
- name: Check out repository code
25+
uses: actions/checkout@v2
26+
27+
- run: echo "The ${{ github.repository }} repository has been cloned to the runner."
28+
29+
- name: Set up Python ${{ matrix.python-version }}
30+
uses: actions/setup-python@v2
31+
with:
32+
python-version: ${{ matrix.python-version }}
33+
34+
- name: Install dependencies
35+
run: |
36+
python -m pip install --upgrade pip
37+
pip install pytest
38+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
39+
40+
- name: Install My Package
41+
run: pip install .
42+
43+
- name: Run Pytest
44+
run: python -m pytest
45+
46+
- run: echo "This job's status is ${{ job.status }}."
47+
48+
Pull_Request_Updates_Version:
49+
runs-on: ubuntu-latest
50+
if: github.event_name == 'pull_request'
51+
steps:
52+
- name: Check out repository code
53+
uses: actions/checkout@v2
54+
55+
- name: Set up Python ${{ matrix.python-version }}
56+
uses: actions/setup-python@v2
57+
with:
58+
python-version: '3.10'
59+
60+
- name: Install dependencies
61+
run: |
62+
python -m pip install --upgrade pip
63+
pip install packaging
64+
65+
- name: Fetch base and head on PR
66+
if: ${{ github.event.pull_request.base.sha }}
67+
run: |
68+
git fetch origin master ${{ github.event.pull_request.base.sha }}
69+
git fetch origin master ${{ github.event.pull_request.head.sha }}
70+
71+
- name: Check that Pull Request includes updating the Version
72+
run: |
73+
git show ${{ github.event.pull_request.base.sha }}:src/mplfinance/_version.py > scripts/tv0.py
74+
git show ${{ github.sha }}:src/mplfinance/_version.py > scripts/tv1.py
75+
python scripts/version_update_check.py tv0 tv1
76+

README.md

+5-2
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,10 @@ Notice, in the above chart, there are no gaps along the x-coordinate, even thoug
264264

265265
- However, sometimes people like to see these gaps, so that they can tell, with a quick glance, where the weekends and holidays fall.
266266

267-
- Non-trading days can be displayed with the `show_nontrading` keyword.
267+
- Non-trading days can be displayed with the **`show_nontrading`** keyword.
268+
- Note that for these purposes **non-trading** intervals are those that ***are not represented in the data at all***. (There are simply no rows for those dates or datetimes). This is because, when data is retrieved from an exchange or other market data source, that data typically will *not* include rows for non-trading days (weekends and holidays for example). Thus ...
269+
- **`show_nontrading=True`** will display all dates (all time intervals) between the first time stamp and the last time stamp in the data (regardless of whether rows exist for those dates or datetimes).
270+
- **`show_nontrading=False`** (the default value) will show ***only*** dates (or datetimes) that have actual rows in the data. (This means that if there are rows in your DataFrame that exist but contain only **`NaN`** values, these rows *will still appear* on the plot even if **`show_nontrading=False`**)
268271
- For example, in the chart below, you can easily see weekends, as well as a gap at Thursday, November 28th for the U.S. Thanksgiving holiday.
269272

270273

@@ -584,7 +587,7 @@ It is my intention to archive the `matplotlib/mpl-finance` repository soon, and
584587

585588
**With this new ` mplfinance ` package installed, in addition to the new API, users can still access the old API**.<br> The old API may be removed someday, but for the foreseeable future we will keep it ... at least until we are very confident that users of the old API can accomplish the same things with the new API.
586589

587-
To access the old API with the new ` mplfinance ` package installed, change the old import statments
590+
To access the old API with the new ` mplfinance ` package installed, change the old import statements
588591

589592
**from:**
590593

tox.ini renamed to archive.tox.ini

File renamed without changes.
File renamed without changes.

examples/mpf_demo.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import pandas as pd
2+
import mplfinance as mpf
3+
4+
infile = 'data/yahoofinance-SPY-20200901-20210113.csv'
5+
6+
df = pd.read_csv(infile, index_col=0, parse_dates=True).iloc[0:60]
7+
8+
# mpf.plot(df,figscale=1.5,type='candle',mav=(10,20))
9+
10+
11+
12+
13+
#mpf.plot(df,type='candle',figscale=1.5)
14+
15+
#df = pd.read_csv(infile, index_col=0, parse_dates=True).iloc[0:180]
16+
#mpf.plot(df,type='renko',figscale=1.5)
17+
#mpf.plot(df,type='pnf',figscale=1.5)
18+
19+
#mpf.plot(df,type='candle',figscale=1.5,mav=10)
20+
21+
mpf.plot(df,type='candle',volume=True,mav=(10,20),figscale=1.5)

examples/mpf_rsi_demo.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import pandas as pd
2+
import mplfinance as mpf
3+
4+
infile = 'data/yahoofinance-SPY-20200901-20210113.csv'
5+
6+
df = pd.read_csv(infile, index_col=0, parse_dates=True).iloc[0:60]
7+
8+
import rsi
9+
df['rsi'] = rsi.relative_strength(df['Close'],n=7)
10+
11+
print(df.head())
12+
print(df.tail())
13+
14+
apd = mpf.make_addplot(df['rsi'],panel=2,color='lime',ylim=(10,90),secondary_y=True)
15+
16+
mpf.plot(df,type='candle',volume=True,mav=(10,20),figscale=1.5,addplot=apd,panel_ratios=(1,0.6))
17+
mpf.plot(df,type='candle',style='charles',volume=True,mav=(10,20),figscale=1.5,addplot=apd,panel_ratios=(1,0.6))
18+
mpf.plot(df,type='candle',style='mike',volume=True,mav=(10,20),figscale=1.5,addplot=apd,panel_ratios=(1,0.6))
19+
mpf.plot(df,type='candle',style='checkers',volume=True,mav=(10,20),figscale=1.5,addplot=apd,panel_ratios=(1,0.6))
20+
mpf.plot(df,type='candle',style='yahoo',volume=True,mav=(10,20),figscale=1.5,addplot=apd,panel_ratios=(1,0.6))

examples/rsi.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import numpy as np
2+
def relative_strength(prices, n=14):
3+
"""
4+
compute the n period relative strength indicator
5+
http://stockcharts.com/school/doku.php?id=chart_school:glossary_r#relativestrengthindex
6+
http://www.investopedia.com/terms/r/rsi.asp
7+
"""
8+
deltas = np.diff(prices)
9+
seed = deltas[:n + 1]
10+
up = seed[seed >= 0].sum() / n
11+
down = -seed[seed < 0].sum() / n
12+
rs = up / down
13+
rsi = np.zeros_like(prices)
14+
rsi[:n] = 100. - 100. / (1. + rs)
15+
16+
for i in range(n, len(prices)):
17+
delta = deltas[i - 1] # cause the diff is 1 shorter
18+
19+
if delta > 0:
20+
upval = delta
21+
downval = 0.
22+
else:
23+
upval = 0.
24+
downval = -delta
25+
26+
up = (up * (n - 1) + upval) / n
27+
down = (down * (n - 1) + downval) / n
28+
29+
rs = up / down
30+
rsi[i] = 100. - 100. / (1. + rs)
31+
32+
return rsi
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from select import select
2+
from datetime import datetime
3+
4+
import time
5+
import pandas as pd
6+
import mplfinance as mpf
7+
import sys
8+
9+
coin = 'BTC'
10+
bot_status = 'trading'
11+
12+
def limit():
13+
timeout = 2.5
14+
print(end='')
15+
rlist, _, _ = select([sys.stdin], [], [], timeout)
16+
print('rlist=',rlist)
17+
if rlist:
18+
s = sys.stdin.readline().strip()
19+
print('s=',s)
20+
if s == 'g':
21+
print('\033[1;34m show chart')
22+
chart()
23+
24+
25+
def dataframe():
26+
# response = **_api exchange_**.candles(coin + '-EUR', '1m', {})
27+
# ohlcv = []
28+
# for s in range(len(response)):
29+
# timestamp = (int(response[s][0]))/1000
30+
# open = float(response[s][1])
31+
# high = float(response[s][2])
32+
# low = float(response[s][3])
33+
# close = float(response[s][4])
34+
# volume = float(response[s][5])
35+
# candles = {'timestamp': (datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S')), 'open': open, 'high': high, 'low': low, 'close': close, 'volume': volume}
36+
# ohlcv.append(candles)
37+
# dataframe = pd.DataFrame(data=ohlcv, dtype=float)
38+
dataframe = pd.read_csv('../../data/SP500_NOV2019_Hist.csv',index_col=0, parse_dates=True)
39+
return dataframe
40+
41+
42+
def chart():
43+
df = dataframe()
44+
df.index = pd.DatetimeIndex(df['timestamp'])
45+
df = df.iloc[::-1]
46+
s = mpf.make_mpf_style(base_mpf_style='charles', gridcolor='#555555', gridstyle="--", rc={'axes.edgecolor': 'white', 'font.size': 5})
47+
fig, axlist = mpf.plot(df, type='candle', style=s, title= coin, ylabel = 'Price (€)', volume=True, warn_too_much_data=9999999, returnfig=True)
48+
mpf.show(block=True)
49+
50+
51+
# trade loop
52+
while bot_status == 'trading':
53+
limit()
54+
print('test')
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import mplfinance as mpf
2+
import pandas as pd
3+
4+
#daily = pd.read_csv('/Users/jsb/Desktop/mplfinance-master/examples/data/SP500_NOV2019_Hist.csv',
5+
# index_col=0, parse_dates=True)
6+
daily = pd.read_csv('../../data/SP500_NOV2019_Hist.csv',
7+
index_col=0, parse_dates=True)
8+
daily.index.name = 'Date'
9+
# print(daily.shape)
10+
print(daily)
11+
# daily = daily.loc[:, ['Open', 'High', 'Low', 'Close', 'Volume']]
12+
13+
mpf.figure(figsize=(20, 8), dpi=100)
14+
15+
mpf.plot(daily, type='candle', tight_layout=True)
+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
### !pip install yfinance
2+
### !pip install mplfinance
3+
import yfinance as yf
4+
import mplfinance as mpf
5+
import numpy as np
6+
import pandas as pd
7+
8+
# get the data from yfiance
9+
df=yf.download('BTC-USD',start='2008-01-04',end='2021-06-3',interval='1d')
10+
11+
#code snippet 5.1
12+
# Fit linear regression on close
13+
# Return the t-statistic for a given parameter estimate.
14+
def tValLinR(close):
15+
#tValue from a linear trend
16+
x = np.ones((close.shape[0],2))
17+
x[:,1] = np.arange(close.shape[0])
18+
ols = sm1.OLS(close, x).fit()
19+
return ols.tvalues[1]
20+
21+
#code snippet 5.2
22+
'''
23+
#search for the maximum absolutet-value. To identify the trend
24+
# - molecule - index of observations we wish to labels.
25+
# - close - which is the time series of x_t
26+
# - span - is the set of values of L (look forward period) that the algorithm will #try (window_size)
27+
# The L that maximizes |tHat_B_1| (t-value) is choosen - which is the look-forward #period
28+
# with the most significant trend. (optimization)
29+
'''
30+
def getBinsFromTrend(molecule, close, span):
31+
32+
#Derive labels from the sign of t-value of trend line
33+
#output includes:
34+
# - t1: End time for the identified trend
35+
# - tVal: t-value associated with the estimated trend coefficient
36+
#- bin: Sign of the trend (1,0,-1)
37+
#The t-statistics for each tick has a different look-back window.
38+
39+
#- idx start time in look-forward window
40+
#- dt1 stop time in look-forward window
41+
#- df1 is the look-forward window (window-size)
42+
#- iloc ?
43+
44+
out = pd.DataFrame(index=molecule, columns=['t1', 'tVal', 'bin', 'windowSize'])
45+
hrzns = range(*span)
46+
windowSize = span[1] - span[0]
47+
maxWindow = span[1]-1
48+
minWindow = span[0]
49+
for idx in close.index:
50+
idx += (maxWindow*pd.Timedelta('1 day'))
51+
if idx >= close.index[-1]:
52+
break
53+
df_tval = pd.Series(dtype='float64')
54+
iloc0 = close.index.get_loc(idx)
55+
if iloc0+max(hrzns) > close.shape[0]:
56+
continue
57+
for hrzn in hrzns:
58+
dt1 = close.index[iloc0-hrzn+1]
59+
df1 = close.loc[dt1:idx]
60+
df_tval.loc[dt1] = tValLinR(df1.values) #calculates t-statistics on period
61+
dt1 = df_tval.replace([-np.inf, np.inf, np.nan], 0).abs().idxmax() #get largest t-statistics calculated over span period
62+
63+
print(df_tval.index[-1])
64+
print(dt1)
65+
print(abs(df_tval.values).argmax() + minWindow)
66+
out.loc[idx, ['t1', 'tVal', 'bin', 'windowSize']] = df_tval.index[-1], df_tval[dt1], np.sign(df_tval[dt1]), abs(df_tval.values).argmax() + minWindow #prevent leakage
67+
out['t1'] = pd.to_datetime(out['t1'])
68+
out['bin'] = pd.to_numeric(out['bin'], downcast='signed')
69+
70+
#deal with massive t-Value outliers - they dont provide more confidence and they ruin the scatter plot
71+
tValueVariance = out['tVal'].values.var()
72+
tMax = 20
73+
if tValueVariance < tMax:
74+
tMax = tValueVariance
75+
76+
out.loc[out['tVal'] > tMax, 'tVal'] = tMax #cutoff tValues > 20
77+
out.loc[out['tVal'] < (-1)*tMax, 'tVal'] = (-1)*tMax #cutoff tValues < -20
78+
return out.dropna(subset=['bin'])
79+
80+
if __name__ == '__main__':
81+
#snippet 5.3
82+
idx_range_from = 3
83+
idx_range_to = 10
84+
df1 = getBinsFromTrend(df.index, df['Close'], [idx_range_from,idx_range_to,1]) #[3,10,1] = range(3,10) This is the issue
85+
tValues = df1['tVal'].values #tVal
86+
87+
doNormalize = False
88+
#normalise t-values to -1, 1
89+
if doNormalize:
90+
np.min(tValues)
91+
minusArgs = [i for i in range(0, len(tValues)) if tValues[i] < 0]
92+
tValues[minusArgs] = tValues[minusArgs] / (np.min(tValues)*(-1.0))
93+
94+
plus_one = [i for i in range(0, len(tValues)) if tValues[i] > 0]
95+
tValues[plus_one] = tValues[plus_one] / np.max(tValues)
96+
97+
#+(idx_range_to-idx_range_from+1)
98+
plt.scatter(df1.index, df0.loc[df1.index].values, c=tValues, cmap='viridis') #df1['tVal'].values, cmap='viridis')
99+
plt.plot(df0.index, df0.values, color='gray')
100+
plt.colorbar()
101+
plt.show()
102+
plt.savefig('fig5.2.png')
103+
plt.clf()
104+
plt.df['Close']()
105+
plt.scatter(df1.index, df0.loc[df1.index].values, c=df1['bin'].values, cmap='vipridis')
106+
107+
#Test methods
108+
ols_tvalue = tValLinR( np.array([3.0, 3.5, 4.0]) )

pytest.ini

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[pytest]
2+
python_files = tests/*

scripts/version_update_check.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import os
2+
import sys
3+
import importlib
4+
from packaging import version
5+
6+
if len(sys.argv) < 3:
7+
raise RuntimeError('Got less than 2 Version Arguments!')
8+
9+
debug = True if (len(sys.argv) > 3 and sys.argv[3] == 'debug') else False
10+
11+
v0 = importlib.import_module(sys.argv[1])
12+
pv0 = version.parse(v0.__version__)
13+
14+
v1 = importlib.import_module(sys.argv[2])
15+
pv1 = version.parse(v1.__version__)
16+
17+
if debug:
18+
print('sys.argv=',sys.argv)
19+
print('v0=',v0)
20+
print('v1=',v1)
21+
print('pv0=',pv0)
22+
print('pv1=',pv1)
23+
# cmd='cat '+sys.argv[1]+'.py'
24+
# print('os.system("'+cmd+'")')
25+
# os.system(cmd)
26+
# cmd='cat '+sys.argv[2]+'.py'
27+
# print('os.system("'+cmd+'")')
28+
# os.system(cmd)
29+
print('v0.__version__=',v0.__version__)
30+
print('v1.__version__=',v1.__version__)
31+
32+
if not pv1 > pv0:
33+
print('ERROR: Pull Request requires mplfinance version to be updated: (Version '+str(pv1)+' is NOT greater than '+str(pv0)+')')
34+
exit(1)
35+
else:
36+
print('Version was updated OK (from '+str(pv0)+' to '+str(pv1)+')')
37+
exit(0)

0 commit comments

Comments
 (0)