import pandas as pd import numpy as np import matplotlib.pyplot as plt from scipy.stats import pearsonr from zipline.algorithm import TradingAlgorithm from zipline.transforms import MovingAverage, batch_transform from zipline.utils.factory import load_from_yahoo from zipline.finance import slippage, commission # Uncomment the line below to get the data for yourself, but it is already included in the above mentioned repository #data = load_from_yahoo(stocks=['AAPL', 'GOOG'],start=datetime.datetime(2012,11,1), end=datetime.datetime(2013,5,8)); data.save('goog_aapl_tests.dat') data = pd.load('goog_aapl_tests.dat') fig = plt.figure(figsize(12,6)) #data.SPX.plot(label='S&P Benchmark') data.GOOG.plot() data.AAPL.plot() legend(loc='best') plt.title("Apple & Google Adj Closing Prices") class GOOG_AAPL_COR(TradingAlgorithm): # inherit from TradingAlgorithm """ Google Apple Correlation algorithm. An algorithm designed to exploit the correlation in the movement of Apple's and Google's common stock. """ def initialize(self): self.capital_base = 1000000 self.pricea = 0 self.priceg = 0 self.window_length = 5 self.corr_tolerance = 0.9 self.max_notional = self.capital_base + 0.1 self.min_notional = self.capital_base * (-1) self.pricealag = 0 self.priceglag = 0 self.buy_orders = [] self.sell_orders = [] self.corr_values_aapl = [] self.corr_values_goog = [] def handle_data(self, data): self.pricea = data.AAPL.price self.priceg = data.GOOG.price # compute correlation between stocks corr, pval = self.correlation(data, self.pricea, self.priceg) print str(data.AAPL.datetime) + ': Pearson Correlation: ' + str(corr) # print results to console #notional = self.portfolio.positions[data.AAPL].amount * pricea #notional = notional + self.portfolio.positions[data.GOOG].amount * priceg # Decision logic if self.priceg < self.priceglag and np.abs(corr) > self.corr_tolerance: self.order('AAPL',-100) self.sell_orders.append((data.AAPL.datetime, pval)) # save the order pval and time for analysis later on print "{dt}: Selling 100 AAPL shares.".format(dt = data.AAPL.datetime) elif self.priceg > self.priceglag and np.abs(corr) > self.corr_tolerance: self.order('AAPL',100) self.buy_orders.append((data.AAPL.datetime, pval)) print "{dt}: Buying 100 AAPL shares.".format(dt = data.AAPL.datetime) if self.pricea < self.pricealag and np.abs(corr) > self.corr_tolerance: self.order('GOOG',-100) self.sell_orders.append((data.GOOG.datetime, pval)) print "{dt}: Selling 100 GOOG shares.".format(dt = data.GOOG.datetime) elif self.pricea > self.pricealag and np.abs(corr) > self.corr_tolerance: self.order('GOOG',100) self.buy_orders.append((data.GOOG.datetime, pval)) print "{dt}: Buying 100 GOOG shares.".format(dt = data.GOOG.datetime) # lag price variables self.pricealag = data.AAPL.price self.priceglag = data.GOOG.price # correlation method def correlation(self, data, pricea, priceg): self.corr_values_aapl.append(pricea) self.corr_values_goog.append(priceg) corr = pearsonr(self.corr_values_aapl[-self.window_length:], self.corr_values_goog[-self.window_length:]) return corr GOOG_AAPL_COR = GOOG_AAPL_COR() results_GOOG_AAPL_COR = GOOG_AAPL_COR.run(data) plt.figure(figsize(18,10), dpi=1600) # plot 1 ax1 = plt.subplot(411) data[['GOOG', 'AAPL']].plot(ax=ax1) plt.ylabel('Price') plt.setp(ax1.get_xticklabels(), visible=False) # hide plot 1 x axis labels plt.title("GOOG_AAPL_COR Results") # prepare data for plot 2 GOOG_AAPL_COR.buy_orders = np.asarray(GOOG_AAPL_COR.buy_orders) GOOG_AAPL_COR.sell_orders = np.asarray(GOOG_AAPL_COR.sell_orders) #plot 2 ax2 = plt.subplot(412, sharex=ax1) plt.plot(GOOG_AAPL_COR.buy_orders[:,0], GOOG_AAPL_COR.buy_orders[:,1], color = 'g') plt.plot(GOOG_AAPL_COR.sell_orders[:,0], GOOG_AAPL_COR.sell_orders[:,1], color = 'r') plt.plot(GOOG_AAPL_COR.buy_orders[:,0], GOOG_AAPL_COR.buy_orders[:,1], '^', c='g', markersize=10, label='buy') plt.plot(GOOG_AAPL_COR.sell_orders[:,0], GOOG_AAPL_COR.sell_orders[:,1], 'v', c='r', markersize=10, label='sell') plt.ylabel('P-Value') plt.grid(color = 'k') plt.setp(ax2.get_xticklabels(), visible=False) plt.legend() # plot 3 ax3 = plt.subplot(413, sharex=ax1) results_GOOG_AAPL_COR.portfolio_value.plot() plt.ylabel('Portfolio Value') plt.setp(ax3.get_xticklabels(), visible=False) plt.legend() #plot 4 ax4 = plt.subplot(414, sharex=ax1) results_GOOG_AAPL_COR.portfolio_value.pct_change().plot() plt.ylabel('Portfolio % Change') plt.legend(loc='best') results_GOOG_AAPL_COR.portfolio_value.describe() # show the summary statistics for our portfolio value results_GOOG_AAPL_COR.portfolio_value.pct_change().apply(lambda x: x * 100).describe() # show the summary statistics for our returns # Plot the distribution of the returns fig = plt.figure(figsize(8,4)) results_GOOG_AAPL_COR.portfolio_value.pct_change().dropna().plot(kind='kde') plt.xlabel=('Returns') title("The Distribution of the Returns for\nGOOG_AAPL_COR") fig = plt.figure(figsize(18, 10), dpi=1600) ax1 = fig.add_subplot(211) data.SPX.plot(label='S&P Benchmark') data.GOOG.plot() data.AAPL.plot() plt.ylabel(r'Stock / Index Value') legend(loc='best') plt.setp(ax1.get_xticklabels(), visible=False) plt.title("Adj Closing Prices") ax2 = fig.add_subplot(212, sharex=ax1) (data.SPX.pct_change() - data.SPX.pct_change()).plot(label='S&P Benchmark, flatlined') (data.GOOG.pct_change() - data.SPX.pct_change()).plot(label='GOOG adj for var in S&P') (data.AAPL.pct_change() - data.SPX.pct_change()).plot(label='AAPL adj for var in S&P') plt.ylabel("Daily Return") legend(loc='best') plt.title("Adj Closing Prices adjusted for S&P movements") class GOOG_AAPL_COR_V_SP500(TradingAlgorithm): # inherit from TradingAlgorithm """ Google Apple Correlation algorithm adjusted for movements in the S&P500. An algorithm designed to exploit the correlation in the movement of Apple's and Google's common stock. """ def initialize(self): self.capital_base = 1000000 self.pricea = 0 self.priceg = 0 self.pricespx = 0 self.window_length = 5 self.corr_tolerance = 0.9 self.max_notional = self.capital_base + 0.1 self.min_notional = self.capital_base * (-1) self.pricealag = 0 self.priceglag = 0 self.pricespxlag = 0 self.buy_orders = [] self.sell_orders = [] self.corr_values_aapl = [] self.corr_values_goog = [] def handle_data(self, data): self.pricea = data.AAPL.price self.priceg = data.GOOG.price self.pricespx = data.SPX.price # find percent change and substract movements from SPX aapl_mov, goog_mov = self.spx_adjust(data, self.pricea, self.priceg, self.pricespx, self.pricealag, self.priceglag, self.pricespxlag) # calculate the correlation between the stocks corr, pval = self.correlation(data, self.pricea, self.priceg) print str(data.AAPL.datetime) + ': Pearson Correlation: ' + str(corr) # print results to console #notional = self.portfolio.positions[data.AAPL].amount * pricea #notional = notional + self.portfolio.positions[data.GOOG].amount * priceg # Decision Logic if goog_mov < 0 and np.abs(corr) > self.corr_tolerance: self.order('AAPL',-100) self.sell_orders.append((data.AAPL.datetime, pval)) # save the order amount and time for analysis print "{dt}: Selling 100 AAPL shares.".format(dt = data.AAPL.datetime) elif goog_mov > 0 and np.abs(corr) > self.corr_tolerance: self.order('AAPL',100) self.buy_orders.append((data.AAPL.datetime, pval)) print "{dt}: Buying 100 AAPL shares.".format(dt = data.AAPL.datetime) if aapl_mov < 0 and np.abs(corr) > self.corr_tolerance: self.order('GOOG',-100) self.sell_orders.append((data.GOOG.datetime, pval)) print "{dt}: Selling 100 GOOG shares.".format(dt = data.GOOG.datetime) elif aapl_mov > 0 and np.abs(corr) > self.corr_tolerance: self.order('GOOG',100) self.buy_orders.append((data.GOOG.datetime, pval)) print "{dt}: Buying 100 GOOG shares.".format(dt = data.GOOG.datetime) # lag price variables self.pricealag = data.AAPL.price self.priceglag = data.GOOG.price self.pricespxlag = data.SPX.price def correlation(self, data, pricea, priceg): self.corr_values_aapl.append(self.pricea) self.corr_values_goog.append(self.priceg) corr = pearsonr(self.corr_values_aapl[-self.window_length:], self.corr_values_goog[-self.window_length:]) # [0] only get the correltion return corr def per_change(self, data, begin, end): percent_change = ((end - begin)/begin) return percent_change def spx_adjust(self, data, pricea, priceg, pricespx, pricealag, priceglag, pricespxlag): spx_change = self.per_change(data, pricespx, self.pricespxlag) aapl_change = (self.per_change(data, pricea, self.pricealag) - spx_change) goog_change = (self.per_change(data, priceg, self.priceglag) - spx_change) return (aapl_change, goog_change) GOOG_AAPL_COR_V_SP500 = GOOG_AAPL_COR_V_SP500() results_GOOG_AAPL_COR_V_SP500 = GOOG_AAPL_COR_V_SP500.run(data) fig = plt.figure(figsize(18,12), dpi=1600) ax1 = plt.subplot(411) (data.SPX.pct_change() - data.SPX.pct_change()).plot() (data.GOOG.pct_change() - data.SPX.pct_change()).plot(label='GOOG') (data.AAPL.pct_change() - data.SPX.pct_change()).plot(label='AAPL') plt.ylabel('Daily Return') legend(loc='best') plt.title("Adj Closing Prices adjusted for S&P movements") plt.setp(ax2.get_xticklabels(), visible=False) GOOG_AAPL_COR_V_SP500.buy_orders = np.asarray(GOOG_AAPL_COR_V_SP500.buy_orders) GOOG_AAPL_COR_V_SP500.sell_orders = np.asarray(GOOG_AAPL_COR_V_SP500.sell_orders) plt.title("GOOG_AAPL_COR_V_SP500 Results") ax2 = plt.subplot(412, sharex=ax1) plt.plot(GOOG_AAPL_COR_V_SP500.buy_orders[:,0], GOOG_AAPL_COR_V_SP500.buy_orders[:,1], color = 'r') plt.plot(GOOG_AAPL_COR_V_SP500.sell_orders[:,0], GOOG_AAPL_COR_V_SP500.sell_orders[:,1], color = 'g') plt.plot(GOOG_AAPL_COR_V_SP500.buy_orders[:,0], GOOG_AAPL_COR_V_SP500.buy_orders[:,1], '^', c='g', markersize=10, label='buy') plt.plot(GOOG_AAPL_COR_V_SP500.sell_orders[:,0], GOOG_AAPL_COR_V_SP500.sell_orders[:,1], 'v', c='r', markersize=10, label='sell') plt.ylabel('P-Value') plt.grid(b=True) plt.setp(ax1.get_xticklabels(), visible=False) plt.legend() ax3 = plt.subplot(413, sharex=ax1) results_GOOG_AAPL_COR_V_SP500.portfolio_value.plot() plt.setp(ax3.get_xticklabels(), visible=False) plt.ylabel('Portfolio Value') plt.legend(loc='best') ax4 = plt.subplot(414, sharex=ax1) results_GOOG_AAPL_COR_V_SP500.portfolio_value.pct_change().plot() plt.ylabel('Portfolio % Change') plt.legend() results_GOOG_AAPL_COR_V_SP500.portfolio_value.describe() results_GOOG_AAPL_COR_V_SP500.portfolio_value.pct_change().apply(lambda x: x * 100).describe() # Plot the distribution of the returns fig = plt.figure(figsize(8,4)) results_GOOG_AAPL_COR_V_SP500.portfolio_value.pct_change().dropna().plot(kind='kde') plt.xlabel=('Returns') title("The Distribution of the Returns for\nGOOG_AAPL_COR_V_SP500") class GOOG_AAPL_COR_V_SP500_Optimized(TradingAlgorithm): # inherit from TradingAlgorithm """ Google Apple Correlation algorithm adjusted for movements in the S&P500. An algorithm designed to exploit the correlation in the movement of Apple's and Google's common stock. """ # need to add notional tollerances def initialize(self): self.capital_base = 1000000 self.pricea = 0 self.priceg = 0 self.pricespx = 0 self.trade_size_aapl = 0 self.trade_size_goog = 0 self.window_length = 5 self.corr_tolerance = 0.9 self.max_notional = self.capital_base + 0.1 self.min_notional = self.capital_base * (-1) self.pricealag = 0 self.priceglag = 0 self.pricespxlag = 0 self.buy_orders = [] self.sell_orders = [] self.corr_values_aapl = [] self.corr_values_goog = [] self.orders = 0 # set slippage in our model, as a function of our trade size and the average trading # volume at the time of the trade self.set_slippage(slippage.VolumeShareSlippage(volume_limit=0.25, price_impact=0.1)) #set commission $9.99 per trade. Cost per trade at TD Ameritrade at time of writing. self.set_commission(commission.PerTrade(cost=9.99)) def handle_data(self, data): self.pricea = data.AAPL.price self.priceg = data.GOOG.price self.pricespx = data.SPX.price # calculate trade size self.trade_size_aapl = round(((self.capital_base * 0.75) / float(self.pricea))) self.trade_size_goog = round(((self.capital_base * 0.75) / float(self.priceg))) # find percent change and substract movements from SPX aapl_mov, goog_mov = self.spx_adjust( data, self.pricea, self.priceg, self.pricespx, self.pricealag, self.priceglag, self.pricespxlag ) # calculate the correlation between the stocks corr, pval = self.correlation(data, self.pricea, self.priceg) print str(data.AAPL.datetime) + ': Pearson Correlation: ' + str(corr) #notional = self.portfolio.positions[data.AAPL].amount * pricea #notional = notional + self.portfolio.positions[data.GOOG].amount * priceg # Decision Logic if goog_mov < 0 and np.abs(corr) > self.corr_tolerance and self.orders > (-2): self.order('AAPL',-(self.trade_size_aapl)) self.sell_orders.append((data.AAPL.datetime, pval)) self.orders -= 1 print "{dt}: Selling {ts} AAPL shares.".format(dt = data.AAPL.datetime, ts = self.trade_size_aapl) elif goog_mov > 0 and np.abs(corr) > self.corr_tolerance and self.orders < (2): self.order('AAPL',(self.trade_size_aapl)) self.buy_orders.append((data.AAPL.datetime, pval)) self.orders += 1 print "{dt}: Buying {ts} AAPL shares.".format(dt = data.AAPL.datetime, ts = self.trade_size_aapl) if aapl_mov < 0 and np.abs(corr) > self.corr_tolerance and np.abs(self.orders) > (-2): self.order('GOOG',-(self.trade_size_goog)) self.sell_orders.append((data.GOOG.datetime, pval)) self.orders -= 1 print "{dt}: Selling {ts} GOOG shares.".format(dt = data.GOOG.datetime, ts = self.trade_size_goog) elif aapl_mov > 0 and np.abs(corr) > self.corr_tolerance and np.abs(self.orders) < (2): self.order('GOOG', self.trade_size_goog) self.buy_orders.append((data.GOOG.datetime, pval)) self.orders += 1 print "{dt}: Buying {ts} GOOG shares.".format(dt = data.GOOG.datetime, ts = self.trade_size_goog) # lag price variables self.pricealag = data.AAPL.price self.priceglag = data.GOOG.price self.pricespxlag = data.SPX.price def correlation(self, data, pricea, priceg): self.corr_values_aapl.append(pricea) self.corr_values_goog.append(priceg) corr = pearsonr(self.corr_values_aapl[-self.window_length:], self.corr_values_goog[-self.window_length:]) return corr def per_change(self, data, begin, end): percent_change = ((end - begin)/begin) return percent_change def spx_adjust(self, data, pricea, priceg, pricespx, pricealag, priceglag, pricespxlag): spx_change = self.per_change(data, pricespx, self.pricespxlag) aapl_change = (self.per_change(data, pricea, self.pricealag) - spx_change) goog_change = (self.per_change(data, priceg, self.priceglag) - spx_change) return (aapl_change, goog_change) GOOG_AAPL_COR_V_SP500_Optimized = GOOG_AAPL_COR_V_SP500_Optimized() results_GOOG_AAPL_COR_V_SP500_Optimized = GOOG_AAPL_COR_V_SP500_Optimized.run(data) fig = plt.figure(figsize(18,12), dpi=1600) plt.title("GOOG_AAPL_COR_V_SP500_Optimized Results") # plot 1 ax1 = plt.subplot(411) (data.SPX.pct_change() - data.SPX.pct_change()).plot() (data.GOOG.pct_change() - data.SPX.pct_change()).plot(label='GOOG') (data.AAPL.pct_change() - data.SPX.pct_change()).plot(label='AAPL') plt.ylabel("Daily Return") legend(loc='best') plt.setp(ax2.get_xticklabels(), visible=False) # prepare data for plot 2 GOOG_AAPL_COR_V_SP500_Optimized.buy_orders = np.asarray(GOOG_AAPL_COR_V_SP500_Optimized.buy_orders) GOOG_AAPL_COR_V_SP500_Optimized.sell_orders = np.asarray(GOOG_AAPL_COR_V_SP500_Optimized.sell_orders) # plot 2 ax2 = plt.subplot(412, sharex=ax1) plt.plot(GOOG_AAPL_COR_V_SP500_Optimized.buy_orders[:,0], GOOG_AAPL_COR_V_SP500_Optimized.buy_orders[:,1], color = 'g') plt.plot(GOOG_AAPL_COR_V_SP500_Optimized.sell_orders[:,0], GOOG_AAPL_COR_V_SP500_Optimized.sell_orders[:,1], color = 'r') plt.plot(GOOG_AAPL_COR_V_SP500_Optimized.buy_orders[:,0], GOOG_AAPL_COR_V_SP500_Optimized.buy_orders[:,1], '^', c='g', markersize=10, label='buy') plt.plot(GOOG_AAPL_COR_V_SP500_Optimized.sell_orders[:,0], GOOG_AAPL_COR_V_SP500_Optimized.sell_orders[:,1], 'v', c='r', markersize=10, label='sell') plt.ylabel('P-Value') plt.grid(b=True) plt.setp(ax1.get_xticklabels(), visible=False) plt.legend() # plot 3 ax3 = plt.subplot(413, sharex=ax1) results_GOOG_AAPL_COR_V_SP500_Optimized.portfolio_value.plot() plt.setp(ax3.get_xticklabels(), visible=False) plt.ylabel('Portfolio Value') plt.legend(loc='best') # plot 4 ax4 = plt.subplot(414, sharex=ax1) results_GOOG_AAPL_COR_V_SP500_Optimized.portfolio_value.pct_change().plot() plt.ylabel('Portfolio % Change') plt.legend() results_GOOG_AAPL_COR_V_SP500_Optimized.portfolio_value.describe() results_GOOG_AAPL_COR_V_SP500_Optimized.portfolio_value.pct_change().apply(lambda x: x * 100).describe() # Plot the distribution of the returns fig = plt.figure(figsize(8,4)) results_GOOG_AAPL_COR_V_SP500_Optimized.portfolio_value.pct_change().dropna().plot(kind='kde') plt.xlabel=('Returns') title("The Distribution of the Returns for\nGOOG_AAPL_COR_V_SP500_Optimized") fig = plt.figure(figsize(18,8), dpi=1600) ax1 = plt.subplot(211) results_GOOG_AAPL_COR.portfolio_value.plot(label='GOOG_AAPL_COR') results_GOOG_AAPL_COR_V_SP500.portfolio_value.plot(label='GOOG_AAPL_COR_V_SP500') results_GOOG_AAPL_COR_V_SP500_Optimized.portfolio_value.plot(label='GOOG_AAPL_COR_V_SP500_Optimized') plt.setp(ax3.get_xticklabels(), visible=False) plt.ylabel('Portfolio Value') plt.legend(loc='best') plt.title('Aggreated Performance') ax1 = plt.subplot(212, sharex=ax1) results_GOOG_AAPL_COR.portfolio_value.pct_change().plot(label='GOOG_AAPL_COR') results_GOOG_AAPL_COR_V_SP500.portfolio_value.pct_change().plot(label='GOOG_AAPL_COR_V_SP500') results_GOOG_AAPL_COR_V_SP500_Optimized.portfolio_value.pct_change().plot(label='GOOG_AAPL_COR_V_SP500_Optimized') plt.ylabel('Portfolio % Change') plt.legend(loc='best') !git add "GOOG V. AAPL Correlation Arb".ipynb !git commit