© Ran Aroussi
@aroussi | aroussi.com | github.com/ranaroussi
May, 2017
[********************** DATA SET **********************]1. [ AVAILABLE DATA **************]| ^ 2. [ AVAILABLE DATA ************************]| ^ 3. [ AVAILABLE DATA ****************************]| ^ ...
[********************** DATA SET **********************] [********** IN-SAMPLE **********][*** OUT-OF-SAMPLE ***][*** FWD TEST ***]
from pandas_datareader import data as pdr
import fix_yahoo_finance
spy = pdr.get_data_yahoo("SPY", start="2000-01-01", auto_adjust=True)
spy.columns = map(str.lower, spy.columns)
spy['return'] = spy['close'].pct_change().fillna(0)
spy.head()
open | high | low | close | volume | return | |
---|---|---|---|---|---|---|
Date | ||||||
2000-01-03 | 148.250000 | 148.250000 | 143.875000 | 145.4375 | 8164300 | 0.000000 |
2000-01-04 | 143.531204 | 144.062500 | 139.640594 | 139.7500 | 8089800 | -0.039106 |
2000-01-05 | 139.937500 | 141.531204 | 137.250000 | 140.0000 | 12177900 | 0.001789 |
2000-01-06 | 139.625000 | 141.500000 | 137.750000 | 137.7500 | 6227200 | -0.016071 |
2000-01-07 | 140.312500 | 145.750000 | 140.062500 | 145.7500 | 8066500 | 0.058076 |
timer.start()
port = pd.DataFrame(spy['return'])
port['strategy'] = port[port['return'].shift(1) <= -0.005]['return']
timer.stop()
[*] Total runtime: 2.47 ms
timer.start()
port = pd.DataFrame(spy['return'])
for ix, _ in port.iterrows():
loc = port.index.get_loc(ix)
if loc > 0:
yday = port.iloc[loc - 1]
if yday['return'] <= -0.005:
port.loc[ix, "strategy"] = port.loc[ix, 'return']
timer.stop()
[*] Total runtime: 860.38 ms
atw
¶timer.start()
port = pd.DataFrame(spy['return'])
for ix, loc in atw.iterate(port, progress=True):
yday = port.iloc[loc - 1]
if yday['return'] <= -0.005:
port.loc[ix, 'strategy'] = port.loc[ix, 'return']
timer.stop()
[*********************100%***********************] 4376 of 4376 complete [*] Total runtime: 4.63 s
port.fillna(0, inplace=True)
port.cumsum().plot()
<matplotlib.axes._subplots.AxesSubplot at 0x10e928c88>
returns = port['strategy'][port['strategy'] != 0]
sharpe = np.sqrt(252) * (np.mean(returns)) / np.std(returns)
sharpe
1.2459348946091056
dd = pd.DataFrame(data={"percent": port['strategy'].cumsum()})
dd['duration'] = np.where(dd['percent'] < 0, 1, 0)
dd['duration'] = dd['duration'].groupby(
(dd['duration'] == 0).cumsum() ).cumcount()
dd[['percent', 'duration']].plot(figsize=(14, 5), subplots=True)
array([<matplotlib.axes._subplots.AxesSubplot object at 0x11036dcf8>, <matplotlib.axes._subplots.AxesSubplot object at 0x1104255f8>], dtype=object)
dd['max'] = dd['percent'].rolling(len(dd), min_periods=1).max()
fig, ax = plt.subplots(figsize=(14, 6))
ax.plot(dd['percent'], lw=1.5)
ax.fill_between(dd.index, dd['percent'], dd['max'], color='c', alpha=.5)
<matplotlib.collections.PolyCollection at 0x1146e77f0>
max_dd = dd['percent'].min()
total_returns = sum(port['strategy'])
recovery_factor = total_returns / abs(max_dd)
recovery_factor
9.060807135217356
start_value = 1
end_value = 1 + sum(port['strategy'])
years = len(returns.resample("A").count())
cagr = ((end_value / start_value) ** (1 / years)) - 1
cagr
0.049828309156602746
dd = atw.drawdown(port['strategy'])
stats = [
("Sharpe ratio", "%.2f" % atw.sharpe(port['strategy'])),
("CAGR", "%.2f%%" % (atw.cagr(port['strategy']) * 100)),
("Win %", "%.2f%%" % (atw.win_rate(port['strategy']) * 100)),
("Avg. %", "%.2f%%" % (atw.avg_return(port['strategy']) * 100)),
("Avg. Win %", "%.2f%%" % (atw.avg_win(port['strategy']) * 100)),
("Avg. Loss %", "%.2f%%" % (atw.avg_loss(port['strategy']) * 100)),
("Profit Factor", "%.2f" % atw.profit_factor(port['strategy'])),
("Max DD %", "%.2f%%" % (dd['percent'].min() * 100)),
("DD Duration %", "%.0f days" % dd['duration'].max() ),
("Recovery Factor", "%.2f" % atw.recovery_factor(port['strategy'], dd['percent']))
]
stats = pd.DataFrame(stats, columns=['metric', 'value'])
stats.set_index(stats.columns[0], inplace=True)
print(stats)
value metric Sharpe ratio 1.25 CAGR 4.98% Win % 55.76% Avg. % 0.13% Avg. Win % 1.09% Avg. Loss % -1.09% Profit Factor 1.26 Max DD % -15.45% DD Duration % 149 days Recovery Factor 9.06
atw.sum_by_year(port).plot(kind='bar')
<matplotlib.axes._subplots.AxesSubplot at 0x110344c88>
atw.monthly_returns_heatmap(port['strategy'])
# split the data into training and testing sets
train, test = atw.train_test_split(spy, test_size=.2)
port = pd.DataFrame(train)
port['ma1'] = port['close'].rolling(window=50).mean()
port['ma2'] = port['close'].rolling(window=100).mean()
port[['ma1', 'ma2', 'close']].plot(linewidth=1)
<matplotlib.axes._subplots.AxesSubplot at 0x115a027b8>