From 0519ae9336253afb2e641687b118cee747ee1755 Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Tue, 3 Nov 2020 19:05:43 -0500 Subject: [PATCH] Finish manual strategy for project 8 I struggled with the manual strategy, mostly because I tried to read good triggers from the price action charts. Finally, I had the ingenious (hmm) idea to scatter plot the 1, 3, and 5 day percentage returns over different indicators. I can also use this information to train my Q learner. --- strategy_evaluation/ManualStrategy.py | 36 ++++++++---- strategy_evaluation/experiment1.py | 85 ++++++++++++++++++++------- strategy_evaluation/indicators.py | 33 +++++++---- 3 files changed, 108 insertions(+), 46 deletions(-) diff --git a/strategy_evaluation/ManualStrategy.py b/strategy_evaluation/ManualStrategy.py index 52cf69f..9c673e2 100644 --- a/strategy_evaluation/ManualStrategy.py +++ b/strategy_evaluation/ManualStrategy.py @@ -58,19 +58,32 @@ class ManualStrategy: orders['Shares'] = orders['Shares'].rolling(2).apply(strat) def three_indicator_strat(self, macd, rsi, price_sma, orders): - # XXX: continue here - def strat(row): - m = macd.loc[row.index] - print(m) - # mac, signal = m.iloc[0] - # print(mac, signal) - return 0 + shares = 0 + _, _, macd_diff = macd.loc[row.name] + cur_rsi = rsi.loc[row.name][0] + cur_price_sma = price_sma.loc[row.name][0] + if self.holding == -1000 and cur_price_sma < 0.9: + shares = 2000 + elif self.holding == 0 and cur_price_sma < 0.9: + shares = 1000 + elif self.holding == -1000 and cur_rsi > 80: + shares = 2000 + elif self.holding == 0 and cur_rsi > 80: + shares = 1000 + elif self.holding == -1000 and macd_diff < -0.5: + shares = 2000 + elif self.holding == 0 and macd_diff < -0.5: + shares = 1000 + elif self.holding == 1000 and cur_price_sma > 1.1: + shares = -2000 + elif self.holding == 0 and cur_price_sma > 1.1: + shares = -1000 + self.holding += shares + return shares orders['Shares'] = orders.apply(strat, axis=1) - raise Exception() - # this method should use the existing policy and test it against new data def testPolicy(self, symbol="IBM", sd=dt.datetime(2009, 1, 1), ed=dt.datetime(2010, 1, 1), @@ -87,10 +100,9 @@ class ManualStrategy: macd = indicators.macd(df, symbol) rsi = indicators.rsi(df, symbol) - price_sma = indicators.price_sma(df, symbol, [21]) + price_sma = indicators.price_sma(df, symbol, [8]) + # self.macd_strat(macd, orders) self.three_indicator_strat(macd, rsi, price_sma, orders) - - # heers = orders[orders["Shares"] != 0] return orders diff --git a/strategy_evaluation/experiment1.py b/strategy_evaluation/experiment1.py index c37a027..2efa3d7 100644 --- a/strategy_evaluation/experiment1.py +++ b/strategy_evaluation/experiment1.py @@ -1,22 +1,76 @@ import pandas as pd import datetime as dt -import marketsim.marketsim as marketsim -import indicators +import sys + import util +import indicators +import marketsim.marketsim as marketsim import matplotlib.pyplot as plt from matplotlib.widgets import MultiCursor from BenchmarkStrategy import BenchmarkStrategy from ManualStrategy import ManualStrategy +def plot_indicators(symbol, df): + fig, ax = plt.subplots(4, sharex=True) + + price_sma = indicators.price_sma(df, symbol, [8]) + bb = indicators.bollinger_band(df, symbol) + sma = indicators.sma(df, symbol, [8]) + rsi = indicators.rsi(df, symbol) + macd = indicators.macd(df, symbol).copy() + + df[[symbol]].plot(ax=ax[0]) + bb.plot(ax=ax[0]) + price_sma.plot(ax=ax[1]) + macd.plot(ax=ax[2]) + rsi.plot(ax=ax[3]) + for a in ax.flat: + a.grid() + plt.show() + sys.exit(0) + + +def visualize_correlations(symbol, df): + indicators.price_sma(df, symbol, [8, 21]) + indicators.price_delta(df, symbol, 5) + indicators.price_delta(df, symbol, 3) + indicators.price_delta(df, symbol, 1) + indicators.macd(df, symbol) + indicators.rsi(df, symbol) + + # df = df[df['rsi'] > 80] + fig, ax = plt.subplots(3, 2) # sharex=True) + df.plot.scatter(x="price_sma_8", y="pct_5", ax=ax[0, 0]) + df.plot.scatter(x="price_sma_8", y="pct_3", ax=ax[1, 0]) + df.plot.scatter(x="price_sma_8", y="pct_1", ax=ax[2, 0]) + # df.plot.scatter(x="rsi", y="pct_5", ax=ax[0, 1]) + # df.plot.scatter(x="rsi", y="pct_3", ax=ax[1, 1]) + # df.plot.scatter(x="rsi", y="pct_1", ax=ax[2, 1]) + df.plot.scatter(x="macd_diff", y="pct_5", ax=ax[0, 1]) + df.plot.scatter(x="macd_diff", y="pct_3", ax=ax[1, 1]) + df.plot.scatter(x="macd_diff", y="pct_1", ax=ax[2, 1]) + + for a in ax.flat: + a.grid() + plt.show() + sys.exit(0) + + def experiment1(): symbol = "JPM" start_value = 10000 - sd = dt.datetime(2008, 1, 1) - ed = dt.datetime(2009, 12, 31) + sd = dt.datetime(2008, 1, 1) # in-sample + ed = dt.datetime(2009, 12, 31) # in-sample + # sd = dt.datetime(2010, 1, 1) # out-sample + # ed = dt.datetime(2011, 12, 31) # out-sample + df = util.get_data([symbol], pd.date_range(sd, ed)) df.drop(columns=["SPY"], inplace=True) + # visualize_correlations(symbol, df) + # plot_indicators(symbol, df) + bs = BenchmarkStrategy() orders = bs.testPolicy(symbol, sd, ed, start_value) df["Benchmark"] = marketsim.compute_portvals(orders, start_value) @@ -26,21 +80,12 @@ def experiment1(): orders = ms.testPolicy(symbol, sd, ed, start_value) df["Manual"] = marketsim.compute_portvals(orders, start_value) df["Orders Manual"] = orders["Shares"] + df["Holding Manual"] = orders["Shares"].cumsum() - price_sma = indicators.price_sma(df, symbol, [21]) - bb = indicators.bollinger_band(df, symbol) - sma = indicators.sma(df, symbol, [9, 21]) - rsi = indicators.rsi(df, symbol) - macd = indicators.macd(df, symbol).copy() - - fig, ax = plt.subplots(4, sharex=True) + fig, ax = plt.subplots(3, sharex=True) df[[symbol]].plot(ax=ax[0]) - # bb.plot(ax=ax[0]) - price_sma.plot(ax=ax[1]) - macd.plot(ax=ax[2]) - rsi.plot(ax=ax[3]) - # df[["Benchmark", "Manual"]].plot(ax=ax[1]) - # df[["Orders Benchmark", "Orders Manual"]].plot(ax=ax[2]) + df[["Benchmark", "Manual"]].plot(ax=ax[1]) + df[["Orders Benchmark", "Orders Manual"]].plot(ax=ax[2]) for a in ax: a.grid() @@ -48,11 +93,7 @@ def experiment1(): plt.show() # plt.savefig('figure_1.png') - # You may use data from other symbols (such as SPY) to inform both your - # Manual Learner and Strategy Learner. The in-sample/development period is - # January 1, 2008 to December 31 2009. The out-of-sample/testing period is - # January 1, 2010 to December 31 2011. - if __name__ == "__main__": experiment1() + diff --git a/strategy_evaluation/indicators.py b/strategy_evaluation/indicators.py index 0f8b9a9..a5efd70 100644 --- a/strategy_evaluation/indicators.py +++ b/strategy_evaluation/indicators.py @@ -17,9 +17,7 @@ def bollinger_band(df, symbol, period=20, m=2): std = df[symbol].rolling(period).std() boll_up = boll_sma + m * std boll_lo = boll_sma - m * std - key_sma = f"{symbol}-Boll({period})-sma" - key_up = f"{symbol}-Boll({period})-up" - key_lo = f"{symbol}-Boll({period})-lo" + key_sma, key_up, key_lo = "boll_sma", "boll_up", "boll_lo" df[key_sma] = boll_sma df[key_up] = boll_up df[key_lo] = boll_lo @@ -32,7 +30,7 @@ def sma(df, symbol, period): period = [period] keys = [] for p in period: - key = f"{symbol}-sma({p})" + key = f"sma_{p}" df[key] = df[symbol].rolling(p).mean() keys.append(key) return df[keys] @@ -44,8 +42,8 @@ def ema(df, symbol, period): period = [period] keys = [] for p in period: - key = f"{symbol}-ema({p})" - df[key] = df[symbol].ewm(span=period).mean() + key = f"ema_{p}" + df[key] = df[symbol].ewm(span=p).mean() keys.append(key) return df[keys] @@ -56,7 +54,7 @@ def price_sma(df, symbol, period): period = [period] keys = [] for p in period: - key = f"{symbol}-price/sma({p})" + key = f"price_sma_{p}" sma = df[symbol].rolling(p).mean() df[key] = df[symbol] / sma keys.append(key) @@ -84,16 +82,28 @@ def rsi(df, symbol, period=14): def macd(df, symbol): macd = df[symbol].ewm(span=12).mean() - df[symbol].ewm(span=26).mean() - k1 = f"macd" - k2 = k1 + "-signal" + k1 = "macd" + k2 = "macd_signal" + k3 = "macd_diff" df[k1] = macd df[k2] = macd.rolling(9).mean() - return df[[k1, k2]] + df[k3] = df[k1] - df[k2] + return df[[k1, k2, k3]] def price_delta(df, symbol, period=1): """Calculate delta between previous day and today.""" - df[f"{symbol}-diff({period})"] = df[symbol].diff(periods=period) + k = f"diff_{period}" + df[k] = df[symbol].diff(periods=period) + return df[k] + + +def price_delta(df, symbol, period=1): + """Calculate percentage change for period.""" + k = f"pct_{period}" + df[k] = df[symbol].pct_change(periods=period) + df[k] = df[k].shift(-period) + return df[k] def test_indicators(): @@ -135,4 +145,3 @@ def test_indicators(): df[symbol].plot(ax=axes[0], title="JPM price action") df[["JPM-macd", "JPM-macd-signal"]].plot(ax=axes[1]) plt.savefig('figure_5.png') -