def back_test(pair, date, param): tracker = TradeAnalysis(Contract(pair[0])) algo = { 'class': ConstantAlgo } algo['param'] = {'x': pair[0], 'y': pair[1], 'a': 1, 'b': 0, 'rolling': param[0], 'bollinger': param[1], 'const': param[2], 'block': 100, 'tracker': tracker } settings = { 'date': date, 'path': DATA_PATH, 'tickset': 'top', 'algo': algo, 'singletick': True} runner = PairRunner(settings) runner.run() account = runner.account history = account.history.to_dataframe(account.items) score = float(history[['pnl']].iloc[-1]) order_win = tracker.order_winning_ratio() order_profit = tracker.analyze_all_profit()[0] num_rounds = tracker.analyze_all_profit()[2] return score, order_win, order_profit, num_rounds, runner
def back_test(pair, date, param): tracker = TradeAnalysis(Contract(pair[0])) algo = {'class': ConstantAlgo} algo['param'] = { 'x': pair[0], 'y': pair[1], 'a': 1, 'b': 0, 'rolling': param[0], 'bollinger': param[1], 'const': param[2], 'block': 100, 'tracker': tracker } settings = { 'date': date, 'path': DATA_PATH, 'tickset': 'top', 'algo': algo, 'singletick': True } runner = PairRunner(settings) runner.run() account = runner.account history = account.history.to_dataframe(account.items) score = float(history[['pnl']].iloc[-1]) order_win = tracker.order_winning_ratio() order_profit = tracker.analyze_all_profit()[0] num_rounds = tracker.analyze_all_profit()[2] return score, order_win, order_profit, num_rounds, runner
def param_updated(self): # make sure parent updates its param super(StopWinAlgo, self).param_updated() # algo settings self.if_ema = self.param['if_ema'] # if false, use sma self.if_stop_win = self.param['if_stop_win'] #if false, don't stop win self.if_consider_spread = self.param['if_consider_spread'] #if false, don't consider spread and fee # create rolling self.long_roll = SimpleMoving(size=self.param['rolling']) self.short_roll = SimpleMoving(size=self.param['rolling']) self.long_autoreg = Autoregressive(alpha = self.param['alpha']) self.short_autoreg = Autoregressive(alpha = self.param['alpha']) self.spreadx_roll = SimpleMoving(size = self.param['rolling']) self.spready_roll = SimpleMoving(size = self.param['rolling']) self.bollinger = self.param['bollinger'] self.block = self.param['block'] self.stop_win = self.param['stop_win'] #other params self.last_long_res = -999 self.last_short_res = -999 #records self.records = {'timestamp': [], 'longs': [], 'shorts': [], 'long_mean': [], 'short_mean': [], 'long_sd': [], 'short_sd':[]} #tracker self.tracker = TradeAnalysis(self.pair.x)
def param_updated(self): # make sure parent updates its param super(SMAAlgo, self).param_updated() # create rolling self.long_roll = SimpleMoving(size=self.param['rolling']) self.short_roll = SimpleMoving(size=self.param['rolling']) self.spreadx_roll = SimpleMoving(size = self.param['rolling']) self.spready_roll = SimpleMoving(size = self.param['rolling']) #params self.bollinger = self.param['bollinger'] self.block = self.param['block'] self.stop_win = self.param['stop_win'] #other params self.last_long_res = -999 self.last_short_res = -999 #records self.records = {'timestamp': [], 'longs': [], 'shorts': [], 'long_mean': [], 'short_mean': [], 'long_sd': [], 'short_sd':[]} self.max_profit = 0 #tracker self.tracker = TradeAnalysis(self.pair.x)
def get_tracker(date_list, product): pair = 0 for date in date_list: pair = get_best_pair(date,market, product) if type(pair) != tuple: continue else: break return TradeAnalysis(Contract(pair[0]))
def back_test(pair, date, param): tracker = TradeAnalysis(Contract(pair[0])) algo = {"class": OUAlgo} algo["param"] = { "x": pair[0], "y": pair[1], "a": 1, "b": 0, "rolling": param[0], "bollinger": param[1], "block": 100, "tracker": tracker, } settings = {"date": date, "path": DATA_PATH, "tickset": "top", "algo": algo, "singletick": True} runner = PairRunner(settings) runner.run() account = runner.account history = account.history.to_dataframe(account.items) score = float(history[["pnl"]].iloc[-1]) order_win = tracker.order_winning_ratio() order_profit = tracker.analyze_all_profit()[0] num_rounds = tracker.analyze_all_profit()[2] return score, order_win, order_profit, num_rounds
def param_updated(self): # make sure parent updates its param super(StopWinAlgo, self).param_updated() # algo settings self.if_ema = self.param["if_ema"] # if false, use sma self.if_stop_win = self.param["if_stop_win"] # if false, don't stop win self.if_consider_spread = self.param["if_consider_spread"] # if false, don't consider spread and fee # create rolling self.long_roll = SimpleMoving(size=self.param["rolling"]) self.short_roll = SimpleMoving(size=self.param["rolling"]) self.long_autoreg = Autoregressive(alpha=self.param["alpha"]) self.short_autoreg = Autoregressive(alpha=self.param["alpha"]) self.spreadx_roll = SimpleMoving(size=self.param["rolling"]) self.spready_roll = SimpleMoving(size=self.param["rolling"]) self.bollinger = self.param["bollinger"] self.block = self.param["block"] self.stop_win = self.param["stop_win"] # other params self.last_long_res = -999 self.last_short_res = -999 # records self.records = { "timestamp": [], "longs": [], "shorts": [], "long_mean": [], "short_mean": [], "long_sd": [], "short_sd": [], } # tracker self.tracker = TradeAnalysis(self.pair.x)
class StopWinAlgo(PairAlgoWrapper): # called when algo param is set def param_updated(self): # make sure parent updates its param super(StopWinAlgo, self).param_updated() # algo settings self.if_ema = self.param['if_ema'] # if false, use sma self.if_stop_win = self.param['if_stop_win'] #if false, don't stop win self.if_consider_spread = self.param[ 'if_consider_spread'] #if false, don't consider spread and fee # create rolling self.long_roll = SimpleMoving(size=self.param['rolling']) self.short_roll = SimpleMoving(size=self.param['rolling']) self.long_autoreg = Autoregressive(alpha=self.param['alpha']) self.short_autoreg = Autoregressive(alpha=self.param['alpha']) self.spreadx_roll = SimpleMoving(size=self.param['rolling']) self.spready_roll = SimpleMoving(size=self.param['rolling']) self.bollinger = self.param['bollinger'] self.block = self.param['block'] self.stop_win = self.param['stop_win'] #other params self.last_long_res = -999 self.last_short_res = -999 #records self.records = { 'timestamp': [], 'longs': [], 'shorts': [], 'long_mean': [], 'short_mean': [], 'long_sd': [], 'short_sd': [] } #tracker self.tracker = TradeAnalysis(self.pair.x) # what to do on every tick def on_tick(self, multiple, contract, info): self.tracker.tick_pass_by() # tell the tracker that one tick passed by # skip if price_table doesnt have both if len(self.price_table.table) < 2: return # get residuals and position long_res = self.pair.get_long_residual() short_res = self.pair.get_short_residual() pos = self.position_y() ## only do this when plotting is neede #update record # if self.if_ema: # self._update_record(long_res, self.autoreg.mean, self.long_roll.sd,\ # short_res, self.autoreg.mean, self.short_roll.sd) # else: # self._update_record(long_res, self.long_roll.mean, self.long_roll.sd,\ # short_res, self.short_roll.mean, self.short_roll.sd) #calculate profit for this round profit = 0 if pos == -1: profit = long_res + self.last_short_res elif pos == 1: profit = short_res + self.last_long_res #two spread spreadx = self.spreadx_roll.mean spready = self.spready_roll.mean avg_spread = (spreadx + spready) / 2 #fee fee = self.pair.get_fee() # stop short position if self.if_stop_win: if pos == -1: if (profit >= max(1, self.stop_win * self.long_roll.sd) and self.if_consider_spread == False) \ or (profit >= max(1, self.stop_win * self.long_roll.sd, fee) and self.if_consider_spread == True): self.long_y(y_qty=1) self.last_long_res = long_res self.tracker.close_with_stop(profit) return # stop long position if pos == 1: if (profit >= max(1, self.stop_win * self.long_roll.sd) and self.if_consider_spread == False) \ or (profit >= max(1, self.stop_win * self.long_roll.sd, fee) and self.if_consider_spread == True): self.short_y(y_qty=1) self.last_short_res = short_res self.tracker.close_with_stop(profit) return # open or close position # action only when unblocked: bock size < rolling queue size if self.long_roll.queue.qsize() > self.block: # long when test long_res > mean+bollinger*sd if (long_res > self.long_autoreg.mean + self.bollinger * self.long_roll.sd \ and self.if_ema == True and self.if_consider_spread == False) \ or (self.long_roll.test_sigma(long_res, self.bollinger) \ and self.if_ema == False and self.if_consider_spread == False) \ or (long_res - self.long_autoreg.mean > max(fee + avg_spread, self.bollinger * self.long_roll.sd) \ and self.if_ema == True and self.if_consider_spread == True) \ or (self.long_roll.test_sigma(long_res, self.bollinger) \ and long_res - self.long_roll.mean > fee + avg_spread \ and self.if_ema == False and self.if_consider_spread == True): \ # only long when position is 0 or -1 if pos <= 0: self.long_y(y_qty=1) self.last_long_res = long_res #tell the tracker if pos == 0: self.tracker.open_position() else: self.tracker.close_with_exit(profit) return # short when test short_res > mean+bollinger*sd elif (short_res > self.short_autoreg.mean + self.bollinger * self.short_roll.sd \ and self.if_ema == True and self.if_consider_spread == False) \ or (self.short_roll.test_sigma(short_res, self.bollinger) \ and self.if_ema == False and self.if_consider_spread == False) \ or (short_res - self.short_autoreg.mean > max(fee + avg_spread, self.bollinger * self.short_roll.sd) \ and self.if_ema == True and self.if_consider_spread == True) \ or (self.short_roll.test_sigma(short_res, self.bollinger) \ and short_res - self.short_roll.mean > fee + avg_spread \ and self.if_ema == False and self.if_consider_spread == True): \ # only short when position is 0 or 1 if pos >= 0: self.short_y(y_qty=1) self.last_short_res = short_res #tell the tracker if pos == 0: self.tracker.open_position() else: self.tracker.close_with_exit(profit) return else: pass # update rolling self.long_roll.add(long_res) self.short_roll.add(short_res) self.long_autoreg.add(long_res) self.short_autoreg.add(short_res) self.spreadx_roll.add(self.pair.get_spread_x()) self.spready_roll.add(self.pair.get_spread_y()) def on_daystart(self, date, info_x, info_y): # recreate rolling at each day start self.long_roll = SimpleMoving(size=self.param['rolling']) self.short_roll = SimpleMoving(size=self.param['rolling']) self.long_autoreg = Autoregressive(alpha=self.param['alpha']) self.short_autoreg = Autoregressive(alpha=self.param['alpha']) self.spreadx_roll = SimpleMoving(size=self.param['rolling']) self.spready_roll = SimpleMoving(size=self.param['rolling']) def on_dayend(self, date, info_x, info_y): #force close on day end pos = self.position_y() # stop short position if pos == -1: self.long_y(y_qty=1) return # stop long position if pos == 1: self.short_y(y_qty=1) return def _update_record(self, long_res, long_mean, long_std, short_res, short_mean, short_std): self.records['timestamp'].append(Clock.timestamp) self.records['longs'].append(long_res) self.records['shorts'].append(short_res) self.records['long_mean'].append(long_mean) self.records['short_mean'].append(short_mean) self.records['long_sd'].append(long_std) self.records['short_sd'].append(short_std)
class StopWinAlgo(PairAlgoWrapper): # called when algo param is set def param_updated(self): # make sure parent updates its param super(StopWinAlgo, self).param_updated() # algo settings self.if_ema = self.param["if_ema"] # if false, use sma self.if_stop_win = self.param["if_stop_win"] # if false, don't stop win self.if_consider_spread = self.param["if_consider_spread"] # if false, don't consider spread and fee # create rolling self.long_roll = SimpleMoving(size=self.param["rolling"]) self.short_roll = SimpleMoving(size=self.param["rolling"]) self.long_autoreg = Autoregressive(alpha=self.param["alpha"]) self.short_autoreg = Autoregressive(alpha=self.param["alpha"]) self.spreadx_roll = SimpleMoving(size=self.param["rolling"]) self.spready_roll = SimpleMoving(size=self.param["rolling"]) self.bollinger = self.param["bollinger"] self.block = self.param["block"] self.stop_win = self.param["stop_win"] # other params self.last_long_res = -999 self.last_short_res = -999 # records self.records = { "timestamp": [], "longs": [], "shorts": [], "long_mean": [], "short_mean": [], "long_sd": [], "short_sd": [], } # tracker self.tracker = TradeAnalysis(self.pair.x) # what to do on every tick def on_tick(self, multiple, contract, info): self.tracker.tick_pass_by() # tell the tracker that one tick passed by # skip if price_table doesnt have both if len(self.price_table.table) < 2: return # get residuals and position long_res = self.pair.get_long_residual() short_res = self.pair.get_short_residual() pos = self.position_y() ## only do this when plotting is neede # update record # if self.if_ema: # self._update_record(long_res, self.autoreg.mean, self.long_roll.sd,\ # short_res, self.autoreg.mean, self.short_roll.sd) # else: # self._update_record(long_res, self.long_roll.mean, self.long_roll.sd,\ # short_res, self.short_roll.mean, self.short_roll.sd) # calculate profit for this round profit = 0 if pos == -1: profit = long_res + self.last_short_res elif pos == 1: profit = short_res + self.last_long_res # two spread spreadx = self.spreadx_roll.mean spready = self.spready_roll.mean avg_spread = (spreadx + spready) / 2 # fee fee = self.pair.get_fee() # stop short position if self.if_stop_win: if pos == -1: if (profit >= max(1, self.stop_win * self.long_roll.sd) and self.if_consider_spread == False) or ( profit >= max(1, self.stop_win * self.long_roll.sd, fee) and self.if_consider_spread == True ): self.long_y(y_qty=1) self.last_long_res = long_res self.tracker.close_with_stop(profit) return # stop long position if pos == 1: if (profit >= max(1, self.stop_win * self.long_roll.sd) and self.if_consider_spread == False) or ( profit >= max(1, self.stop_win * self.long_roll.sd, fee) and self.if_consider_spread == True ): self.short_y(y_qty=1) self.last_short_res = short_res self.tracker.close_with_stop(profit) return # open or close position # action only when unblocked: bock size < rolling queue size if self.long_roll.queue.qsize() > self.block: # long when test long_res > mean+bollinger*sd if ( ( long_res > self.long_autoreg.mean + self.bollinger * self.long_roll.sd and self.if_ema == True and self.if_consider_spread == False ) or ( self.long_roll.test_sigma(long_res, self.bollinger) and self.if_ema == False and self.if_consider_spread == False ) or ( long_res - self.long_autoreg.mean > max(fee + avg_spread, self.bollinger * self.long_roll.sd) and self.if_ema == True and self.if_consider_spread == True ) or ( self.long_roll.test_sigma(long_res, self.bollinger) and long_res - self.long_roll.mean > fee + avg_spread and self.if_ema == False and self.if_consider_spread == True ) ): # only long when position is 0 or -1 if pos <= 0: self.long_y(y_qty=1) self.last_long_res = long_res # tell the tracker if pos == 0: self.tracker.open_position() else: self.tracker.close_with_exit(profit) return # short when test short_res > mean+bollinger*sd elif ( ( short_res > self.short_autoreg.mean + self.bollinger * self.short_roll.sd and self.if_ema == True and self.if_consider_spread == False ) or ( self.short_roll.test_sigma(short_res, self.bollinger) and self.if_ema == False and self.if_consider_spread == False ) or ( short_res - self.short_autoreg.mean > max(fee + avg_spread, self.bollinger * self.short_roll.sd) and self.if_ema == True and self.if_consider_spread == True ) or ( self.short_roll.test_sigma(short_res, self.bollinger) and short_res - self.short_roll.mean > fee + avg_spread and self.if_ema == False and self.if_consider_spread == True ) ): # only short when position is 0 or 1 if pos >= 0: self.short_y(y_qty=1) self.last_short_res = short_res # tell the tracker if pos == 0: self.tracker.open_position() else: self.tracker.close_with_exit(profit) return else: pass # update rolling self.long_roll.add(long_res) self.short_roll.add(short_res) self.long_autoreg.add(long_res) self.short_autoreg.add(short_res) self.spreadx_roll.add(self.pair.get_spread_x()) self.spready_roll.add(self.pair.get_spread_y()) def on_daystart(self, date, info_x, info_y): # recreate rolling at each day start self.long_roll = SimpleMoving(size=self.param["rolling"]) self.short_roll = SimpleMoving(size=self.param["rolling"]) self.long_autoreg = Autoregressive(alpha=self.param["alpha"]) self.short_autoreg = Autoregressive(alpha=self.param["alpha"]) self.spreadx_roll = SimpleMoving(size=self.param["rolling"]) self.spready_roll = SimpleMoving(size=self.param["rolling"]) def on_dayend(self, date, info_x, info_y): # force close on day end pos = self.position_y() # stop short position if pos == -1: self.long_y(y_qty=1) return # stop long position if pos == 1: self.short_y(y_qty=1) return def _update_record(self, long_res, long_mean, long_std, short_res, short_mean, short_std): self.records["timestamp"].append(Clock.timestamp) self.records["longs"].append(long_res) self.records["shorts"].append(short_res) self.records["long_mean"].append(long_mean) self.records["short_mean"].append(short_mean) self.records["long_sd"].append(long_std) self.records["short_sd"].append(short_std)
class SMAAlgo(PairAlgoWrapper): # called when algo param is set def param_updated(self): # make sure parent updates its param super(SMAAlgo, self).param_updated() # create rolling self.long_roll = SimpleMoving(size=self.param['rolling']) self.short_roll = SimpleMoving(size=self.param['rolling']) self.spreadx_roll = SimpleMoving(size = self.param['rolling']) self.spready_roll = SimpleMoving(size = self.param['rolling']) #params self.bollinger = self.param['bollinger'] self.block = self.param['block'] self.stop_win = self.param['stop_win'] #other params self.last_long_res = -999 self.last_short_res = -999 #records self.records = {'timestamp': [], 'longs': [], 'shorts': [], 'long_mean': [], 'short_mean': [], 'long_sd': [], 'short_sd':[]} self.max_profit = 0 #tracker self.tracker = TradeAnalysis(self.pair.x) def on_tick(self, multiple, contract, info): self.tracker.tick_pass_by() # skip if price_table doesnt have both, TODO fix this bug internally if len(self.price_table.table) < 2: return # get residuals and position long_res = self.pair.get_long_residual() short_res = self.pair.get_short_residual() pos = self.position_y() #two spread spreadx = self.spreadx_roll.mean spready = self.spready_roll.mean avg_spread = (spreadx + spready)/2 #fee fee = self.pair.get_fee() #update record # self._update_record(long_res, self.long_roll.mean, self.long_roll.sd,\ # short_res, self.short_roll.mean, self.short_roll.sd) #calculate profit profit = 0 if pos == -1: profit = long_res + self.last_short_res elif pos == 1: profit = short_res + self.last_long_res #trailing stop win if profit > self.max_profit and profit > 0: self.max_profit = profit else: # stop short position if pos == -1: if self.max_profit - profit > max(1,self.stop_win * self.long_roll.sd) and profit > 0: self.long_y(y_qty = 1) self.last_long_res = long_res self.tracker.close_with_stop(profit - fee) return # stop long position if pos == 1: if self.max_profit - profit > max(1,self.stop_win * self.short_roll.sd) and profit > 0: self.short_y(y_qty = 1) self.last_short_res = short_res self.tracker.close_with_stop(profit - fee) return # action only when unblocked: bock size < rolling queue size if self.long_roll.queue.qsize() > self.block: # long when test long_res > mean+bollinger*sd if self.long_roll.test_sigma(long_res, self.bollinger) \ and long_res > self.long_roll.mean + avg_spread + fee/2: # only long when position is 0 or -1 if pos <= 0: self.long_y(y_qty=1) self.last_long_res = long_res self.max_profit = 0 #tell the tracker if pos == 0: self.tracker.open_position() else: self.tracker.close_with_exit(profit - fee) return # short when test short_res > mean+bollinger*sd elif self.short_roll.test_sigma(short_res, self.bollinger) \ and short_res > self.short_roll.mean + avg_spread + fee/2: # only short when position is 0 or 1 if pos >= 0: self.short_y(y_qty=1) self.last_short_res = short_res self.max_profit = 0 #tell the tracker if pos == 0: self.tracker.open_position() else: self.tracker.close_with_exit(profit - fee) return else: pass # update rolling self.long_roll.add(long_res) self.short_roll.add(short_res) self.spreadx_roll.add(self.pair.get_spread_x()) self.spready_roll.add(self.pair.get_spread_y()) def on_daystart(self, date, info_x, info_y): # recreate rolling at each day start self.long_roll = SimpleMoving(size=self.param['rolling']) self.short_roll = SimpleMoving(size=self.param['rolling']) self.spreadx_roll = SimpleMoving(size = self.param['rolling']) self.spready_roll = SimpleMoving(size = self.param['rolling']) def on_dayend(self, date, info_x, info_y): pos = self.position_y() # stop short position if pos == -1: self.long_y(y_qty = 1) return # stop long position if pos == 1: self.short_y(y_qty = 1) return def _update_record(self, long_res, long_mean, long_std, short_res, short_mean, short_std): self.records['timestamp'].append(Clock.timestamp) self.records['longs'].append(long_res) self.records['shorts'].append(short_res) self.records['long_mean'].append(long_mean) self.records['short_mean'].append(short_mean) self.records['long_sd'].append(long_std) self.records['short_sd'].append(short_std)