import pandas as pd
pd.options.display.float_format = '{:,.4f}'.format
data = pd.read_csv("dj_data.csv", parse_dates = ["Date"], index_col = "Date")
data.head(5)
Open | High | Low | Close | Adj Close | Volume | |
---|---|---|---|---|---|---|
Date | ||||||
2007-01-03 | 12,459.5400 | 12,580.3496 | 12,404.8203 | 12,474.5195 | 12,474.5195 | 327200000 |
2007-01-04 | 12,473.1602 | 12,510.4102 | 12,403.8604 | 12,480.6904 | 12,480.6904 | 259060000 |
2007-01-05 | 12,480.0498 | 12,480.1299 | 12,365.4102 | 12,398.0098 | 12,398.0098 | 235220000 |
2007-01-08 | 12,392.0098 | 12,445.9199 | 12,337.3701 | 12,423.4902 | 12,423.4902 | 223500000 |
2007-01-09 | 12,424.7695 | 12,466.4297 | 12,369.1699 | 12,416.5996 | 12,416.5996 | 225190000 |
data.info()
<class 'pandas.core.frame.DataFrame'> DatetimeIndex: 3333 entries, 2007-01-03 to 2020-03-30 Data columns (total 6 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Open 3333 non-null float64 1 High 3333 non-null float64 2 Low 3333 non-null float64 3 Close 3333 non-null float64 4 Adj Close 3333 non-null float64 5 Volume 3333 non-null int64 dtypes: float64(5), int64(1) memory usage: 182.3 KB
dow = data.loc['2010-01-01': '2020-03-31', "Close"].to_frame()
dow
Close | |
---|---|
Date | |
2010-01-04 | 10,583.9600 |
2010-01-05 | 10,572.0195 |
2010-01-06 | 10,573.6797 |
2010-01-07 | 10,606.8604 |
2010-01-08 | 10,618.1904 |
... | ... |
2020-03-24 | 20,704.9102 |
2020-03-25 | 21,200.5508 |
2020-03-26 | 22,552.1699 |
2020-03-27 | 21,636.7793 |
2020-03-30 | 22,327.4805 |
2577 rows × 1 columns
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
plt.style.use('ggplot')
dow.describe()
Close | |
---|---|
count | 2,577.0000 |
mean | 17,820.3425 |
std | 5,292.2609 |
min | 9,686.4805 |
25% | 13,034.4902 |
50% | 17,113.1504 |
75% | 21,892.4297 |
max | 29,551.4199 |
dow.plot(figsize = (10, 8), fontsize = 13, color='purple')
plt.legend(fontsize = 13)
plt.title("Dow Jones Closing Data: 1-3-2010 to 3-31-2020", fontsize = 20, pad = 20)
plt.show()
df.pct_change()
gets the rate of change from one row to the next¶dow['Return'] = dow.pct_change()
dow.dropna(inplace = True)
dow.tail(5)
Close | Return | |
---|---|---|
Date | ||
2020-03-24 | 20,704.9102 | 0.1137 |
2020-03-25 | 21,200.5508 | 0.0239 |
2020-03-26 | 22,552.1699 | 0.0638 |
2020-03-27 | 21,636.7793 | -0.0406 |
2020-03-30 | 22,327.4805 | 0.0319 |
y
axis is on right with pricesy
for the return is on leftdow.plot(figsize = (10, 8), secondary_y = "Return",
mark_right = True, fontsize = 13)
plt.show()
dow.rename(columns = {"Close": "DJI_Close", "Return": "DJI_Return"},
inplace = True)
dow.head(5)
DJI_Close | DJI_Return | |
---|---|---|
Date | ||
2010-01-05 | 10,572.0195 | -0.0011 |
2010-01-06 | 10,573.6797 | 0.0002 |
2010-01-07 | 10,606.8604 | 0.0031 |
2010-01-08 | 10,618.1904 | 0.0011 |
2010-01-11 | 10,663.9902 | 0.0043 |
Positions:
Strategies:
a) Investing (+1) into DJI tomorrow if today´s return was positive
b) Short selling (-1) DJI tomorrow if today´s return was negative
np.sign()
- Returns an element-wise indication of the sign of a number.dow['Position'] = np.sign(dow['DJI_Return'])
dow.sample(5)
DJI_Close | DJI_Return | Position | |
---|---|---|---|
Date | |||
2019-07-22 | 27,171.9004 | 0.0007 | 1.0000 |
2011-10-28 | 12,231.1104 | 0.0018 | 1.0000 |
2020-01-14 | 28,939.6699 | 0.0011 | 1.0000 |
2018-10-25 | 24,984.5508 | 0.0163 | 1.0000 |
2018-02-02 | 25,520.9609 | -0.0254 | -1.0000 |
dow['Strategy_Return'] = dow.Position.shift() * dow.DJI_Return
dow.head(10)
DJI_Close | DJI_Return | Position | Strategy_Return | |
---|---|---|---|---|
Date | ||||
2010-01-05 | 10,572.0195 | -0.0011 | -1.0000 | NaN |
2010-01-06 | 10,573.6797 | 0.0002 | 1.0000 | -0.0002 |
2010-01-07 | 10,606.8604 | 0.0031 | 1.0000 | 0.0031 |
2010-01-08 | 10,618.1904 | 0.0011 | 1.0000 | 0.0011 |
2010-01-11 | 10,663.9902 | 0.0043 | 1.0000 | 0.0043 |
2010-01-12 | 10,627.2598 | -0.0034 | -1.0000 | -0.0034 |
2010-01-13 | 10,680.7695 | 0.0050 | 1.0000 | -0.0050 |
2010-01-14 | 10,710.5498 | 0.0028 | 1.0000 | 0.0028 |
2010-01-15 | 10,609.6504 | -0.0094 | -1.0000 | -0.0094 |
2010-01-19 | 10,725.4297 | 0.0109 | 1.0000 | -0.0109 |
strategy_return
0
cumprod
DJI_Close
dow.Strategy_Return.add(1, fill_value = 0).cumprod()
Date 2010-01-05 1.0000 2010-01-06 0.9998 2010-01-07 1.0030 2010-01-08 1.0041 2010-01-11 1.0084 ... 2020-03-24 0.4726 2020-03-25 0.4839 2020-03-26 0.5147 2020-03-27 0.4938 2020-03-30 0.4781 Name: Strategy_Return, Length: 2576, dtype: float64
dow['Strategy'] = dow.Strategy_Return.add(1, fill_value = 0).cumprod() * dow.iloc[0,0]
display(dow.head(5), dow.tail(5))
DJI_Close | DJI_Return | Position | Strategy_Return | Strategy | |
---|---|---|---|---|---|
Date | |||||
2010-01-05 | 10,572.0195 | -0.0011 | -1.0000 | NaN | 10,572.0195 |
2010-01-06 | 10,573.6797 | 0.0002 | 1.0000 | -0.0002 | 10,570.3594 |
2010-01-07 | 10,606.8604 | 0.0031 | 1.0000 | 0.0031 | 10,603.5296 |
2010-01-08 | 10,618.1904 | 0.0011 | 1.0000 | 0.0011 | 10,614.8561 |
2010-01-11 | 10,663.9902 | 0.0043 | 1.0000 | 0.0043 | 10,660.6416 |
DJI_Close | DJI_Return | Position | Strategy_Return | Strategy | |
---|---|---|---|---|---|
Date | |||||
2020-03-24 | 20,704.9102 | 0.1137 | 1.0000 | -0.1137 | 4,995.9025 |
2020-03-25 | 21,200.5508 | 0.0239 | 1.0000 | 0.0239 | 5,115.4960 |
2020-03-26 | 22,552.1699 | 0.0638 | 1.0000 | 0.0638 | 5,441.6291 |
2020-03-27 | 21,636.7793 | -0.0406 | -1.0000 | -0.0406 | 5,220.7539 |
2020-03-30 | 22,327.4805 | 0.0319 | 1.0000 | -0.0319 | 5,054.0941 |
dow[['DJI_Close', 'Strategy']].plot(figsize = (12, 7), fontsize = 13)
plt.title('Simple Momentum Strategy', fontsize = 20)
plt.legend(fontsize = 13)
plt.show()
def summary_annualize(returns):
summary = returns.agg(['mean', 'std']).T
summary['Return'] = summary["mean"] * 252
summary['Risk'] = summary['std'] * np.sqrt(252)
summary.drop(columns = ['mean', 'std'], inplace = True)
return summary
dow.columns
Index(['DJI_Close', 'DJI_Return', 'Position', 'Strategy_Return', 'Strategy'], dtype='object')
summary_annualize(dow[["DJI_Return", "Strategy_Return"]])
Return | Risk | |
---|---|---|
DJI_Return | 0.0872 | 0.1679 |
Strategy_Return | -0.0580 | 0.1679 |
Strategies:
data = pd.read_csv("dj_data.csv", parse_dates = ["Date"], index_col = "Date")
dow = data.loc['2010-01-01': '2020-03-31', "Close"].to_frame()
dow['Return'] = dow.pct_change()
dow.rename(columns = {"Close": "DJI_Close", "Return": "DJI_Return"},
inplace = True)
dow.dropna(inplace = True)
display(dow.head(5))
display(dow.tail(5))
DJI_Close | DJI_Return | |
---|---|---|
Date | ||
2010-01-05 | 10,572.0195 | -0.0011 |
2010-01-06 | 10,573.6797 | 0.0002 |
2010-01-07 | 10,606.8604 | 0.0031 |
2010-01-08 | 10,618.1904 | 0.0011 |
2010-01-11 | 10,663.9902 | 0.0043 |
DJI_Close | DJI_Return | |
---|---|---|
Date | ||
2020-03-24 | 20,704.9102 | 0.1137 |
2020-03-25 | 21,200.5508 | 0.0239 |
2020-03-26 | 22,552.1699 | 0.0638 |
2020-03-27 | 21,636.7793 | -0.0406 |
2020-03-30 | 22,327.4805 | 0.0319 |
dow["Position"] = -np.sign(dow['DJI_Return'])
dow["Strategy_Return"] = dow["Position"].shift() * dow['DJI_Return']
dow['Strategy'] = dow.Strategy_Return.add(1, fill_value = 0).cumprod() * dow.iloc[0, 0]
display(dow.head(5))
display(dow.tail(5))
DJI_Close | DJI_Return | Position | Strategy_Return | Strategy | |
---|---|---|---|---|---|
Date | |||||
2010-01-05 | 10,572.0195 | -0.0011 | 1.0000 | NaN | 10,572.0195 |
2010-01-06 | 10,573.6797 | 0.0002 | -1.0000 | 0.0002 | 10,573.6797 |
2010-01-07 | 10,606.8604 | 0.0031 | -1.0000 | -0.0031 | 10,540.4990 |
2010-01-08 | 10,618.1904 | 0.0011 | -1.0000 | -0.0011 | 10,529.2398 |
2010-01-11 | 10,663.9902 | 0.0043 | -1.0000 | -0.0043 | 10,483.8237 |
DJI_Close | DJI_Return | Position | Strategy_Return | Strategy | |
---|---|---|---|---|---|
Date | |||||
2020-03-24 | 20,704.9102 | 0.1137 | -1.0000 | 0.1137 | 16,885.3904 |
2020-03-25 | 21,200.5508 | 0.0239 | -1.0000 | -0.0239 | 16,481.1826 |
2020-03-26 | 22,552.1699 | 0.0638 | -1.0000 | -0.0638 | 15,430.4419 |
2020-03-27 | 21,636.7793 | -0.0406 | 1.0000 | 0.0406 | 16,056.7622 |
2020-03-30 | 22,327.4805 | 0.0319 | -1.0000 | 0.0319 | 16,569.3350 |
dow[['DJI_Close', 'Strategy']].plot(figsize = (12, 9), fontsize = 13, title = "Contrarian Strategy");
summary_annualize(dow[['DJI_Return', 'Strategy_Return']])
Return | Risk | |
---|---|---|
DJI_Return | 0.0872 | 0.1679 |
Strategy_Return | 0.0580 | 0.1679 |
data = pd.read_csv("dj_data.csv", parse_dates = ["Date"], index_col = "Date")
dow = data.loc['2010-01-01': '2020-03-31', "Close"].to_frame()
dow['DJI_Return'] = dow.pct_change()
dow.columns = ["DJI_Close", "DJI_Return"]
dow.dropna(inplace = True)
DJI_Return
, the return for the day, is positive, tomorrow will be a -1
position1
dow["Position"] = np.where(dow['DJI_Return'] > 0.0, -1, 1)
dow["Strategy_Return"] = dow["Position"].shift() * dow['DJI_Return']
dow['Strategy'] = dow.Strategy_Return.add(1, fill_value = 0).cumprod() * dow.iloc[0, 0]
dow[['DJI_Close', 'Strategy']].plot(figsize = (12, 9), fontsize = 13, title="Backtesting, Identical Results to Contrarian");
dow["Position"] = np.where(dow['DJI_Return'] > 0.0, 0, 1)
dow["Strategy_Return"] = dow["Position"].shift() * dow['DJI_Return']
dow['Strategy'] = dow.Strategy_Return.add(1, fill_value = 0).cumprod() * dow.iloc[0, 0]
dow[['DJI_Close', 'Strategy']].plot(figsize = (12, 9), fontsize = 13, title="If Return > 0, No Change");
dow["Position"] = np.where(dow['DJI_Return'] > 0.01, -1, 1)
dow["Strategy_Return"] = dow["Position"].shift() * dow['DJI_Return']
dow['Strategy'] = dow.Strategy_Return.add(1, fill_value = 0).cumprod() * dow.iloc[0, 0]
dow[['DJI_Close', 'Strategy']].plot(figsize = (12, 9), fontsize = 13, title="If Return > 1% - Sell | If Not - Hold");
summary_annualize(dow[["DJI_Return", "Strategy_Return"]])
Return | Risk | |
---|---|---|
DJI_Return | 0.0872 | 0.1679 |
Strategy_Return | 0.1743 | 0.1677 |
Even if a Strategy seems to outperform the basic Strategy, the following issues need to be considered/analyzed as well:
dow = data.loc['2010-01-01': '2020-03-31', "Close"].to_frame()
dow['DJI_Return'] = dow.pct_change()
dow.columns = ["DJI_Close", "DJI_Return"]
dow.dropna(inplace = True)
rolling_50 = dow.DJI_Close.rolling(window = 50).mean()
print("Past 50 day averages for first examples where it can be calculated:")
display(rolling_50.iloc[50:56])
print("")
print("Past 50 day averages for last 5 days in the data:")
display(rolling_50.tail(5))
Past 50 day averages for first examples where it can be calculated:
Date 2010-03-18 10,397.0342 2010-03-19 10,400.4002 2010-03-22 10,403.9808 2010-03-23 10,409.3936 2010-03-24 10,412.8368 2010-03-25 10,417.1158 Name: DJI_Close, dtype: float64
Past 50 day averages for last 5 days in the data:
Date 2020-03-24 26,708.5479 2020-03-25 26,554.4179 2020-03-26 26,426.6679 2020-03-27 26,278.7991 2020-03-30 26,139.3959 Name: DJI_Close, dtype: float64
dow["SMA50"] = dow.DJI_Close.rolling(window = 50).mean()
dow[['DJI_Close', "SMA50"]].plot(figsize=(12,6), fontsize = 13, title="Simple Moving Average Against Daily Prices")
plt.legend(fontsize = 13)
plt.show()
dow["SMA200"] = dow.DJI_Close.rolling(window = 200).mean()
dow[["SMA50", "SMA200"]].plot(figsize=(12,6), fontsize = 13, title="Simple Moving Averages: 50 vs 200")
plt.legend(fontsize = 13)
plt.show()
dow.dropna(inplace = True)
dow.head(5)
DJI_Close | DJI_Return | SMA50 | SMA200 | |
---|---|---|---|---|
Date | ||||
2010-10-19 | 10,978.6201 | -0.0148 | 10,582.0898 | 10,507.0982 |
2010-10-20 | 11,107.9697 | 0.0118 | 10,591.3642 | 10,509.7780 |
2010-10-21 | 11,146.5703 | 0.0035 | 10,606.7190 | 10,512.6424 |
2010-10-22 | 11,132.5596 | -0.0013 | 10,622.9712 | 10,515.2709 |
2010-10-25 | 11,164.0498 | 0.0028 | 10,640.1892 | 10,518.0002 |
dow['position'] = np.sign(dow.SMA50.sub(dow.SMA200))
display(dow.head(5))
print('')
display(dow.tail(5))
DJI_Close | DJI_Return | SMA50 | SMA200 | position | |
---|---|---|---|---|---|
Date | |||||
2010-10-19 | 10,978.6201 | -0.0148 | 10,582.0898 | 10,507.0982 | 1.0000 |
2010-10-20 | 11,107.9697 | 0.0118 | 10,591.3642 | 10,509.7780 | 1.0000 |
2010-10-21 | 11,146.5703 | 0.0035 | 10,606.7190 | 10,512.6424 | 1.0000 |
2010-10-22 | 11,132.5596 | -0.0013 | 10,622.9712 | 10,515.2709 | 1.0000 |
2010-10-25 | 11,164.0498 | 0.0028 | 10,640.1892 | 10,518.0002 | 1.0000 |
DJI_Close | DJI_Return | SMA50 | SMA200 | position | |
---|---|---|---|---|---|
Date | |||||
2020-03-24 | 20,704.9102 | 0.1137 | 26,708.5479 | 27,010.9029 | -1.0000 |
2020-03-25 | 21,200.5508 | 0.0239 | 26,554.4179 | 26,986.5923 | -1.0000 |
2020-03-26 | 22,552.1699 | 0.0638 | 26,426.6679 | 26,969.1106 | -1.0000 |
2020-03-27 | 21,636.7793 | -0.0406 | 26,278.7991 | 26,947.2703 | -1.0000 |
2020-03-30 | 22,327.4805 | 0.0319 | 26,139.3959 | 26,928.3739 | -1.0000 |
dow[["SMA50", "SMA200", "position"]].plot(figsize=(12,6), secondary_y = 'position', fontsize = 13, title="SMA50, SMA200, and Position")
plt.show()
dow['Strategy_Return'] = dow['position'].shift() * dow['DJI_Return']
dow['Strategy'] = dow.Strategy_Return.add(1, fill_value = 0).cumprod() * dow.iloc[0, 0]
display(dow.head(5))
print('')
display(dow.tail(5))
DJI_Close | DJI_Return | SMA50 | SMA200 | position | Strategy_Return | Strategy | |
---|---|---|---|---|---|---|---|
Date | |||||||
2010-10-19 | 10,978.6201 | -0.0148 | 10,582.0898 | 10,507.0982 | 1.0000 | NaN | 10,978.6201 |
2010-10-20 | 11,107.9697 | 0.0118 | 10,591.3642 | 10,509.7780 | 1.0000 | 0.0118 | 11,107.9697 |
2010-10-21 | 11,146.5703 | 0.0035 | 10,606.7190 | 10,512.6424 | 1.0000 | 0.0035 | 11,146.5703 |
2010-10-22 | 11,132.5596 | -0.0013 | 10,622.9712 | 10,515.2709 | 1.0000 | -0.0013 | 11,132.5596 |
2010-10-25 | 11,164.0498 | 0.0028 | 10,640.1892 | 10,518.0002 | 1.0000 | 0.0028 | 11,164.0498 |
DJI_Close | DJI_Return | SMA50 | SMA200 | position | Strategy_Return | Strategy | |
---|---|---|---|---|---|---|---|
Date | |||||||
2020-03-24 | 20,704.9102 | 0.1137 | 26,708.5479 | 27,010.9029 | -1.0000 | -0.1137 | 8,400.9733 |
2020-03-25 | 21,200.5508 | 0.0239 | 26,554.4179 | 26,986.5923 | -1.0000 | -0.0239 | 8,199.8681 |
2020-03-26 | 22,552.1699 | 0.0638 | 26,426.6679 | 26,969.1106 | -1.0000 | -0.0638 | 7,677.0940 |
2020-03-27 | 21,636.7793 | -0.0406 | 26,278.7991 | 26,947.2703 | -1.0000 | 0.0406 | 7,988.7066 |
2020-03-30 | 22,327.4805 | 0.0319 | 26,139.3959 | 26,928.3739 | -1.0000 | -0.0319 | 7,733.6867 |
dow[['DJI_Close', 'Strategy']].plot(figsize = (12, 9), fontsize = 13, title="SMA Cross-Over Momentum Stratgy");
summary_annualize(dow[['DJI_Return', 'Strategy_Return']])
Return | Risk | |
---|---|---|
DJI_Return | 0.0878 | 0.1676 |
Strategy_Return | -0.0229 | 0.1677 |
dow['position'] = -np.sign(dow.SMA50.sub(dow.SMA200))
dow[['SMA50', 'SMA200', 'position']].plot(figsize = (12, 9), fontsize = 13, secondary_y = 'position', title="SMA Cross-Over Momentum Stratgy");
dow['Strategy_Return'] = dow['position'].shift() * dow['DJI_Return']
dow['Strategy'] = dow.Strategy_Return.add(1, fill_value = 0).cumprod() * dow.iloc[0, 0]
dow[['DJI_Close', 'Strategy']].plot(figsize = (12, 9), fontsize = 13, title="SMA Cross-Over Momentum Stratgy");
summary_annualize(dow[['DJI_Return', 'Strategy_Return']])
Return | Risk | |
---|---|---|
DJI_Return | 0.0878 | 0.1676 |
Strategy_Return | 0.0229 | 0.1677 |
dow = data.loc['2010-01-01': '2020-03-31', "Close"].to_frame()
dow['DJI_Return'] = dow.pct_change()
dow.columns = ["DJI_Close", "DJI_Return"]
dow.dropna(inplace = True)
dow['position'] = np.sign(dow['DJI_Return'])
dow['Strategy_Return'] = dow['position'] * dow['DJI_Return']
dow['Strategy'] = dow.Strategy_Return.add(1, fill_value = 0).cumprod() * dow.iloc[0, 0]
display(dow.head(5))
display(dow.tail(5))
DJI_Close | DJI_Return | position | Strategy_Return | Strategy | |
---|---|---|---|---|---|
Date | |||||
2010-01-05 | 10,572.0195 | -0.0011 | -1.0000 | 0.0011 | 10,583.9465 |
2010-01-06 | 10,573.6797 | 0.0002 | 1.0000 | 0.0002 | 10,585.6085 |
2010-01-07 | 10,606.8604 | 0.0031 | 1.0000 | 0.0031 | 10,618.8266 |
2010-01-08 | 10,618.1904 | 0.0011 | 1.0000 | 0.0011 | 10,630.1695 |
2010-01-11 | 10,663.9902 | 0.0043 | 1.0000 | 0.0043 | 10,676.0210 |
DJI_Close | DJI_Return | position | Strategy_Return | Strategy | |
---|---|---|---|---|---|
Date | |||||
2020-03-24 | 20,704.9102 | 0.1137 | 1.0000 | 0.1137 | 185,617,768,656.5365 |
2020-03-25 | 21,200.5508 | 0.0239 | 1.0000 | 0.0239 | 190,061,144,946.2066 |
2020-03-26 | 22,552.1699 | 0.0638 | 1.0000 | 0.0638 | 202,178,296,243.3131 |
2020-03-27 | 21,636.7793 | -0.0406 | -1.0000 | 0.0406 | 210,384,695,787.1586 |
2020-03-30 | 22,327.4805 | 0.0319 | 1.0000 | 0.0319 | 217,100,711,786.1638 |
dow[['DJI_Close', 'Strategy']].plot(figsize = (12, 9), fontsize = 13, title="The Perfect Strategy", logy = True);
summary_annualize(dow[['DJI_Return', 'Strategy_Return']])
Return | Risk | |
---|---|---|
DJI_Return | 0.0872 | 0.1679 |
Strategy_Return | 1.6609 | 0.1314 |