diff --git a/strategy_evaluation/BenchmarkStrategy.py b/strategy_evaluation/BenchmarkStrategy.py index 2d11164..59fd7bd 100644 --- a/strategy_evaluation/BenchmarkStrategy.py +++ b/strategy_evaluation/BenchmarkStrategy.py @@ -25,10 +25,8 @@ class BenchmarkStrategy: orders["Symbol"] = symbol orders["Order"] = "" orders["Shares"] = 0 - orders.iloc[0] = [symbol, "BUY", 1000] - orders.iloc[-1] = [symbol, "SELL", 1000] - orders = orders[orders["Shares"] != 0] + orders.iloc[-1] = [symbol, "SELL", -1000] if self.verbose: print(type(orders)) # it better be a DataFrame! diff --git a/strategy_evaluation/ManualStrategy.py b/strategy_evaluation/ManualStrategy.py index d6183b1..262acf4 100644 --- a/strategy_evaluation/ManualStrategy.py +++ b/strategy_evaluation/ManualStrategy.py @@ -1,6 +1,7 @@ import datetime as dt import pandas as pd -import util as ut +import util +import indicators class ManualStrategy: @@ -20,7 +21,7 @@ class ManualStrategy: # example usage of the old backward compatible util function syms = [symbol] dates = pd.date_range(sd, ed) - prices_all = ut.get_data(syms, dates) # automatically adds SPY + prices_all = util.get_data(syms, dates) # automatically adds SPY prices = prices_all[syms] # only portfolio symbols # prices_SPY = prices_all['SPY'] # only SPY, for comparison later if self.verbose: @@ -28,31 +29,60 @@ class ManualStrategy: # example use with new colname # automatically adds SPY - volume_all = ut.get_data(syms, dates, colname="Volume") + volume_all = util.get_data(syms, dates, colname="Volume") volume = volume_all[syms] # only portfolio symbols # volume_SPY = volume_all['SPY'] # only SPY, for comparison later if self.verbose: print(volume) + def macd_strat(self, macd, orders): + + def strat(ser): + m = macd.loc[ser.index] + prev_macd, prev_signal = m.iloc[0] + cur_macd, cur_signal = m.iloc[1] + shares = 0 + if cur_macd < -1 and prev_macd < prev_signal and cur_macd > cur_signal: + if self.holding == 0: + shares = 1000 + elif self.holding == -1000: + shares = 2000 + elif cur_macd > 1 and prev_macd > prev_signal and cur_macd < cur_signal: + if self.holding == 0: + shares = -1000 + elif self.holding == 1000: + shares = -2000 + self.holding += shares + return shares + + orders['Shares'] = orders['Shares'].rolling(2).apply(strat) + + # 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), sv=10000): - dates = pd.date_range(sd, ed) - prices = ut.get_data([symbol], dates) # automatically adds SPY - orders = pd.DataFrame(index=prices.index) + + self.holding = 0 + df = util.get_data([symbol], pd.date_range(sd, ed)) + df.drop(columns=["SPY"], inplace=True) + macd = indicators.macd(df, symbol) + + orders = pd.DataFrame(index=df.index) orders["Symbol"] = symbol orders["Order"] = "" orders["Shares"] = 0 + self.macd_strat(macd, orders) + # here we build a fake set of trades - orders.iloc[0] = [symbol, "BUY", 1000] - orders.iloc[40] = [symbol, "SELL", 1000] - orders.iloc[41] = [symbol, "BUY", 1000] - orders.iloc[60] = [symbol, "SELL", 2000] - orders.iloc[61] = [symbol, "BUY", 2000] - orders.iloc[-1] = [symbol, "SELL", 1000] - orders = orders[orders["Shares"] != 0] + # orders.iloc[0] = [symbol, "BUY", 1000] + # orders.iloc[40] = [symbol, "SELL", 1000] + # orders.iloc[41] = [symbol, "BUY", 1000] + # orders.iloc[60] = [symbol, "SELL", 2000] + # orders.iloc[61] = [symbol, "BUY", 2000] + # orders.iloc[-1] = [symbol, "SELL", 1000] + # orders = orders[orders["Shares"] != 0] return orders diff --git a/strategy_evaluation/experiment1.py b/strategy_evaluation/experiment1.py index 7b03e2c..2fb8887 100644 --- a/strategy_evaluation/experiment1.py +++ b/strategy_evaluation/experiment1.py @@ -9,22 +9,6 @@ from BenchmarkStrategy import BenchmarkStrategy from ManualStrategy import ManualStrategy -def macd_strat(macd): - def strat(x): - print(x) - - macd['macd_trigger'] = macd.rolling(2).apply(strat) - - # for i, row in macd.iterrows(): - # if i == 0: - # continue - # print(row) - # prev_macd, prev_signal, _ = row - # cur_macd, cur_signal, _ = row - # if cur_macd < -.5 and (prev_macd < prev_signal) \ - # and (cur_macd > cur_signal): - # macd.iloc[i]['macd_buy_sell'] = 1 - def experiment1(): symbol = "JPM" start_value = 10000 @@ -32,46 +16,33 @@ def experiment1(): ed = dt.datetime(2009, 12, 31) df = util.get_data([symbol], pd.date_range(sd, ed)) df.drop(columns=["SPY"], inplace=True) - # df = pd.DataFrame(index=df.index) bs = BenchmarkStrategy() orders = bs.testPolicy(symbol, sd, ed, start_value) df["Benchmark"] = marketsim.compute_portvals(orders, start_value) + df["Orders Benchmark"] = orders["Shares"] ms = ManualStrategy() orders = ms.testPolicy(symbol, sd, ed, start_value) df["Manual"] = marketsim.compute_portvals(orders, start_value) + df["Orders Manual"] = orders["Shares"] # indicators.price_sma(df, symbol, 21) # sma = indicators.sma(df, symbol, [9, 21]) # rsi = indicators.rsi(df, symbol) macd = indicators.macd(df, symbol).copy() - # macd_strat(macd) - fig, ax = plt.subplots(2, sharex=True) + fig, ax = plt.subplots(4, sharex=True) df[symbol].plot(ax=ax[0]) - # sma.plot(ax=ax[0]) - macd.plot(ax=ax[1]) - # macd.iloc[:,0].plot(ax=ax[1]) - # rsi.plot(ax=ax[2]) - # df[["Benchmark", "Manual"]].plot(ax=ax[3]) + macd.plot(ax=ax[3]) + df[["Benchmark", "Manual"]].plot(ax=ax[1]) + df[["Orders Benchmark", "Orders Manual"]].plot(ax=ax[2]) - # XXX: Plot where we buy and sell. - - for a in ax: a.grid() + for a in ax: + a.grid() multi = MultiCursor(fig.canvas, ax, color='r', lw=0.5) plt.show() - - # df.plot(title="results", subplots=True) - #sd = dt.datetime(2008, 1, 1) - #ed = dt.datetime(2009, 12, 31) - #df = get_data([symbol], pd.date_range(sd, ed)) - #df.drop(columns=["SPY"], inplace=True) - # df_orig = df.copy() - #df = indicators.normalize(df) - #indicators.price_sma(df, symbol, 21) - #df.plot(title="21 SMA and EMA") - #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 @@ -79,63 +50,5 @@ def experiment1(): # January 1, 2010 to December 31 2011. -class BlittedCursor: - """ - A cross hair cursor using blitting for faster redraw. - """ - def __init__(self, ax): - self.ax = ax - self.background = None - self.horizontal_line = ax.axhline(color='k', lw=0.8, ls='--') - self.vertical_line = ax.axvline(color='k', lw=0.8, ls='--') - # text location in axes coordinates - self.text = ax.text(0.72, 0.9, '', transform=ax.transAxes) - self._creating_background = False - ax.figure.canvas.mpl_connect('draw_event', self.on_draw) - - def on_draw(self, event): - self.create_new_background() - - def set_cross_hair_visible(self, visible): - need_redraw = self.horizontal_line.get_visible() != visible - self.horizontal_line.set_visible(visible) - self.vertical_line.set_visible(visible) - self.text.set_visible(visible) - return need_redraw - - def create_new_background(self): - if self._creating_background: - # discard calls triggered from within this function - return - self._creating_background = True - self.set_cross_hair_visible(False) - self.ax.figure.canvas.draw() - self.background = self.ax.figure.canvas.copy_from_bbox(self.ax.bbox) - self.set_cross_hair_visible(True) - self._creating_background = False - - def on_mouse_move(self, event): - if self.background is None: - self.create_new_background() - if not event.inaxes: - need_redraw = self.set_cross_hair_visible(False) - if need_redraw: - self.ax.figure.canvas.restore_region(self.background) - self.ax.figure.canvas.blit(self.ax.bbox) - else: - self.set_cross_hair_visible(True) - # update the line positions - x, y = event.xdata, event.ydata - self.horizontal_line.set_ydata(y) - self.vertical_line.set_xdata(x) - self.text.set_text('x=%1.2f, y=%1.2f' % (x, y)) - - self.ax.figure.canvas.restore_region(self.background) - self.ax.draw_artist(self.horizontal_line) - self.ax.draw_artist(self.vertical_line) - self.ax.draw_artist(self.text) - self.ax.figure.canvas.blit(self.ax.bbox) - - if __name__ == "__main__": experiment1() diff --git a/strategy_evaluation/figure_1.png b/strategy_evaluation/figure_1.png new file mode 100644 index 0000000..36494a2 Binary files /dev/null and b/strategy_evaluation/figure_1.png differ diff --git a/strategy_evaluation/strategy_evaluation.md b/strategy_evaluation/strategy_evaluation.md new file mode 100644 index 0000000..660ea89 --- /dev/null +++ b/strategy_evaluation/strategy_evaluation.md @@ -0,0 +1,3 @@ +# Report + +![First strategy based on MACD. Better than just holding](figure_1.png)