def simdf_to_trades1(df, slippage = 0): xdf = df[df['pos'] != df['pos'].shift(1)] prev_pos = 0 tradeid = 0 pos_list = [] closed_trades = [] for o, c, pos, tprice, cont, dtime in zip(xdf['open'], xdf['close'], xdf['pos'], xdf['traded_price'], xdf['contract'], xdf.index): if (prev_pos * pos >=0) and (abs(prev_pos)<abs(pos)): if len(pos_list)>0 and (pos_list[-1].pos*(pos - prev_pos) < 0): print "Error: the new trade should be on the same direction of the existing trade cont=%s, prev_pos=%s, pos=%s, time=%s" % (cont, prev_pos, pos, dtime) new_pos = strat.TradePos([cont], [1], pos - prev_pos, tprice, tprice) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(tprice + misc.sign(pos - prev_pos)*slippage, dtime) pos_list.append(new_pos) else: for i, tp in enumerate(reversed(pos_list)): if (prev_pos - tp.pos - pos) * (prev_pos) < 0: break else: tp.close(tprice - misc.sign(tp.pos)*slippage, dtime) prev_pos -= tp.pos tradeid += 1 tp.exit_tradeid = tradeid closed_trades.append(tp) pos_list = [ tp for tp in pos_list if not tp.is_closed ] if prev_pos != pos: if len(pos_list) == 0: new_pos = strat.TradePos([cont], [1], pos - prev_pos, tprice, tprice) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(tprice + misc.sign(pos - prev_pos)*slippage, dtime) pos_list.append(new_pos) else: print "Warning: handling partial position for prev_pos=%s, pos=%s, cont=%s, time=%s, should avoid this situation!" % (prev_pos, pos, cont, dtime) partial_tp = copy.deepcopy(pos_list[-1]) partial_tp.pos = prev_pos - pos partial_tp.close(tprice - misc.sign(tp.pos)*slippage, dtime) tradeid += 1 partial_tp.exit_tradeid = tradeid closed_trades.append(partial_tp) pos_list[-1].pos -= prev_pos - pos prev_pos = pos if (len(pos_list) !=0) or (prev_pos!=0): print "ERROR: something wrong with the backtest position management - there are unclosed positions after the test" return closed_trades
def open_tradepos(self, contracts, price, traded_pos): tp = price + misc.sign(traded_pos) * self.offset new_pos = self.pos_class(insts = contracts, volumes = self.weights, \ pos = self.unit * traded_pos, \ entry_target = tp, exit_target = tp, \ multiple = 1, **self.pos_args) new_pos.entry_tradeid = self.tradeid self.tradeid += 1 new_pos.open(tp, self.unit * traded_pos, self.timestamp) self.positions.append(new_pos) self.traded_price = (self.traded_price * self.traded_vol + tp * new_pos.pos)/(self.traded_vol + new_pos.pos) self.traded_vol += new_pos.pos self.traded_cost += abs(new_pos.pos) * (self.offset + tp * self.tcost)
def simdf_to_trades2(df, slippage=0.0): xdf = df[df['pos'] != df['pos'].shift(1)] prev_pos = 0 tradeid = 0 pos_list = [] closed_trades = [] for o, c, pos, tprice, cont, dtime in zip(xdf['open'], xdf['close'], xdf['pos'], xdf['traded_price'], xdf['contract'], xdf.index): if (prev_pos * pos >= 0) and (abs(prev_pos) < abs(pos)): if len(pos_list) > 0 and (pos_list[-1].pos * (pos - prev_pos) < 0): print "Error: the new trade should be on the same direction of the existing trade cont=%s, prev_pos=%s, pos=%s, time=%s" % ( cont, prev_pos, pos, dtime) npos = int(abs(pos - prev_pos)) new_pos = [trade_position.TradePos(insts=[cont], volumes=[1], pos=misc.sign(pos - prev_pos), entry_target=tprice, exit_target=tprice) for i in range(npos)] for tpos in new_pos: tradeid += 1 tpos.entry_tradeid = tradeid tpos.open(tprice, misc.sign(pos - prev_pos), dtime) pos_list = pos_list + new_pos new_pos = [trade_position.TradePos(insts=[cont], volumes=[1], pos=misc.sign(pos - prev_pos), entry_target=tprice, exit_target=tprice) for i in range(npos)] for tpos in new_pos: tradeid += 1 tpos.entry_tradeid = tradeid tpos.open(tprice, misc.sign(pos - prev_pos), dtime) pos_list = pos_list + new_pos else: for i, tp in enumerate(reversed(pos_list)): if (prev_pos - tp.pos - pos) * (prev_pos) < 0: break else: tp.close(tprice, dtime) prev_pos -= tp.pos tradeid += 1 tp.exit_tradeid = tradeid closed_trades.append(tp) pos_list = [tp for tp in pos_list if not tp.is_closed] if prev_pos != pos: if len(pos_list) == 0: npos = int(abs(pos - prev_pos)) new_pos = [ trade_position.TradePos(insts=[cont], volumes=[1], pos=misc.sign(pos - prev_pos), entry_target=tprice, exit_target=tprice) for i in range(npos)] for tpos in new_pos: tradeid += 1 tpos.entry_tradeid = tradeid tpos.open(tprice, misc.sign(pos - prev_pos), dtime) pos_list = pos_list + new_pos else: print "Warning: This should not happen for unit tradepos for prev_pos=%s, pos=%s, cont=%s, time=%s, should avoid this situation!" % ( prev_pos, pos, cont, dtime) prev_pos = pos if (len(pos_list) != 0) or (prev_pos != 0): print "ERROR: something wrong with the backtest position management - there are unclosed positions after the test" return closed_trades
def simdf_to_trades2(df, slippage=0.0): xdf = df[df['pos'] != df['pos'].shift(1)] prev_pos = 0 tradeid = 0 pos_list = [] closed_trades = [] for pos, tprice, cont, dtime in zip(xdf['pos'], xdf['traded_price'], xdf['contract'], xdf.index): if (prev_pos * pos >= 0) and (abs(prev_pos) < abs(pos)): if len(pos_list) > 0 and (pos_list[-1].pos * (pos - prev_pos) < 0): print "Error: the new trade should be on the same direction of the existing trade cont=%s, prev_pos=%s, pos=%s, time=%s" % ( cont, prev_pos, pos, dtime) npos = int(abs(pos - prev_pos)) new_pos = [trade_position.TradePos(insts=[cont], volumes=[1], pos=misc.sign(pos - prev_pos), entry_target=tprice, exit_target=tprice) for i in range(npos)] for tpos in new_pos: tradeid += 1 tpos.entry_tradeid = tradeid tpos.open(tprice, misc.sign(pos - prev_pos), dtime) pos_list = pos_list + new_pos new_pos = [trade_position.TradePos(insts=[cont], volumes=[1], pos=misc.sign(pos - prev_pos), entry_target=tprice, exit_target=tprice) for i in range(npos)] for tpos in new_pos: tradeid += 1 tpos.entry_tradeid = tradeid tpos.open(tprice, misc.sign(pos - prev_pos), dtime) pos_list = pos_list + new_pos else: for i, tp in enumerate(reversed(pos_list)): if (prev_pos - tp.pos - pos) * (prev_pos) < 0: break else: tp.close(tprice, dtime) prev_pos -= tp.pos tradeid += 1 tp.exit_tradeid = tradeid closed_trades.append(tp) pos_list = [tp for tp in pos_list if not tp.is_closed] if prev_pos != pos: if len(pos_list) == 0: npos = int(abs(pos - prev_pos)) new_pos = [ trade_position.TradePos(insts=[cont], volumes=[1], pos=misc.sign(pos - prev_pos), entry_target=tprice, exit_target=tprice) for i in range(npos)] for tpos in new_pos: tradeid += 1 tpos.entry_tradeid = tradeid tpos.open(tprice, misc.sign(pos - prev_pos), dtime) pos_list = pos_list + new_pos else: print "Warning: This should not happen for unit tradepos for prev_pos=%s, pos=%s, cont=%s, time=%s, should avoid this situation!" % ( prev_pos, pos, cont, dtime) prev_pos = pos if (len(pos_list) != 0) or (prev_pos != 0): print "ERROR: something wrong with the backtest position management - there are unclosed positions after the test" return closed_trades
def dual_thrust_sim( mdf, config): ddf = config['ddf'] close_daily = config['close_daily'] marginrate = config['marginrate'] offset = config['offset'] k = config['param'][0] win = config['param'][1] multiplier = config['param'][2] f = config['param'][3] ep_enabled = config['EP'] start_equity = config['capital'] chan = config['chan'] chan_func = config['chan_func'] tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] min_rng = config['min_range'] no_trade_set = config['no_trade_set'] if win == -1: tr= pd.concat([ddf.high - ddf.low, ddf.close - ddf.close.shift(1)], join='outer', axis=1).max(axis=1).shift(1) elif win == 0: tr = pd.concat([(pd.rolling_max(ddf.high, 2) - pd.rolling_min(ddf.close, 2))*multiplier, (pd.rolling_max(ddf.close, 2) - pd.rolling_min(ddf.low, 2))*multiplier, ddf.high - ddf.close, ddf.close - ddf.low], join='outer', axis=1).max(axis=1).shift(1) else: tr= pd.concat([pd.rolling_max(ddf.high, win) - pd.rolling_min(ddf.close, win), pd.rolling_max(ddf.close, win) - pd.rolling_min(ddf.low, win)], join='outer', axis=1).max(axis=1).shift(1) ddf['TR'] = tr ddf['H1'] = eval(chan_func['high']['func'])(ddf, chan, **chan_func['high']['args']).shift(1) ddf['L1'] = eval(chan_func['low']['func'])(ddf, chan, **chan_func['low']['args']).shift(1) ll = mdf.shape[0] mdf['pos'] = pd.Series([0]*ll, index = mdf.index) mdf['cost'] = pd.Series([0]*ll, index = mdf.index) curr_pos = [] closed_trades = [] start_d = ddf.index[0] end_d = mdf.index[-1].date() prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 for dd in mdf.index: mslice = mdf.ix[dd] min_id = agent.get_min_id(dd) d = dd.date() dslice = ddf.ix[d] if np.isnan(dslice.TR) or (mslice.close == 0): continue if (mslice.low == 0): mslice.low = mslice.close if mslice.high >= mslice.open * 1.2: mslice.high = mslice.close if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos d_open = dslice.open if (prev_d < d): d_open = mslice.open d_high = mslice.high d_low = mslice.low else: d_open = dslice.open d_high = max(d_high, mslice.high) d_low = min(d_low, mslice.low) if (d_open <= 0): continue prev_d = d buytrig = d_open + max(min_rng * d_open, dslice.TR * k) selltrig = d_open - max(min_rng * d_open, dslice.TR * k) if ep_enabled: buytrig = max(buytrig, d_high) selltrig = min(selltrig, d_low) if (min_id >= config['exit_min']) : if (pos != 0) and (close_daily or (d == end_d)): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 elif min_id not in no_trade_set: if (pos!=0) and (SL>0): curr_pos[0].trail_update(mslice.close) if curr_pos[0].check_exit(mslice.close, SL*mslice.close): curr_pos[0].close(mslice.close-offset*misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 if (mslice.high >= buytrig) and (pos <=0 ): if len(curr_pos) > 0: curr_pos[0].close(mslice.close+offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) if mslice.high >= dslice.H1: new_pos = strat.TradePos([mslice.contract], [1], unit, mslice.close + offset, mslice.close + offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) elif (mslice.low <= selltrig) and (pos >=0 ): if len(curr_pos) > 0: curr_pos[0].close(mslice.close-offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) if mslice.low <= dslice.L1: new_pos = strat.TradePos([mslice.contract], [1], -unit, mslice.close - offset, mslice.close - offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) mdf.ix[dd, 'pos'] = pos (res_pnl, ts) = backtest.get_pnl_stats( mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats( closed_trades ) res = dict( res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def move_to(self, newpos): ''' Arguments: newpos: new position vector, the length of this vector sets which channels will be used. ''' channels = len(newpos) pos = [self._posins.get_position(i) for i in range(channels)] stepspos = [0 for i in range(channels)] est = [] for i in range(channels): e = PositionEstimator() e.add(pos[i], stepspos[i]) est.append(e) delta = [newpos[i] - pos[i] for i in range(channels)] dist = [abs(delta[i]) for i in range(channels)] hold = [False for i in range(channels)] increase_steps = True # print 'move_to(): start pos = %r, delta = %r, dist = %r' % \ # (pos, delta, dist) steps = [ -misc.sign(delta[i]) * self._startstep for i in range(channels) ] j = 0 while j < 1000: # Move for i in range(channels): if not hold[i]: self._moveins.move_steps(i + self._channel_ofs, steps[i]) stepspos[i] += steps[i] time.sleep(self._delay) # Update position pos2 = [self._posins.get_position(i) for i in range(channels)] realpos2 = pos2[0] delta2 = [newpos[i] - pos2[i] for i in range(channels)] dist2 = [abs(delta2[i]) for i in range(channels)] for i in range(channels): pos2[i] = est[i].add(pos2[i], stepspos[i]) # print 'move_to(): pos = %r, delta2 = %r' % (pos2, delta2) # Increase step size exponentially if increase_steps: for i in range(channels): if not hold[i]: if misc.sign(delta2[i]) != misc.sign(delta[i]): hold[i] = True elif abs(steps[i]) != self._maxstep: steps[i] = misc.sign(delta2[i]) * min( abs(steps[i]) * 2, self._maxstep) # print 'move_to(): increasing stepsize for ch%d to %f' % (i, steps[i]) if all_true(hold): # print 'move_to(): increase_steps=False' increase_steps = False for i in range(channels): hold[i] = False if self._use_reset: est[i].reset() # Immediately reverse if we moved too far if not increase_steps: for i in range(channels): if not hold[i]: if misc.sign(delta2[i]) != misc.sign(delta[i]): if abs(steps[i]) == self._minstep: hold[i] = True else: steps[i] = int( misc.sign(delta2[i]) * max(round(abs(steps[i]) / 2), self._minstep)) if self._use_reset: est[i].reset() # print 'move_to(): reversing and decreasing stepsize for ch%d to %f' % (i, steps[i]) if all_true(hold): # print 'move_to(): Moved to position!' return realpos2 # Remember relative position delta = delta2 j += 1
def dual_thrust_sim(mdf, config): close_daily = config['close_daily'] marginrate = config['marginrate'] offset = config['offset'] k = config['k'] f = config['f'] start_equity = config['capital'] win = config['win'] multiplier = config['m'] tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] min_rng = config['min_range'] ma_fast = config['MA_fast'] ll = mdf.shape[0] mdf['min_idx'] = pd.Series(1, index=mdf.index) mdf.loc[mdf['min_id'] < 1500, 'min_idx'] = 0 mdf['date_idx'] = mdf.index.date xdf = mdf.groupby([mdf['date_idx'], mdf['min_idx'] ]).apply(dh.ohlcsum).reset_index().set_index('datetime') if win == -1: tr = pd.concat( [xdf.high - xdf.low, abs(xdf.close - xdf.close.shift(1))], join='outer', axis=1).max(axis=1).shift(1) elif win == -2: tr = pd.rolling_max(xdf.high, 2) - pd.rolling_min(xdf.low, 2) elif win == 0: tr = pd.concat( [(pd.rolling_max(xdf.high, 2) - pd.rolling_min(xdf.close, 2)) * multiplier, (pd.rolling_max(xdf.close, 2) - pd.rolling_min(xdf.low, 2)) * multiplier, xdf.high - xdf.close, xdf.close - xdf.low], join='outer', axis=1).max(axis=1).shift(1) else: tr = pd.concat([ pd.rolling_max(xdf.high, win) - pd.rolling_min(xdf.close, win), pd.rolling_max(xdf.close, win) - pd.rolling_min(xdf.low, win) ], join='outer', axis=1).max(axis=1).shift(1) xdf['TR'] = tr xdf['MA'] = pd.rolling_mean(xdf.close, ma_fast).shift(1) ddf = pd.concat([xdf['TR'], xdf['MA'], xdf['open'], xdf['date_idx']], axis=1, keys=['TR', 'MA', 'dopen', 'date']).fillna(0) mdf = mdf.join(ddf, how='left').fillna(method='ffill') mdf['pos'] = pd.Series([0] * ll, index=mdf.index) mdf['cost'] = pd.Series([0] * ll, index=mdf.index) curr_pos = [] closed_trades = [] start_d = ddf.index[0] end_d = mdf.index[-1].date() #prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 for dd in mdf.index: mslice = mdf.ix[dd] min_id = agent.get_min_id(dd) if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if mslice.TR == 0 or mslice.MA == 0: continue d_open = mslice.dopen #if (prev_d < d): # d_open = mslice.open #else: # d_open = dslice.open rng = max(min_rng * d_open, k * mslice.TR) if (d_open <= 0): continue buytrig = d_open + rng selltrig = d_open - rng if mslice.MA > mslice.close: buytrig += f * rng elif mslice.MA < mslice.close: selltrig -= f * rng if (min_id >= config['exit_min']) and (close_daily or (mslice.date == end_d)): if (pos != 0): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 else: if (pos != 0) and (SL > 0): curr_pos[0].trail_update(mslice.close) if (curr_pos[0].trail_check(mslice.close, SL * mslice.close)): curr_pos[0].close(mslice.close - offset * misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 if (mslice.high >= buytrig) and (pos <= 0): if len(curr_pos) > 0: curr_pos[0].close(mslice.close + offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) new_pos = strat.TradePos([mslice.contract], [1], unit, mslice.close + offset, mslice.close + offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) elif (mslice.low <= selltrig) and (pos >= 0): if len(curr_pos) > 0: curr_pos[0].close(mslice.close - offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) new_pos = strat.TradePos([mslice.contract], [1], -unit, mslice.close - offset, mslice.close - offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) mdf.ix[dd, 'pos'] = pos (res_pnl, ts) = backtest.get_pnl_stats(mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats(closed_trades) res = dict(res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def layer_sim(mdf, config): tcost = config['trans_cost'] unit = config['unit'] offset = config['offset'] pos_class = config['pos_class'] pos_args = config['pos_args'] freq = config['freq'] signal_func = config['signal_func'] signal_args = config['signal_args'] signal_level = config['signal_level'] close_daily = config['close_daily'] for idx, (f, sfunc, sargs, slvl) in enumerate( zip(freq, signal_func, signal_args, signal_level)): df = dh.conv_ohlc_freq(mdf, f, extra_cols=['contract']) if idx == 0: xdf = df farg = tuple(sargs) func = eval(sfunc[0]) sigout = func(df, *farg) sig_field = sfunc[1] % farg signal = sigout[sig_field] long_lvl = slvl[0] + slvl[1] short_lvl = slvl[0] - slvl[1] if idx > 0: long_ind = (signal > long_lvl) short_ind = (signal < short_lvl) else: long_ind = (signal > long_lvl) & (signal.shift(1) <= long_lvl) short_ind = (signal < short_lvl) & (signal.shift(1) >= short_lvl) xdata = pd.concat([signal, long_ind, short_ind], axis=1, keys=[ 'signal' + str(idx), 'long_ind' + str(idx), 'short_ind' + str(idx) ]).shift(1) #print xdata xdf = xdf.join(xdata, how='left').fillna(method='ffill') xdf['close_ind'] = np.isnan(xdf['close'].shift(-1)) if close_daily: daily_end = (xdf['date'] != xdf['date'].shift(-1)) xdf['close_ind'] = xdf['close_ind'] | daily_end xdf['pos'] = 0 xdf['cost'] = 0 xdf['traded_price'] = xdf.open curr_pos = [] closed_trades = [] tradeid = 0 for idx, dd in enumerate(xdf.index): mslice = xdf.ix[dd] if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos signal_indlist = [ np.isnan(getattr(mslice, 'signal' + str(i))) for i in range(len(freq)) ] long_indlist = [ getattr(mslice, 'long_ind' + str(i)) for i in range(len(freq)) ] short_indlist = [ getattr(mslice, 'short_ind' + str(i)) for i in range(len(freq)) ] if True in signal_indlist: continue if mslice.close_ind: if pos != 0: curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 else: if (pos != 0): direction = 0 long_ind = (True in long_indlist) short_ind = (True in short_indlist) if ((pos < 0) and long_ind) or ((pos > 0) and short_ind): curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 long_ind = (False not in long_indlist) short_ind = (False not in short_indlist) if (long_ind or short_ind) and (pos == 0): target_pos = long_ind * unit - short_ind * unit new_pos = pos_class([mslice.contract], [1], target_pos, mslice.open, mslice.open, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.open + misc.sign(target_pos) * offset, dd) curr_pos.append(new_pos) #print dd, target_pos, len(curr_pos), curr_pos[0].pos, curr_pos #[getattr(mslice, 'long_ind' + str(i)) for i in range(len(freq))] pos = target_pos xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(target_pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open + misc.sign(target_pos) * offset) xdf.set_value(dd, 'pos', pos) return (xdf, closed_trades)
def dual_thrust_sim(mdf, config): ddf = config['ddf'] close_daily = config['close_daily'] offset = config['offset'] k = config['param'][0] win = config['param'][1] multiplier = config['param'][2] f = config['param'][3] ep_enabled = config['EP'] chan = config['chan'] chan_func = config['chan_func'] tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] min_rng = config['min_range'] no_trade_set = config['no_trade_set'] if win == -1: tr = pd.concat([ddf.high - ddf.low, ddf.close - ddf.close.shift(1)], join='outer', axis=1).max(axis=1).shift(1) elif win == 0: tr = pd.concat( [(pd.rolling_max(ddf.high, 2) - pd.rolling_min(ddf.close, 2)) * multiplier, (pd.rolling_max(ddf.close, 2) - pd.rolling_min(ddf.low, 2)) * multiplier, ddf.high - ddf.close, ddf.close - ddf.low], join='outer', axis=1).max(axis=1).shift(1) else: tr = pd.concat([ pd.rolling_max(ddf.high, win) - pd.rolling_min(ddf.close, win), pd.rolling_max(ddf.close, win) - pd.rolling_min(ddf.low, win) ], join='outer', axis=1).max(axis=1).shift(1) ddf['TR'] = tr ddf['MA'] = pd.rolling_mean(ddf.close, chan).shift(1) ddf['H1'] = eval(chan_func['high']['func'])( ddf, chan, **chan_func['high']['args']).shift(1) ddf['L1'] = eval(chan_func['low']['func'])( ddf, chan, **chan_func['low']['args']).shift(1) ll = mdf.shape[0] mdf['pos'] = 0 mdf['cost'] = 0 curr_pos = [] closed_trades = [] start_d = ddf.index[0] end_d = mdf.index[-1].date() prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 for dd in mdf.index: mslice = mdf.loc[dd] min_id = mslice.min_id d = mslice.date dslice = ddf.loc[d] if np.isnan(dslice.TR) or (mslice.close == 0): continue if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.set_value(dd, 'pos', pos) d_open = dslice.open if (d_open <= 0): continue rng = max(min_rng * d_open, k * dslice.TR) if (prev_d < d): d_open = mslice.open d_high = mslice.high d_low = mslice.low else: d_open = dslice.open d_high = max(d_high, mslice.high) d_low = min(d_low, mslice.low) prev_d = d buytrig = d_open + rng selltrig = d_open - rng if dslice.MA > mslice.close: buytrig += f * rng elif dslice.MA < mslice.close: selltrig -= f * rng if ep_enabled: buytrig = max(buytrig, d_high) selltrig = min(selltrig, d_low) if (min_id >= config['exit_min']): if (pos != 0) and (close_daily or (d == end_d)): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.set_value( dd, 'cost', mdf.at[dd, 'cost'] - abs(pos) * (offset + mslice.close * tcost)) pos = 0 elif min_id not in no_trade_set: if (pos != 0) and (SL > 0): curr_pos[0].trail_update(mslice.close) if curr_pos[0].check_exit(mslice.close, SL * mslice.close): curr_pos[0].close(mslice.close - offset * misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.set_value( dd, 'cost', mdf.at[dd, 'cost'] - abs(pos) * (offset + mslice.close * tcost)) pos = 0 if (mslice.high >= buytrig) and (pos <= 0): if len(curr_pos) > 0: curr_pos[0].close(mslice.close + offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.set_value( dd, 'cost', mdf.at[dd, 'cost'] - abs(pos) * (offset + mslice.close * tcost)) if mslice.high >= dslice.H1: new_pos = strat.TradePos([mslice.contract], [1], unit, mslice.close + offset, mslice.close + offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.set_value( dd, 'cost', mdf.at[dd, 'cost'] - abs(pos) * (offset + mslice.close * tcost)) elif (mslice.low <= selltrig) and (pos >= 0): if len(curr_pos) > 0: curr_pos[0].close(mslice.close - offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.set_value( dd, 'cost', mdf.at[dd, 'cost'] - abs(pos) * (offset + mslice.close * tcost)) if mslice.low <= dslice.L1: new_pos = strat.TradePos([mslice.contract], [1], -unit, mslice.close - offset, mslice.close - offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.set_value( dd, 'cost', mdf.at[dd, 'cost'] - abs(pos) * (offset + mslice.close * tcost)) mdf.set_value(dd, 'pos', pos) return (mdf, closed_trades)
def bband_chan_sim( mdf, config): start_equity = config['capital'] marginrate = config['marginrate'] offset = config['offset'] pos_class = config['pos_class'] pos_args = config['pos_args'] param = config['param'] #tick_base = config['tick_base'] close_daily = config['close_daily'] win = param[0] k = param[1] chan = param[2] if chan > 0: chan_func = config['chan_func'] tcost = config['trans_cost'] filter_func = config['filter_func']['func'] filter_args = config['filter_func']['args'] filter_param = config['filter_func']['param'] unit = config['unit'] freq = config['freq'] xdf = dh.conv_ohlc_freq(mdf, freq) xdf['boll_ma'] = dh.MA(xdf, win).shift(1) boll_std = dh.STDEV(xdf, win).shift(1) xdf['upbnd'] = xdf['boll_ma'] + boll_std * k xdf['lowbnd'] = xdf['boll_ma'] - boll_std * k if chan > 0: xdf['chan_h'] = eval(chan_func['high']['func'])(xdf, chan, **chan_func['high']['args']).shift(1) xdf['chan_l'] = eval(chan_func['low']['func'])(xdf, chan, **chan_func['low']['args']).shift(1) else: xdf['chan_h'] = 0 xdf['chan_l'] = 10000000 xdf['high_band'] = xdf[['chan_h', 'upbnd']].max(axis=1) xdf['low_band'] = xdf[['chan_l', 'lowbnd']].min(axis=1) xdf['filter'] = eval(filter_func)(xdf, filter_param[0], **filter_args) xdf['filter_ma'] = pd.rolling_mean(xdf['filter'], filter_param[1]) xdf['filter_ind'] = xdf['filter_ma'] >= filter_param[2] xdf['prev_close'] = xdf['close'].shift(1) xdf['close_ind'] = np.isnan(xdf['close'].shift(-1)) if close_daily: daily_end = (xdf['date']!=xdf['date'].shift(-1)) xdf['close_ind'] = xdf['close_ind'] | daily_end ll = xdf.shape[0] xdf['pos'] = 0 xdf['cost'] = 0 xdf['traded_price'] = xdf.open curr_pos = [] closed_trades = [] tradeid = 0 for idx, dd in enumerate(xdf.index): mslice = xdf.loc[dd] if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos xdf.set_value(dd, 'pos', pos) if np.isnan(mslice.boll_ma) or np.isnan(mslice.chan_h): continue if mslice.close_ind: if pos!=0: curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value(dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * ( mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 else: if ((mslice.open > mslice.boll_ma) and (pos<0)) or ((mslice.open < mslice.boll_ma) and (pos>0)): curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value(dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 if ((mslice.open >= mslice.high_band) or (mslice.open <= mslice.low_band)) and (pos==0): target_pos = ( mslice.open >= mslice.high_band) * unit - (mslice.open <= mslice.low_band) * unit new_pos = pos_class([mslice.contract], [1], target_pos, mslice.open, mslice.open, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.open + misc.sign(target_pos)*offset, dd) curr_pos.append(new_pos) pos = target_pos xdf.set_value(dd, 'cost', xdf.at[dd, 'cost'] - abs(target_pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open + misc.sign(target_pos)*offset) xdf.set_value(dd, 'pos', pos) return (xdf, closed_trades)
def fisher_swing_sim(df, xdf, config): marginrate = config["marginrate"] offset = config["offset"] win = config["win"] start_equity = config["capital"] tcost = config["trans_cost"] unit = config["unit"] fisher = dh.FISHER(xdf, win[0]) xdf["FISHER_I"] = fisher["FISHER_I"].shift(1) xdf = xdf.join(dh.BBANDS_STOP(xdf, win[1], 1.0).shift(1)) ha_df = dh.HEIKEN_ASHI(xdf, win[2]).shift(1) xdf["HAopen"] = ha_df["HAopen"] xdf["HAclose"] = ha_df["HAclose"] ll = df.shape[0] df["pos"] = pd.Series([0] * ll, index=df.index) df["cost"] = pd.Series([0] * ll, index=df.index) curr_pos = [] closed_trades = [] end_d = df.index[-1].date() tradeid = 0 for dd in df.index: mslice = df.ix[dd] min_id = agent.get_min_id(dd) d = dd.date() if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos df.ix[dd, "pos"] = pos if np.isnan(mslice.BBSTOP_lower) or np.isnan(mslice.FISHER_I) or np.isnan(mslice.HAclose): continue end_trading = (min_id >= config["exit_min"]) and (d == end_d) stop_loss = (pos > 0) and ((mslice.close < mslice.BBSTOP_lower) or (mslice.FISHER_I < 0)) stop_loss = stop_loss or ((pos < 0) and ((mslice.close > mslice.BBSTOP_upper) or (mslice.FISHER_I > 0))) start_long = (mslice.FISHER_I > 0) and (mslice.HAclose > mslice.HAopen) and (mslice.BBSTOP_trend > 0) start_short = (mslice.FISHER_I < 0) and (mslice.HAclose < mslice.HAopen) and (mslice.BBSTOP_trend < 0) if pos != 0: if stop_loss or end_trading: curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] df.ix[dd, "cost"] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 if (not end_trading) and (pos == 0): if start_long and start_short: print "warning: get both long and short signal, something is wrong!" print mslice continue pos = (start_long == True) * unit - (start_short == True) * unit if abs(pos) > 0: # target = (start_long == True) * mslice.close +(start_short == True) * mslice.close new_pos = strat.TradePos([mslice.contract], [1], pos, mslice.close, mslice.close) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + misc.sign(pos) * offset, dd) curr_pos.append(new_pos) df.ix[dd, "cost"] -= abs(pos) * (offset + mslice.close * tcost) df.ix[dd, "pos"] = pos (res_pnl, ts) = backtest.get_pnl_stats(df, start_equity, marginrate, "m") res_trade = backtest.get_trade_stats(closed_trades) res = dict(res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def MA_sim(mdf, config): offset = config['offset'] use_chan = config['use_chan'] pos_class = config['pos_class'] pos_args = config['pos_args'] pos_update = config.get('pos_update', False) stoploss = config.get('stoploss', 0.0) win_list = config['param'] MA_func = eval(config['MA_func']) close_daily = config['close_daily'] tcost = config['trans_cost'] unit = config['unit'] freq = config['freq'] chan_ratio = config['channel_ratio'] channel = int(chan_ratio * win_list[-1]) xdf = dh.conv_ohlc_freq(mdf, freq, extra_cols=['contract']) for idx, win in enumerate(win_list): xdf['MA' + str(idx)] = MA_func(xdf, win).shift(1) if use_chan: xdf['chan_high'] = eval(config['channel_func'][0])( xdf, channel, **config['channel_args'][0]).shift(2) xdf['chan_low'] = eval(config['channel_func'][1])( xdf, channel, **config['channel_args'][1]).shift(2) else: xdf['chan_high'] = pd.Series(index=xdf.index) xdf['chan_low'] = pd.Series(index=xdf.index) tot_MA = len(win_list) xdf['prev_close'] = xdf['close'].shift(1) xdf['close_ind'] = np.isnan(xdf['close'].shift(-1)) if close_daily: daily_end = (xdf['date'] != xdf['date'].shift(-1)) xdf['close_ind'] = xdf['close_ind'] | daily_end ll = xdf.shape[0] xdf['pos'] = 0 xdf['cost'] = 0 xdf['traded_price'] = xdf.open curr_pos = [] closed_trades = [] tradeid = 0 for idx, dd in enumerate(xdf.index): mslice = xdf.loc[dd] ma_list = [ getattr(mslice, 'MA' + str(i)) for i in range(len(win_list)) ] ma_short = ma_list[0] ma_last = ma_list[-1] if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos xdf.set_value(dd, 'pos', pos) if np.isnan(getattr(mslice, "MA" + str(tot_MA - 1))): continue if mslice.close_ind: if pos != 0: curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 else: if (((ma_short >= ma_last) or (mslice.open >= mslice.chan_high)) and (pos < 0)) or (((ma_short <= ma_last) or (mslice.open <= mslice.chan_low)) and (pos > 0)): curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 if (((ma_short >= ma_list[1]) and (ma_short >= ma_last) and ((use_chan == False) or (mslice.open>=mslice.chan_high))) or \ ((ma_short <= ma_list[1]) and (ma_short <= ma_last) and ((use_chan == False) or (mslice.open<=mslice.chan_low)))) and (pos==0): target_pos = ((ma_short >= ma_list[1]) and (ma_short >= ma_last) and ((use_chan == False) or (mslice.open>=mslice.chan_high))) * unit \ - ((ma_short <= ma_list[1]) and (ma_short <= ma_last) and ((use_chan == False) or (mslice.open<=mslice.chan_low))) * unit new_pos = pos_class([mslice.contract], [1], target_pos, mslice.open, mslice.open, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.open + misc.sign(target_pos) * offset, dd) curr_pos.append(new_pos) pos = target_pos xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(target_pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open + misc.sign(target_pos) * offset) xdf.set_value(dd, 'pos', pos) return (xdf, closed_trades)
def rbreaker_sim( mdf, config): if 'ddf' in config: ddf = config['ddf'] else: freq = config['freq'] ddf = dh.conv_ohlc_freq(mdf, freq) start_equity = config['capital'] tcost = config['trans_cost'] unit = config['unit'] pos_class = config['pos_class'] pos_args = config['pos_args'] close_daily = config['close_daily'] marginrate = config['marginrate'] offset = config['offset'] min_rng = config['min_rng'] k = config['params'] a = k[0] b = k[1] c = k[2] ddf['range'] = ddf.high - ddf.low ddf['ssetup'] = ddf.high + a*(ddf.close - ddf.low) ddf['bsetup'] = ddf.low - a*(ddf.high - ddf.close) ddf['senter'] = (1+b)*(ddf.high+ddf.close)/2.0 - b * ddf.low ddf['benter'] = (1+b)*(ddf.low+ddf.close)/2.0 - b * ddf.high ddf['bbreak'] = ddf.ssetup + c * (ddf.ssetup - ddf.bsetup) ddf['sbreak'] = ddf.bsetup - c * (ddf.ssetup - ddf.bsetup) ddf = ddf.shift(1) ll = mdf.shape[0] mdf['pos'] = pd.Series([0]*ll, index = mdf.index) mdf['cost'] = pd.Series([0]*ll, index = mdf.index) curr_pos = [] closed_trades = [] start_d = mdf.index[0].date() end_d = mdf.index[-1].date() prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 cur_high = 0 cur_low = 0 rev_flag = True dslice = None num_trades = 0 for dd in mdf.index: mslice = mdf.ix[dd] min_id = mslice.min_id d = mslice.date if (prev_d < d): num_trades = 0 cur_high = mslice.high cur_low = mslice.low if d not in ddf.index: print d, dd continue else: dslice = ddf.ix[d] if np.isnan(dslice.bbreak): continue if dslice.range < min_rng * dslice.close: rev_flag = False else: rev_flag = True prev_d = d else: cur_high = max(cur_high, mslice.high) cur_low = min(cur_low, mslice.low) if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if (min_id <= config['start_min']): continue if (min_id >= config['exit_min']): if (pos != 0) and (close_daily or (d == end_d)): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 else: if num_trades >=3: continue if ((mslice.high >= dslice.bbreak) and (pos <= 0)) or ((mslice.low <= dslice.sbreak) and (pos >= 0)): rev_flag = False if (mslice.close >= dslice.bbreak): direction = 1 else: direction = -1 if pos != 0: curr_pos[0].close(mslice.close + direction*offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) new_pos = pos_class([mslice.contract], [1], unit*direction, mslice.close, 0, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset*direction, dd) curr_pos.append(new_pos) pos = unit*direction mdf.ix[dd, 'cost'] -= abs(direction) * (offset + mslice.close*tcost) num_trades += 1 elif rev_flag and (((cur_high < dslice.bbreak) and (cur_high >= dslice.ssetup) and (mslice.close <= dslice.senter) and (pos >=0)) or \ ((cur_low > dslice.sbreak) and (cur_low <= dslice.bsetup) and (mslice.close >= dslice.benter) and (pos <=0))): if len(curr_pos) > 0: curr_pos[0].close(mslice.close-misc.sign(pos)*offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) new_pos = pos_class([mslice.contract], [1], -unit*misc.sign(pos), mslice.close, 0, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset*misc.sign(pos), dd) curr_pos.append(new_pos) pos = -unit*misc.sign(pos) mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) num_trades += 1 mdf.ix[dd, 'pos'] = pos return (mdf, closed_trades)
def _derivative(self): a = self.a x = self.x u = self.u HEB = transformation(x[9],x[10],x[11]) gb = HEB*matrix([[0.0],[0.0],[9.80665]]) Va = [x[0],x[1],x[2]] V = sqrt(Va[0]**2+Va[1]**2+Va[2]**2) alpha = arctan(Va[2] / Va[0]) beta = arcsin(Va[1] / V) T,P = atmosphere(-x[5]) R = 287.0 rho = P/R/T qbar = .5*rho*V*V qbarS = qbar*a.S a._calc(Va, x, u) CL = a.CL CD = a.CD CY = a.CY Cl = a.Cl Cm = a.Cm Cn = a.Cn thrust = a.thrust Ixx = a.Ixx Iyy = a.Iyy Izz = a.Izz Ixz = a.Ixz CX = -CD*cos(alpha) + CL*sin(alpha) CZ = -CD*sin(alpha) - CL*cos(alpha) Xb = (CX*qbarS + thrust)/a.m Yb = CY*qbarS/a.m Zb = CZ*qbarS/a.m Lb = Cl*qbarS*a.b Mb = Cm*qbarS*a.c Nb = Cn*qbarS*a.b nz = -Zb/9.80665 xd0 = Xb + float(gb[0]) + x[8]*x[1] - x[7]*x[2]; xd1 = Yb + float(gb[1]) - x[8]*x[0] + x[6]*x[2]; xd2 = Zb + float(gb[2]) + x[7]*x[0] - x[6]*x[1]; y = HEB.transpose()*matrix([[x[0]],[x[1]],[x[2]]]) xd3 = float(y[0]); xd4 = float(y[1]); xd5 = float(y[2]); xd6 = (Izz*Lb + Ixz*Nb - (Ixz*(Iyy - Ixx - Izz)*x[6]+\ (Ixz**2 + Izz*(Izz - Iyy))*x[8]) * x[7]) / (Ixx*Izz - Ixz**2); xd7 = (Mb - (Ixx - Izz) * x[6] * x[8] - Ixz * (x[6]**2 - x[8]**2)) / Iyy; xd8 = (Ixz*Lb + Ixx*Nb + (Ixz*(Iyy - Ixx - Izz)*x[8] + \ (Ixz**2 + Ixx*(Ixx - Iyy))*x[6])*x[7])/(Ixx*Izz - Ixz**2); cosPitch = cos(x[10]); if abs(cosPitch) <= 0.00001: cosPitch = 0.00001 * sign(cosPitch) tanPitch = sin(x[10]) / cosPitch; xd9 = x[6] + (sin(x[9]) * x[7] + cos(x[9]) * x[8]) * tanPitch; xd10 = cos(x[9]) * x[7] - sin(x[9]) * x[8]; xd11 = (sin(x[9]) * x[7] + cos(x[9]) * x[8]) / cosPitch; return array([xd0,xd1,xd2,xd3,xd4,xd5,xd6,xd7,xd8,xd9,xd10,xd11]);
def ttl_soup_sim(mdf, config): close_daily = config['close_daily'] marginrate = config['marginrate'] offset = config['offset'] pos_update = config['pos_update'] pos_class = config['pos_class'] pos_args = config['pos_args'] proc_func = config['proc_func'] proc_args = config['proc_args'] start_equity = config['capital'] tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] chan = config['chan'] exit_ratio = config['exit_ratio'] exit_chan = int(chan * exit_ratio) gap_win = config['gap_win'] no_trade_set = config['no_trade_set'] ll = mdf.shape[0] xdf = proc_func(mdf, **proc_args) donch_data = dh.DONCH_IDX(xdf, chan) hh_str = 'DONCH_H%s' % str(chan) hidx_str = 'DONIDX_H%s' % str(chan) ll_str = 'DONCH_L%s' % str(chan) lidx_str = 'DONIDX_L%s' % str(chan) xdf['exit_hh'] = pd.rolling_max(xdf.high, exit_chan) xdf['exit_ll'] = pd.rolling_min(xdf.low, exit_chan) xdf['ssetup'] = (xdf['close'] >= donch_data[hh_str].shift(1)) & ( donch_data[hidx_str] >= gap_win) xdf['bsetup'] = (xdf['close'] <= donch_data[ll_str].shift(1)) & ( donch_data[lidx_str] >= gap_win) atr = dh.ATR(xdf, chan) donch_data['prevhh'] = donch_data[hh_str].shift(1) donch_data['prevll'] = donch_data[ll_str].shift(1) xdata = pd.concat([ donch_data[hidx_str], donch_data[hh_str], donch_data[lidx_str], donch_data[ll_str], xdf['ssetup'], xdf['bsetup'], atr, donch_data[hh_str].shift(1), donch_data[ll_str].shift(1) ], axis=1, keys=[ 'hh_idx', 'hh', 'll_idx', 'll', 'ssetup', 'bsetup', 'ATR', 'prev_hh', 'prev_ll' ]).fillna(0) xdata = xdata.shift(1) mdf = mdf.join(xdata, how='left').fillna(method='ffill') mdf['pos'] = pd.Series([0] * ll, index=mdf.index) mdf['cost'] = pd.Series([0] * ll, index=mdf.index) curr_pos = [] closed_trades = [] end_d = mdf.index[-1].date #prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 for idx, dd in enumerate(mdf.index): mslice = mdf.ix[dd] min_id = mslice.min_id min_cnt = (min_id - 300) / 100 * 60 + min_id % 100 + 1 if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if (mslice.prev_hh == 0): continue if (min_id >= config['exit_min']) and (close_daily or (mslice.datetime.date == end_d)): if (pos != 0): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 elif min_id not in no_trade_set: if (pos != 0): exit_flag = False if ((pos > 0) and (mslice.close <= mslice.exit_ll)) or ( (pos < 0) and (mslice.close >= mslice.exit_hh)): exit_flag = True if exit_flag or curr_pos[0].check_exit(mslice.close, 0): curr_pos[0].close(mslice.close - offset * misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 elif pos_update and (min_cnt % config['pos_freq'] == 0): curr_pos[0].update_price(mslice.close) if mslice.bsetup and (pos == 0) and (mslice.close >= mslice.prev_ll): new_pos = pos_class([mslice.contract], [1], unit, mslice.close + offset, mslice.low, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) elif mslice.ssetup and (pos == 0) and mslice.close <= mslice.prev_hh: new_pos = pos_class([mslice.contract], [1], -unit, mslice.close - offset, mslice.high, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) mdf.ix[dd, 'pos'] = pos (res_pnl, ts) = backtest.get_pnl_stats(mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats(closed_trades) res = dict(res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def aberration_sim(mdf, config): start_equity = config['capital'] marginrate = config['marginrate'] offset = config['offset'] pos_class = config['pos_class'] pos_args = config['pos_args'] param = config['param'] tick_base = config['tick_base'] close_daily = config['close_daily'] win = param[0] k = param[1] chan = param[2] if chan > 0: chan_func = config['chan_func'] tcost = config['trans_cost'] unit = config['unit'] freq = config['freq'] #freq_min = int(freq[:-3]) mode = config.get('mode', 'close') xdf = dh.conv_ohlc_freq(mdf, freq) boll_ma = dh.MA(xdf, win).shift(1) boll_std = dh.STDDEV(xdf, win).shift(1) upbnd = np.ceil((boll_ma + boll_std * k) / tick_base) * tick_base lowbnd = np.floor((boll_ma - boll_std * k) / tick_base) * tick_base boll_ma = np.floor(boll_ma / tick_base + 0.5) * tick_base xdata = [boll_ma, boll_std, upbnd, lowbnd, xdf['min_id']] xkeys = ['ma', 'stdev', 'upbnd', 'lowbnd', 'xmin_id'] if chan > 0: chan_h = eval(chan_func['high']['func'])(xdf, chan, **chan_func['high']['args']) chan_l = eval(chan_func['low']['func'])(xdf, chan, **chan_func['low']['args']) xdata = xdata + [chan_h, chan_l] xkeys = xkeys + ['chan_h', 'chan_l'] xdf = pd.concat(xdata, axis=1, keys=xkeys).fillna(0) mdf = mdf.join(xdf, how='left').fillna(method='ffill') mdf['is_new'] = (mdf['xmin_id'].shift(1) != mdf['xmin_id']) ll = mdf.shape[0] mdf['pos'] = pd.Series([0] * ll, index=mdf.index) mdf['cost'] = pd.Series([0] * ll, index=mdf.index) curr_pos = [] closed_trades = [] start_d = mdf.date[0] end_d = mdf.date[-1] tradeid = 0 for idx, dd in enumerate(mdf.index): mslice = mdf.ix[dd] min_id = mslice.min_id d = mslice.date if len(curr_pos) == 0: pos = 0 start_pos = 0 else: pos = curr_pos[0].pos start_pos = pos mdf.ix[dd, 'pos'] = pos if mslice.ma == 0: continue upbnd = mslice.upbnd lowbnd = mslice.lowbnd if chan > 0: if mslice.chan_h == 0: continue else: upbnd = max(mslice.chan_h, upbnd) lowbnd = min(mslice.chan_l, lowbnd) if min_id >= config['exit_min']: if (pos != 0) and ((d == end_d) or close_daily): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 else: if mode == 'close': high_trig = mslice.close low_trig = mslice.close trade_price = mslice.close else: high_trig = mslice.high low_trig = mslice.low trade_price = mslice.open if ((high_trig >= mslice.ma) and (pos < 0)) or ((low_trig <= mslice.ma) and (pos > 0)): if pos < 0: exec_price = max(trade_price, mslice.ma) else: exec_price = min(trade_price, mslice.ma) curr_pos[0].close(exec_price - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + exec_price * tcost) pos = 0 if ((high_trig > upbnd) and (pos <= 0)) or ((low_trig < lowbnd) and (pos >= 0)): target_pos = (high_trig > upbnd) * unit - (low_trig < lowbnd) * unit if target_pos == 0: print "the min bar hit both up and low bounds, need to think about how to handle it", start_pos, mslice if mslice.close > mslice.ma: target_pos = (high_trig > upbnd) * unit target = max(trade_price, upbnd) else: trade_pos = -(low_trig < lowbnd) * unit target = min(trade_price, lowbnd) else: target = (high_trig > upbnd) * max(trade_price, upbnd) + ( low_trig < lowbnd) * min(trade_price, lowbnd) new_pos = pos_class([mslice.contract], [1], target_pos, target, target, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(target + misc.sign(target_pos) * offset, dd) curr_pos.append(new_pos) pos = target_pos mdf.ix[dd, 'cost'] -= abs(target_pos) * (offset + target * tcost) mdf.ix[dd, 'pos'] = pos return (mdf, closed_trades)
def bband_chan_sim(mdf, config): offset = config['offset'] pos_class = config['pos_class'] pos_args = config['pos_args'] pos_update = config.get('pos_update', False) stoploss = config.get('stoploss', 0.0) param = config['param'] bar_func = eval(config['bar_conv_func']) std_func = eval(config['std_func']) #tick_base = config['tick_base'] close_daily = config['close_daily'] win = param[0] k = param[1] chan = param[2] stop_ratio = config.get('exit_stop', 0.0) k_e = k * stop_ratio if chan > 0: chan_func = config['chan_func'] tcost = config['trans_cost'] unit = config['unit'] freq = config['freq'] xdf = dh.conv_ohlc_freq(mdf, freq, extra_cols=['contract'], bar_func=bar_func) xdf['boll_ma'] = dh.MA(xdf, win).shift(1) xdf['boll_std'] = std_func(xdf, win).shift(1) xdf['upbnd'] = xdf['boll_ma'] + xdf['boll_std'] * k xdf['lowbnd'] = xdf['boll_ma'] - xdf['boll_std'] * k xdf['up_exit'] = xdf['boll_ma'] + xdf['boll_std'] * k_e xdf['dn_exit'] = xdf['boll_ma'] - xdf['boll_std'] * k_e if chan > 0: xdf['chan_h'] = eval(chan_func['high']['func'])( xdf, chan, **chan_func['high']['args']).shift(2) xdf['chan_l'] = eval(chan_func['low']['func'])( xdf, chan, **chan_func['low']['args']).shift(2) else: xdf['chan_h'] = 0 xdf['chan_l'] = 10000000 xdf['high_band'] = xdf[['chan_h', 'upbnd']].max(axis=1) xdf['low_band'] = xdf[['chan_l', 'lowbnd']].min(axis=1) xdf['prev_close'] = xdf['close'].shift(1) xdf['close_ind'] = np.isnan(xdf['close'].shift(-1)) if close_daily: daily_end = (xdf['date'] != xdf['date'].shift(-1)) xdf['close_ind'] = xdf['close_ind'] | daily_end ll = xdf.shape[0] xdf['pos'] = 0 xdf['cost'] = 0 xdf['traded_price'] = xdf.open curr_pos = [] closed_trades = [] tradeid = 0 for idx, dd in enumerate(xdf.index): mslice = xdf.loc[dd] if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos xdf.set_value(dd, 'pos', pos) if np.isnan(mslice.boll_ma) or np.isnan(mslice.chan_h): continue if mslice.close_ind: if pos != 0: curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 else: if ((mslice.open > mslice.up_exit) and (pos < 0)) or ((mslice.open < mslice.dn_exit) and (pos > 0)): curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 if ((mslice.open >= mslice.high_band) or (mslice.open <= mslice.low_band)) and (pos == 0): target_pos = (mslice.open >= mslice.high_band) * unit - ( mslice.open <= mslice.low_band) * unit new_pos = pos_class([mslice.contract], [1], target_pos, mslice.open, mslice.open, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.open + misc.sign(target_pos) * offset, dd) curr_pos.append(new_pos) pos = target_pos xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(target_pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open + misc.sign(target_pos) * offset) if pos_update and pos != 0: if curr_pos[0].check_exit(mslice.open, stoploss * mslice.boll_std): curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 else: curr_pos[0].update_bar(mslice) xdf.set_value(dd, 'pos', pos) return (xdf, closed_trades)
def dual_thrust_sim( mdf, config): close_daily = config['close_daily'] marginrate = config['marginrate'] offset = config['offset'] k = config['param'][0] win = config['param'][1] multiplier = config['param'][2] f = config['param'][3] pos_update = config['pos_update'] pos_class = config['pos_class'] pos_args = config['pos_args'] proc_func = config['proc_func'] proc_args = config['proc_args'] start_equity = config['capital'] chan_func = config['chan_func'] chan_high = eval(chan_func['high']['func']) chan_low = eval(chan_func['low']['func']) tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] min_rng = config['min_range'] chan = config['chan'] use_chan = config['use_chan'] no_trade_set = config['no_trade_set'] ll = mdf.shape[0] xdf = proc_func(mdf, **proc_args) if win == -1: tr= pd.concat([xdf.high - xdf.low, abs(xdf.close - xdf.close.shift(1))], join='outer', axis=1).max(axis=1) elif win == 0: tr = pd.concat([(pd.rolling_max(xdf.high, 2) - pd.rolling_min(xdf.close, 2))*multiplier, (pd.rolling_max(xdf.close, 2) - pd.rolling_min(xdf.low, 2))*multiplier, xdf.high - xdf.close, xdf.close - xdf.low], join='outer', axis=1).max(axis=1) else: tr= pd.concat([pd.rolling_max(xdf.high, win) - pd.rolling_min(xdf.close, win), pd.rolling_max(xdf.close, win) - pd.rolling_min(xdf.low, win)], join='outer', axis=1).max(axis=1) xdf['TR'] = tr xdf['chan_h'] = chan_high(xdf, chan, **chan_func['high']['args']) xdf['chan_l'] = chan_low(xdf, chan, **chan_func['low']['args']) xdf['MA'] = pd.rolling_mean(xdf.close, chan) xdata = pd.concat([xdf['TR'].shift(1), xdf['MA'].shift(1), xdf['chan_h'].shift(1), xdf['chan_l'].shift(1), xdf['open']], axis=1, keys=['TR','MA', 'chanH', 'chanL', 'dopen']).fillna(0) mdf = mdf.join(xdata, how = 'left').fillna(method='ffill') mdf['pos'] = pd.Series([0]*ll, index = mdf.index) mdf['cost'] = pd.Series([0]*ll, index = mdf.index) curr_pos = [] closed_trades = [] end_d = mdf.index[-1].date #prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 for dd in mdf.index: mslice = mdf.ix[dd] min_id = mslice.min_id min_cnt = (min_id-300)/100 * 60 + min_id % 100 + 1 if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if (mslice.TR == 0) or (mslice.MA == 0): continue d_open = mslice.dopen rng = max(min_rng * d_open, k * mslice.TR) if (d_open <= 0): continue buytrig = d_open + rng selltrig = d_open - rng if 'reset_margin' in pos_args: pos_args['reset_margin'] = mslice.TR * SL if mslice.MA > mslice.close: buytrig += f * rng elif mslice.MA < mslice.close: selltrig -= f * rng if (min_id >= config['exit_min']) and (close_daily or (mslice.date == end_d)): if (pos != 0): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 elif min_id not in no_trade_set: if (pos!=0) and pos_update: curr_pos[0].update_price(mslice.close) if (curr_pos[0].check_exit( mslice.close, SL * mslice.close )): curr_pos[0].close(mslice.close-offset*misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 if (mslice.high >= buytrig) and (pos <=0 ): if len(curr_pos) > 0: curr_pos[0].close(mslice.close+offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) if (use_chan == False) or (mslice.high > mslice.chanH): new_pos = pos_class([mslice.contract], [1], unit, mslice.close + offset, mslice.close + offset, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) elif (mslice.low <= selltrig) and (pos >=0 ): if len(curr_pos) > 0: curr_pos[0].close(mslice.close-offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) if (use_chan == False) or (mslice.low < mslice.chanL): new_pos = pos_class([mslice.contract], [1], -unit, mslice.close - offset, mslice.close - offset, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) mdf.ix[dd, 'pos'] = pos (res_pnl, ts) = backtest.get_pnl_stats( mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats( closed_trades ) res = dict( res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def ttl_soup_sim( mdf, config): close_daily = config['close_daily'] marginrate = config['marginrate'] offset = config['offset'] pos_update = config['pos_update'] pos_class = config['pos_class'] pos_args = config['pos_args'] proc_func = config['proc_func'] proc_args = config['proc_args'] start_equity = config['capital'] tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] chan = config['chan'] exit_ratio = config['exit_ratio'] exit_chan = int(chan * exit_ratio) gap_win = config['gap_win'] no_trade_set = config['no_trade_set'] ll = mdf.shape[0] xdf = proc_func(mdf, **proc_args) donch_data = dh.DONCH_IDX(xdf, chan) hh_str = 'DONCH_H%s' % str(chan) hidx_str = 'DONIDX_H%s' % str(chan) ll_str = 'DONCH_L%s' % str(chan) lidx_str = 'DONIDX_L%s' % str(chan) xdf['exit_hh'] = pd.rolling_max(xdf.high, exit_chan) xdf['exit_ll'] = pd.rolling_min(xdf.low, exit_chan) xdf['ssetup'] = (xdf['close'] >= donch_data[hh_str].shift(1)) & (donch_data[hidx_str]>=gap_win) xdf['bsetup'] = (xdf['close'] <= donch_data[ll_str].shift(1)) & (donch_data[lidx_str]>=gap_win) atr = dh.ATR(xdf, chan) donch_data['prevhh'] = donch_data[hh_str].shift(1) donch_data['prevll'] = donch_data[ll_str].shift(1) xdata = pd.concat([donch_data[hidx_str], donch_data[hh_str], donch_data[lidx_str], donch_data[ll_str], xdf['ssetup'], xdf['bsetup'],atr, donch_data[hh_str].shift(1), donch_data[ll_str].shift(1)], axis=1, keys=['hh_idx', 'hh', 'll_idx', 'll', 'ssetup', 'bsetup', 'ATR', 'prev_hh', 'prev_ll']).fillna(0) xdata = xdata.shift(1) mdf = mdf.join(xdata, how = 'left').fillna(method='ffill') mdf['pos'] = pd.Series([0]*ll, index = mdf.index) mdf['cost'] = pd.Series([0]*ll, index = mdf.index) curr_pos = [] closed_trades = [] end_d = mdf.index[-1].date #prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 for idx, dd in enumerate(mdf.index): mslice = mdf.ix[dd] min_id = mslice.min_id min_cnt = (min_id-300)/100 * 60 + min_id % 100 + 1 if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if (mslice.prev_hh == 0): continue if (min_id >= config['exit_min']) and (close_daily or (mslice.datetime.date == end_d)): if (pos != 0): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 elif min_id not in no_trade_set: if (pos!=0): exit_flag = False if ((pos > 0) and (mslice.close <= mslice.exit_ll)) or ((pos < 0) and (mslice.close >= mslice.exit_hh)): exit_flag = True if exit_flag or curr_pos[0].check_exit( mslice.close, 0): curr_pos[0].close(mslice.close-offset*misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 elif pos_update and (min_cnt % config['pos_freq'] == 0): curr_pos[0].update_price(mslice.close) if mslice.bsetup and (pos == 0) and (mslice.close>=mslice.prev_ll): new_pos = pos_class([mslice.contract], [1], unit, mslice.close + offset, mslice.low, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) elif mslice.ssetup and (pos == 0) and mslice.close<=mslice.prev_hh: new_pos = pos_class([mslice.contract], [1], -unit, mslice.close - offset, mslice.high, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) mdf.ix[dd, 'pos'] = pos (res_pnl, ts) = backtest.get_pnl_stats( mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats( closed_trades ) res = dict( res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def dual_thrust_sim(ddf, mdf, config): close_daily = config["close_daily"] marginrate = config["marginrate"] offset = config["offset"] k = config["k"] start_equity = config["capital"] win = config["win"] multiplier = config["m"] tcost = config["trans_cost"] unit = config["unit"] SL = config["stoploss"] min_rng = config["min_range"] no_trade_set = config["no_trade_set"] if win == -1: tr = pd.concat([ddf.high - ddf.low, ddf.close - ddf.close.shift(1)], join="outer", axis=1).max(axis=1).shift(1) elif win == 0: tr = ( pd.concat( [ (pd.rolling_max(ddf.high, 2) - pd.rolling_min(ddf.close, 2)) * multiplier, (pd.rolling_max(ddf.close, 2) - pd.rolling_min(ddf.low, 2)) * multiplier, ddf.high - ddf.close, ddf.close - ddf.low, ], join="outer", axis=1, ) .max(axis=1) .shift(1) ) else: tr = ( pd.concat( [ pd.rolling_max(ddf.high, win) - pd.rolling_min(ddf.close, win), pd.rolling_max(ddf.close, win) - pd.rolling_min(ddf.low, win), ], join="outer", axis=1, ) .max(axis=1) .shift(1) ) ddf["TR"] = tr # ddf['prev_high'] = ddf.high.shift(1) # ddf['prev_low'] = ddf.low.shift(1) ll = mdf.shape[0] mdf["pos"] = pd.Series([0] * ll, index=mdf.index) mdf["cost"] = pd.Series([0] * ll, index=mdf.index) curr_pos = [] closed_trades = [] start_d = ddf.index[0] end_d = mdf.index[-1].date() prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 for dd in mdf.index: mslice = mdf.ix[dd] min_id = agent.get_min_id(dd) d = dd.date() dslice = ddf.ix[d] if min_id in no_trade_set or np.isnan(dslice.TR): continue if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, "pos"] = pos d_open = dslice.open if prev_d < d: d_open = mslice.open # d_high = mslice.high # d_low = mslice.low else: d_open = dslice.open # d_high = max(d_high, mslice.high) # d_low = min(d_low, mslice.low) if d_open <= 0: continue prev_d = d buytrig = d_open + max(min_rng * d_open, dslice.TR * k) selltrig = d_open - max(min_rng * d_open, dslice.TR * k) # d_high = max(d_high, dslice.prev_high) # d_low = min(d_low, dslice.prev_low) if min_id >= config["exit_min"]: if (pos != 0) and (close_daily or (d == end_d)): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, "cost"] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 else: if (pos != 0) and (SL > 0): curr_pos[0].trail_update(mslice.close) if curr_pos[0].trail_check(mslice.close, SL * mslice.close): curr_pos[0].close(mslice.close - offset * misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, "cost"] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 if (mslice.high >= buytrig) and (pos <= 0): if len(curr_pos) > 0: curr_pos[0].close(mslice.close + offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, "cost"] -= abs(pos) * (offset + mslice.close * tcost) new_pos = strat.TradePos([mslice.contract], [1], unit, mslice.close + offset, mslice.close + offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, "cost"] -= abs(pos) * (offset + mslice.close * tcost) elif (mslice.low <= selltrig) and (pos >= 0): if len(curr_pos) > 0: curr_pos[0].close(mslice.close - offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, "cost"] -= abs(pos) * (offset + mslice.close * tcost) new_pos = strat.TradePos([mslice.contract], [1], -unit, mslice.close - offset, mslice.close - offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, "cost"] -= abs(pos) * (offset + mslice.close * tcost) mdf.ix[dd, "pos"] = pos (res_pnl, ts) = backtest.get_pnl_stats(mdf, start_equity, marginrate, "m") res_trade = backtest.get_trade_stats(closed_trades) res = dict(res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def dual_thrust_sim(mdf, config): (pos_class, pos_args) = config['pos_param'] update_freq = config.get('update_freq', 0) ddf = config['ddf'] close_daily = config['close_daily'] offset = config['offset'] k = config['param'][0] win = config['param'][1] multiplier = config['param'][2] f = config['param'][3] chan = config['chan'] chan_func = config['chan_func'] use_chan = config['use_chan'] tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] min_rng = config['min_range'] if win == -1: tr = pd.concat([ddf.high - ddf.low, ddf.close - ddf.close.shift(1)], join='outer', axis=1).max(axis=1).shift(1) elif win == 0: tr = pd.concat( [(pd.rolling_max(ddf.high, 2) - pd.rolling_min(ddf.close, 2)) * multiplier, (pd.rolling_max(ddf.close, 2) - pd.rolling_min(ddf.low, 2)) * multiplier, ddf.high - ddf.close, ddf.close - ddf.low], join='outer', axis=1).max(axis=1).shift(1) else: tr = pd.concat([ pd.rolling_max(ddf.high, win) - pd.rolling_min(ddf.close, win), pd.rolling_max(ddf.close, win) - pd.rolling_min(ddf.low, win) ], join='outer', axis=1).max(axis=1).shift(1) ddf['TR'] = tr ddf['ATR'] = dh.ATR(ddf, win) if use_chan: ddf['CH_H'] = eval(chan_func['high']['func'])( ddf, chan, **chan_func['high']['args']).shift(1) ddf['CH_L'] = eval(chan_func['low']['func'])( ddf, chan, **chan_func['low']['args']).shift(1) if update_freq > 1: xdf = dh.conv_ohlc_freq(mdf, str(update_freq) + 'Min') else: xdf = mdf xdata = pd.concat([xdf['open'], xdf['high'], xdf['low'], xdf['close']], axis=1, keys=['xopen', 'xhigh', 'xlow', 'xclose']) mdf = mdf.join(xdata, how='left').fillna(method='ffill') ll = mdf.shape[0] mdf['pos'] = 0 mdf['cost'] = 0 start_d = ddf.index[0] end_d = mdf.index[-1].date() prev_d = start_d - datetime.timedelta(days=1) curr_pos = [] closed_trades = [] tradeid = 0 for idx, dd in enumerate(mdf.index): mslice = mdf.ix[dd] min_id = mslice.min_id d = mslice.date dslice = ddf.ix[d] if np.isnan(dslice.TR) or (mslice.close == 0): continue if use_chan and np.isnan(dslice.CH_H): continue if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos d_open = dslice.open if (d_open <= 0): continue rng = max(min_rng * d_open, k * dslice.TR) if (prev_d < d): d_open = mslice.open else: d_open = dslice.open prev_d = d buytrig = d_open + rng selltrig = d_open - rng stoploss = SL * dslice.ATR tmp_args = pos_args.copy() if 'reset_margin' in pos_args: tmp_args['reset_margin'] = dslice.ATR * pos_args['reset_margin'] stoploss = tmp_args['reset_margin'] * stoploss close_pos = False if pos != 0: if ((pos > 0) and (mslice.high < buytrig)) or ((pos < 0) and (mslice.low > selltrig)): close_pos = curr_pos[0].check_exit(mslice.close, stoploss) if (close_pos == False) and (update_freq > 0) and ( (mslice.min_id + 1) % update_freq == 0): xslice = conv_xslice(mslice) curr_pos[0].update_bar(xslice) if close_pos or ((mslice.min_id >= config['exit_min']) and (close_daily or (d == end_d))): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 if mslice.min_id < config['exit_min']: if (mslice.high >= buytrig) and (pos <= 0): if len(curr_pos) > 0: curr_pos[0].close(mslice.close + offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) if (use_chan == False) or (use_chan and (mslice.high >= dslice.CH_H)): new_pos = eval(pos_class)([mslice.contract], [1], unit, mslice.close + offset, mslice.close + offset, **tmp_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) elif (mslice.low <= selltrig) and (pos >= 0): if len(curr_pos) > 0: curr_pos[0].close(mslice.close - offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) if (use_chan == False) or (use_chan and (mslice.low <= dslice.CH_L)): new_pos = eval(pos_class)([mslice.contract], [1], -unit, mslice.close - offset, mslice.close - offset, **tmp_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) mdf.ix[dd, 'pos'] = pos return (mdf, closed_trades)
def layer_sim( mdf, config): tcost = config['trans_cost'] unit = config['unit'] offset = config['offset'] pos_class = config['pos_class'] pos_args = config['pos_args'] freq = config['freq'] signal_func = config['signal_func'] signal_args = config['signal_args'] signal_level = config['signal_level'] close_daily = config['close_daily'] for idx, (f, sfunc, sargs, slvl) in enumerate(zip(freq, signal_func, signal_args, signal_level)): df = dh.conv_ohlc_freq(mdf, f, extra_cols=['contract']) if idx == 0: xdf = df farg = tuple(sargs) func = eval(sfunc[0]) sigout = func(df, *farg) sig_field = sfunc[1] % farg signal = sigout[sig_field] long_lvl = slvl[0] + slvl[1] short_lvl = slvl[0] - slvl[1] if idx > 0: long_ind = (signal > long_lvl) short_ind = (signal < short_lvl) else: long_ind = (signal > long_lvl) & (signal.shift(1) <= long_lvl) short_ind = (signal < short_lvl) & (signal.shift(1) >= short_lvl) xdata = pd.concat([signal, long_ind, short_ind], axis = 1, keys = ['signal'+str(idx), 'long_ind'+str(idx), 'short_ind'+str(idx)]).shift(1) #print xdata xdf = xdf.join(xdata, how = 'left').fillna(method='ffill') xdf['close_ind'] = np.isnan(xdf['close'].shift(-1)) if close_daily: daily_end = (xdf['date']!=xdf['date'].shift(-1)) xdf['close_ind'] = xdf['close_ind'] | daily_end xdf['pos'] = 0 xdf['cost'] = 0 xdf['traded_price'] = xdf.open curr_pos = [] closed_trades = [] tradeid = 0 for idx, dd in enumerate(xdf.index): mslice = xdf.ix[dd] if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos signal_indlist = [np.isnan(getattr(mslice, 'signal' + str(i))) for i in range(len(freq))] long_indlist = [getattr(mslice, 'long_ind' + str(i)) for i in range(len(freq))] short_indlist = [ getattr(mslice, 'short_ind'+str(i)) for i in range(len(freq))] if True in signal_indlist: continue if mslice.close_ind: if pos!=0: curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value(dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * ( mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 else: if (pos !=0): direction = 0 long_ind = (True in long_indlist) short_ind = (True in short_indlist) if ((pos < 0) and long_ind) or ((pos > 0) and short_ind): curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value(dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 long_ind = (False not in long_indlist) short_ind = (False not in short_indlist) if (long_ind or short_ind) and (pos == 0): target_pos = long_ind * unit - short_ind * unit new_pos = pos_class([mslice.contract], [1], target_pos, mslice.open, mslice.open, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.open + misc.sign(target_pos)*offset, dd) curr_pos.append(new_pos) #print dd, target_pos, len(curr_pos), curr_pos[0].pos, curr_pos #[getattr(mslice, 'long_ind' + str(i)) for i in range(len(freq))] pos = target_pos xdf.set_value(dd, 'cost', xdf.at[dd, 'cost'] - abs(target_pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open + misc.sign(target_pos)*offset) xdf.set_value(dd, 'pos', pos) return (xdf, closed_trades)
def r_breaker_sim(ddf, mdf, config): marginrate = config['marginrate'] offset = config['offset'] k = config['k'] a = k[0] b = k[1] c = k[2] start_equity = config['capital'] tcost = config['trans_cost'] unit = config['unit'] close_daily = config['close_daily'] ddf['range'] = (ddf.high - ddf.low).shift(1) ddf['ssetup'] = (ddf.high + a * (ddf.close - ddf.low)).shift(1) ddf['bsetup'] = (ddf.low - a * (ddf.high - ddf.close)).shift(1) ddf['senter'] = ((1 + b) * (ddf.high + ddf.close) / 2.0 - b * ddf.low).shift(1) ddf['benter'] = ((1 + b) * (ddf.low + ddf.close) / 2.0 - b * ddf.high).shift(1) ddf['bbreak'] = ddf.ssetup + c * (ddf.ssetup - ddf.bsetup) ddf['sbreak'] = ddf.bsetup - c * (ddf.ssetup - ddf.bsetup) ll = mdf.shape[0] mdf['pos'] = pd.Series([0] * ll, index=mdf.index) mdf['cost'] = pd.Series([0] * ll, index=mdf.index) curr_pos = [] closed_trades = [] start_d = ddf.index[0] end_d = mdf.index[-1].date() prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 cur_high = 0 cur_low = 0 for dd in mdf.index: mslice = mdf.ix[dd] min_id = agent.get_min_id(dd) d = dd.date() dslice = ddf.ix[d] if np.isnan(dslice.bbreak): continue if (prev_d < d): num_trades = 0 cur_high = mslice.high cur_low = mslice.low else: cur_high = max([cur_high, mslice.high]) cur_low = min([cur_low, mslice.low]) prev_d = d if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if (min_id >= config['exit_min']): if (pos != 0) and (close_daily or (d == end_d)): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 elif (min_id <= config['start_min']): continue else: if num_trades >= 2: continue if ((cur_high < dslice.bbreak) and (cur_high >= dslice.ssetup) and (mslice.close < dslice.senter) and (pos >=0)) or \ ((cur_low > dslice.sbreak) and (cur_low <= dslice.bsetup) and (mslice.close > dslice.benter) and (pos <=0)): if len(curr_pos) > 0: curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) new_pos = strat.TradePos([mslice.contract], [1], -unit * misc.sign(pos), mslice.close, 0) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset * misc.sign(pos), dd) curr_pos.append(new_pos) pos = -unit * misc.sign(pos) mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) num_trades += 1 elif ((mslice.close >= dslice.bbreak) or (mslice.close <= dslice.sbreak)) and (pos == 0): if (mslice.close >= dslice.bbreak): direction = 1 else: direction = -1 new_pos = strat.TradePos([mslice.contract], [1], unit * direction, mslice.close, 0) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset * misc.sign(direction), dd) curr_pos.append(new_pos) pos = unit * direction mdf.ix[dd, 'cost'] -= abs(direction) * (offset + mslice.close * tcost) num_trades += 1 mdf.ix[dd, 'pos'] = pos (res_pnl, ts) = backtest.get_pnl_stats(mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats(closed_trades) res = dict(res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def fisher_swing_sim(mdf, config): pos_class = config['pos_class'] pos_args = config['pos_args'] pos_update = config.get('pos_update', False) offset = config['offset'] close_daily = config['close_daily'] tcost = config['trans_cost'] unit = config['unit'] freq = config['freq'] param = config['param'] fisher_n = param[0] bband_n = param[1] bband_std = param[2] heiken_n = param[3] xdf = dh.conv_ohlc_freq(mdf, freq, extra_cols=['contract']) fisher = dh.FISHER(xdf, win[0]) xdf['FISHER_I'] = fisher['FISHER_I'].shift(1) bbands_stop = dh.BBANDS_STOP(xdf, win[1], 1.0) xdf['BBSTOP_upper'] = bbands_stop['BBSTOP_upper'].shift(1) xdf['BBSTOP_lower'] = bbands_stop['BBSTOP_lower'].shift(1) xdf['BBSTOP_trend'] = bbands_stop['BBSTOP_trend'].shift(1) ha_df = dh.HEIKEN_ASHI(xdf, win[2]).shift(1) xdf['HAopen'] = ha_df['HAopen'].shift(1) xdf['HAclose'] = ha_df['HAclose'].shift(1) xdf['prev_close'] = xdf['close'].shift(1) xdf['close_ind'] = np.isnan(xdf['close'].shift(-1)) if close_daily: daily_end = (xdf['date'] != xdf['date'].shift(-1)) xdf['close_ind'] = xdf['close_ind'] | daily_end xdf['pos'] = 0 xdf['cost'] = 0 xdf['traded_price'] = xdf.open curr_pos = [] closed_trades = [] tradeid = 0 for idx, dd in enumerate(xdf.index): mslice = xdf.loc[dd] min_id = mslice.min_id d = dd.date() if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos xdf.set_value(dd, 'pos', pos) if np.isnan(mslice.BBSTOP_lower) or np.isnan( mslice.FISHER_I) or np.isnan(mslice.HAclose): continue stop_loss = (pos > 0) and ((mslice.open < mslice.BBSTOP_lower) or (mslice.FISHER_I < 0)) stop_loss = stop_loss or ((pos < 0) and ((mslice.open > mslice.BBSTOP_upper) or (mslice.FISHER_I > 0))) start_long = (mslice.FISHER_I > 0) and ( mslice.HAclose > mslice.HAopen) and (mslice.BBSTOP_trend > 0) start_short = (mslice.FISHER_I < 0) and ( mslice.HAclose < mslice.HAopen) and (mslice.BBSTOP_trend < 0) if mslice.close_ind: if pos != 0: curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 else: if stop_loss: curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 pos = (start_long == True) * unit - (start_short == True) * unit if abs(pos) > 0: #target = (start_long == True) * mslice.close +(start_short == True) * mslice.close new_pos = pos_class([mslice.contract], [1], pos, mslice.open, mslice.open, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.open + misc.sign(pos) * offset, dd) curr_pos.append(new_pos) xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open + misc.sign(pos) * offset) xdf.ix[dd, 'pos'] = pos return (xdf, closed_trades)
def run_sim(config): mdf = config['mdf'] close_daily = config['close_daily'] offset = config['offset'] k = config['param'][0] win = config['param'][1] multiplier = config['param'][2] f = config['param'][3] price_mode = config.get('price_mode', 'TP') pos_update = config['pos_update'] pos_class = config['pos_class'] pos_args = config['pos_args'] proc_func = config['proc_func'] proc_args = config['proc_args'] chan_func = config['chan_func'] chan_high = eval(chan_func['high']['func']) chan_low = eval(chan_func['low']['func']) tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] min_rng = config['min_range'] chan = config['chan'] use_chan = config['use_chan'] no_trade_set = config['no_trade_set'] pos_freq = config.get('pos_freq', 1) xdf = proc_func(mdf, **proc_args) if win == -1: tr = pd.concat( [xdf.high - xdf.low, abs(xdf.close - xdf.close.shift(1))], join='outer', axis=1).max(axis=1) elif win == 0: tr = pd.concat( [(pd.rolling_max(xdf.high, 2) - pd.rolling_min(xdf.close, 2)) * multiplier, (pd.rolling_max(xdf.close, 2) - pd.rolling_min(xdf.low, 2)) * multiplier, xdf.high - xdf.close, xdf.close - xdf.low], join='outer', axis=1).max(axis=1) else: tr = pd.concat([ pd.rolling_max(xdf.high, win) - pd.rolling_min(xdf.close, win), pd.rolling_max(xdf.close, win) - pd.rolling_min(xdf.low, win) ], join='outer', axis=1).max(axis=1) xdf['TR'] = tr xdf['chan_h'] = chan_high(xdf['high'], chan, **chan_func['high']['args']) xdf['chan_l'] = chan_low(xdf['low'], chan, **chan_func['low']['args']) xdata = pd.concat([ xdf['TR'].shift(1), xdf['MA'].shift(1), xdf['chan_h'].shift(1), xdf['chan_l'].shift(1), xdf['open'] ], axis=1, keys=['tr', 'ma', 'chanh', 'chanl', 'dopen']).fillna(0) df = mdf.join(xdata, how='left').fillna(method='ffill') df['pos'] = 0 df['cost'] = 0 df['traded_price'] = df['open'] sim_data = dh.DynamicRecArray(dataframe=df) nlen = len(sim_data) positions = [] closed_trades = [] tradeid = 0 curr_date = None buytrig = selltrig = 0.0 for n in range(nlen - 3): cost = 0 pos = sim_data['pos'][n] if sim_data['ma'][n] == 0 or sim_data['chan_h'][n] == 0 or sim_data[ 'dopen'][n] == 0: continue if curr_date != sim_data['date'][n]: curr_date = sim_data['date'][n] dopen = sim_data['dopen'][n] rng = max(min_rng * dopen, k * sim_data['tr'][n]) buytrig = dopen + rng selltrig = dopen - rng if sim_data['ma'][n] > dopen: buytrig += f * rng else: selltrig -= f * rng continue if price_mode == 'TP': ref_long = ref_short = (sim_data['close'][n] + sim_data['high'][n] + sim_data['low'][n]) / 3.0 elif price_mode == 'HL': ref_long = sim_data['high'][n] ref_short = sim_data['low'][n] elif price_mode == 'CL': ref_long = ref_short = sim_data['close'][n] else: ref_long = ref_short = sim_data['open'][n + 1] target_pos = (ref_long > buytrig) - (ref_short < selltrig) if len(positions) > 0: need_close = (close_daily or (curr_date == sim_data['date'][-1])) and ( sim_data['min_id'][n] >= config['exit_min']) for tradepos in positions: ep = sim_data['low'][n] if tradepos.pos > 0 else sim_data[ 'high'][n] if need_close or tradepos.check_exit( sim_data['open'][n + 1], 0) or (tradepos.pos * target_pos < 0): tradepos.close( sim_data['open'][n + 1] - offset * misc.sign(tradepos.pos), sim_data['datetime'][n + 1]) tradepos.exit_tradeid = tradeid tradeid += 1 pos -= tradepos.pos cost += abs(tradepos.pos) * ( offset + sim_data['open'][n + 1] * tcost) closed_trades.append(tradepos) elif pos_update: tradepos.update_price(ep) positions = [pos for pos in positions if not pos.is_closed] if need_close: continue if target_pos != 0: if (not use_chan) or ( ((ref_long > sim_data['chanh'][n]) and target_pos > 0) or ((ref_short < sim_data['chanl'][n]) and target_pos < 0)): new_pos = pos_class( [sim_data['contract'][n]], [1], unit * target_pos, sim_data['open'][n + 1] + target_pos * offset, buytrig, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(sim_data['open'][n + 1] + target_pos * offset, sim_data['datetime'][n + 1]) positions.append(new_pos) pos += unit * target_pos cost += abs(target_pos) * (offset + sim_data['open'][n + 1] * tcost) sim_data['cost'][n + 1] = cost sim_data['pos'][n + 1] = pos out_df = pd.concat([]) return out_df, closed_trades
def dual_thrust_sim( mdf, config): ddf = config['ddf'] close_daily = config['close_daily'] offset = config['offset'] k = config['param'][0] win = config['param'][1] multiplier = config['param'][2] f = config['param'][3] ep_enabled = config['EP'] chan = config['chan'] chan_func = config['chan_func'] tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] min_rng = config['min_range'] no_trade_set = config['no_trade_set'] if win == -1: tr= pd.concat([ddf.high - ddf.low, ddf.close - ddf.close.shift(1)], join='outer', axis=1).max(axis=1).shift(1) elif win == 0: tr = pd.concat([(pd.rolling_max(ddf.high, 2) - pd.rolling_min(ddf.close, 2))*multiplier, (pd.rolling_max(ddf.close, 2) - pd.rolling_min(ddf.low, 2))*multiplier, ddf.high - ddf.close, ddf.close - ddf.low], join='outer', axis=1).max(axis=1).shift(1) else: tr= pd.concat([pd.rolling_max(ddf.high, win) - pd.rolling_min(ddf.close, win), pd.rolling_max(ddf.close, win) - pd.rolling_min(ddf.low, win)], join='outer', axis=1).max(axis=1).shift(1) ddf['TR'] = tr ddf['MA'] = pd.rolling_mean(ddf.close, chan).shift(1) ddf['H1'] = eval(chan_func['high']['func'])(ddf, chan, **chan_func['high']['args']).shift(1) ddf['L1'] = eval(chan_func['low']['func'])(ddf, chan, **chan_func['low']['args']).shift(1) ll = mdf.shape[0] mdf['pos'] = 0 mdf['cost'] = 0 curr_pos = [] closed_trades = [] start_d = ddf.index[0] end_d = mdf.index[-1].date() prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 for dd in mdf.index: mslice = mdf.loc[dd] min_id = mslice.min_id d = mslice.date dslice = ddf.loc[d] if np.isnan(dslice.TR) or (mslice.close == 0): continue if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.set_value(dd, 'pos', pos) d_open = dslice.open if (d_open <= 0): continue rng = max(min_rng * d_open, k * dslice.TR) if (prev_d < d): d_open = mslice.open d_high = mslice.high d_low = mslice.low else: d_open = dslice.open d_high = max(d_high, mslice.high) d_low = min(d_low, mslice.low) prev_d = d buytrig = d_open + rng selltrig = d_open - rng if dslice.MA > mslice.close: buytrig += f * rng elif dslice.MA < mslice.close: selltrig -= f * rng if ep_enabled: buytrig = max(buytrig, d_high) selltrig = min(selltrig, d_low) if (min_id >= config['exit_min']) : if (pos != 0) and (close_daily or (d == end_d)): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.set_value(dd, 'cost', mdf.at[dd, 'cost'] - abs(pos) * (offset + mslice.close*tcost)) pos = 0 elif min_id not in no_trade_set: if (pos!=0) and (SL>0): curr_pos[0].trail_update(mslice.close) if curr_pos[0].check_exit(mslice.close, SL*mslice.close): curr_pos[0].close(mslice.close-offset*misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.set_value(dd, 'cost', mdf.at[dd, 'cost'] - abs(pos) * (offset + mslice.close*tcost)) pos = 0 if (mslice.high >= buytrig) and (pos <=0 ): if len(curr_pos) > 0: curr_pos[0].close(mslice.close+offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.set_value(dd, 'cost', mdf.at[dd, 'cost'] - abs(pos) * (offset + mslice.close*tcost)) if mslice.high >= dslice.H1: new_pos = tradepos.TradePos([mslice.contract], [1], unit, mslice.close + offset, mslice.close + offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.set_value(dd, 'cost', mdf.at[dd, 'cost'] - abs(pos) * (offset + mslice.close*tcost)) elif (mslice.low <= selltrig) and (pos >=0 ): if len(curr_pos) > 0: curr_pos[0].close(mslice.close-offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.set_value(dd, 'cost', mdf.at[dd, 'cost'] - abs(pos) * (offset + mslice.close*tcost)) if mslice.low <= dslice.L1: new_pos = tradepos.TradePos([mslice.contract], [1], -unit, mslice.close - offset, mslice.close - offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.set_value(dd, 'cost', mdf.at[dd, 'cost'] - abs(pos) * (offset + mslice.close*tcost)) mdf.set_value(dd, 'pos', pos) return (mdf, closed_trades)
def r_breaker_sim( ddf, mdf, config): marginrate = config['marginrate'] offset = config['offset'] k = config['k'] a = k[0] b = k[1] c = k[2] start_equity = config['capital'] tcost = config['trans_cost'] unit = config['unit'] close_daily = config['close_daily'] ddf['range'] = (ddf.high - ddf.low).shift(1) ddf['ssetup'] = (ddf.high+a*(ddf.close - ddf.low)).shift(1) ddf['bsetup'] = (ddf.low-a*(ddf.high - ddf.close)).shift(1) ddf['senter'] = ((1+b)*(ddf.high+ddf.close)/2.0 - b * ddf.low).shift(1) ddf['benter'] = ((1+b)*(ddf.low+ddf.close)/2.0 - b * ddf.high).shift(1) ddf['bbreak'] = ddf.ssetup + c * (ddf.ssetup - ddf.bsetup) ddf['sbreak'] = ddf.bsetup - c * (ddf.ssetup - ddf.bsetup) ll = mdf.shape[0] mdf['pos'] = pd.Series([0]*ll, index = mdf.index) mdf['cost'] = pd.Series([0]*ll, index = mdf.index) curr_pos = [] closed_trades = [] start_d = ddf.index[0] end_d = mdf.index[-1].date() prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 cur_high = 0 cur_low = 0 for dd in mdf.index: mslice = mdf.ix[dd] min_id = agent.get_min_id(dd) d = dd.date() dslice = ddf.ix[d] if np.isnan(dslice.bbreak): continue if (prev_d < d): num_trades = 0 cur_high = mslice.high cur_low = mslice.low else: cur_high = max([cur_high, mslice.high]) cur_low = min([cur_low, mslice.low]) prev_d = d if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if (min_id >= config['exit_min']): if (pos != 0) and (close_daily or (d == end_d)): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 elif (min_id <= config['start_min']): continue else: if num_trades >=2: continue if ((cur_high < dslice.bbreak) and (cur_high >= dslice.ssetup) and (mslice.close < dslice.senter) and (pos >=0)) or \ ((cur_low > dslice.sbreak) and (cur_low <= dslice.bsetup) and (mslice.close > dslice.benter) and (pos <=0)): if len(curr_pos) > 0: curr_pos[0].close(mslice.close-misc.sign(pos)*offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) new_pos = strat.TradePos([mslice.contract], [1], -unit*misc.sign(pos), mslice.close, 0) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset*misc.sign(pos), dd) curr_pos.append(new_pos) pos = -unit*misc.sign(pos) mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) num_trades += 1 elif ((mslice.close >= dslice.bbreak) or (mslice.close <= dslice.sbreak)) and (pos == 0): if (mslice.close >= dslice.bbreak): direction = 1 else: direction = -1 new_pos = strat.TradePos([mslice.contract], [1], unit*direction, mslice.close, 0) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset*misc.sign(direction), dd) curr_pos.append(new_pos) pos = unit*direction mdf.ix[dd, 'cost'] -= abs(direction) * (offset + mslice.close*tcost) num_trades += 1 mdf.ix[dd, 'pos'] = pos (res_pnl, ts) = backtest.get_pnl_stats( mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats( closed_trades ) res = dict( res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def asctrend_sim(mdf, config): offset = config['offset'] tcost = config['trans_cost'] unit = config['unit'] stoploss = config['stoploss'] bar_func = config.get('bar_conv_func', 'dh.bar_conv_func2') param = config['param'] freq = config['freq'] pos_update = config.get('pos_update', False) pos_class = config['pos_class'] pos_args = config['pos_args'] close_daily = config['close_daily'] xdf = dh.conv_ohlc_freq(mdf, freq, extra_cols=['contract'], bar_func=eval(bar_func)) asc_period = param[0] asc_risk = param[1] rsi_sig = config['rsi_sig'] asctrend = dh.ASCTREND(xdf, asc_period, risk=asc_risk) xdf['asc_signal'] = asctrend["ASCSIG_%s" % str(asc_period)].shift(1) xdf['asc_stop'] = asctrend["ASCSTOP_%s" % str(asc_period)].shift(1) rsi_period = param[2] rsi_offset = param[3] rsi_buy = 50 + rsi_offset rsi_sell = 50 - rsi_offset rsi = dh.RSI(xdf, n=rsi_period) rsi_signal = pd.Series(0, index=rsi.index) if rsi_sig: rsi_signal[(rsi >= rsi_buy) & (rsi.shift(1) < rsi_buy)] = 1 rsi_signal[(rsi <= rsi_sell) & (rsi.shift(1) > rsi_sell)] = -1 else: rsi_signal[(rsi >= rsi_buy)] = 1 rsi_signal[(rsi <= rsi_sell)] = -1 xdf['rsi_signal'] = rsi_signal.shift(1) if len(param) > 4: sar_step = param[4] sar_max = param[5] else: sar_step = 0.005 sar_max = 0.02 sar = dh.SAR(xdf, incr=sar_step, maxaf=sar_max) sar_signal = pd.Series(0, index=sar.index) sar_signal[(sar < xdf['close'])] = 1 sar_signal[(sar > xdf['close'])] = -1 xdf['sar_signal'] = sar_signal.shift(1) xdf['sar_stop'] = sar.shift(1) xdf['close_ind'] = np.isnan(xdf['close'].shift(-1)) if close_daily: daily_end = (xdf['date'] != xdf['date'].shift(-1)) xdf['close_ind'] = xdf['close_ind'] | daily_end xdf['pos'] = 0 xdf['cost'] = 0 xdf['traded_price'] = xdf.open curr_pos = [] closed_trades = [] tradeid = 0 for idx, dd in enumerate(xdf.index): mslice = xdf.loc[dd] if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos xdf.set_value(dd, 'pos', pos) if np.isnan(mslice.sar_stop) or np.isnan(mslice.asc_stop): continue buy_trig = (mslice.asc_signal > 0) and (mslice.rsi_signal > 0) and (mslice.sar_signal > 0) sell_trig = (mslice.asc_signal < 0) and (mslice.rsi_signal < 0) and (mslice.sar_signal < 0) buy_close = (mslice.asc_signal < 0) or (mslice.rsi_signal < 0) sell_close = (mslice.asc_signal > 0) or (mslice.rsi_signal > 0) if mslice.close_ind: if (pos != 0): curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 else: if pos_update and pos != 0: curr_pos[0].update_price(mslice.asc_stop) pos_close = curr_pos[0].check_exit(mslice.open, 0) else: pos_close = False if (buy_close and (pos > 0)) or (sell_close and (pos < 0)) or pos_close: curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 if (buy_trig or sell_trig) and (pos == 0): target_pos = buy_trig * unit - sell_trig * unit new_pos = pos_class([mslice.contract], [1], target_pos, mslice.open, mslice.asc_stop, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.open + misc.sign(target_pos) * offset, dd) curr_pos.append(new_pos) pos = target_pos xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(target_pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open + misc.sign(target_pos) * offset) xdf.set_value(dd, 'pos', pos) return (xdf, closed_trades)
def psar_chan_sim(mdf, config): marginrate = config['marginrate'] offset = config['offset'] tcost = config['trans_cost'] unit = config['unit'] stoploss = config['stoploss'] bar_func = config.get('bar_conv_func', 'dh.bar_conv_func2') param = config['param'] freq = config['freq'] use_HL = config.get('use_HL', False) use_chan = config['use_chan'] chan_func = config['chan_func'] chan_args = config['chan_args'] chan = param[0] sar_param = param[1] pos_update = config.get('pos_update', False) pos_class = config['pos_class'] pos_args = config['pos_args'] close_daily = config['close_daily'] xdf = dh.conv_ohlc_freq(mdf, freq, extra_cols=['contract'], bar_func=eval(bar_func)) if use_chan: xdf['chanH'] = eval(chan_func[0])(xdf, chan, **chan_args[0]).shift(1) xdf['chanL'] = eval(chan_func[1])(xdf, chan, **chan_args[1]).shift(1) else: xdf['chanH'] = 0 xdf['chanL'] = 10000000 psar_data = dh.PSAR(xdf, **sar_param) xdf['psar_dir'] = psar_data['PSAR_DIR'].shift(1) xdf['psar_val'] = psar_data['PSAR_VAL'].shift(1) xdf['prev_high'] = xdf['high'].shift(1) xdf['prev_low'] = xdf['low'].shift(1) xdf['prev_close'] = xdf['close'].shift(1) xdf['close_ind'] = np.isnan(xdf['close'].shift(-1)) if close_daily: daily_end = (xdf['date'] != xdf['date'].shift(-1)) xdf['close_ind'] = xdf['close_ind'] | daily_end xdf['pos'] = 0 xdf['cost'] = 0 xdf['traded_price'] = xdf.open curr_pos = [] closed_trades = [] tradeid = 0 for idx, dd in enumerate(xdf.index): mslice = xdf.loc[dd] if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos xdf.set_value(dd, 'pos', pos) if np.isnan(mslice.chanH) or np.isnan(mslice.chanL): continue if use_HL: buy_trig = (mslice.prev_high >= mslice.chanH) and (mslice.psar_dir > 0) sell_trig = (mslice.prev_low <= mslice.chanL) and (mslice.psar_dir < 0) long_close = (mslice.prev_low <= mslice.chanL) or (mslice.psar_dir < 0) short_close = (mslice.prev_high >= mslice.chanH) or (mslice.psar_dir > 0) else: buy_trig = (mslice.open >= mslice.chanH) and (mslice.psar_dir > 0) sell_trig = (mslice.open <= mslice.chanL) and (mslice.psar_dir < 0) long_close = (mslice.open <= mslice.chanL) or (mslice.psar_dir < 0) short_close = (mslice.open >= mslice.chanH) or (mslice.psar_dir > 0) if mslice.close_ind: if (pos != 0): curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 else: if (short_close and (pos > 0)) or (long_close and (pos < 0)): curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 if (buy_trig or sell_trig) and (pos == 0): target_pos = buy_trig * unit - sell_trig * unit new_pos = pos_class([mslice.contract], [1], target_pos, mslice.open, mslice.open, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.open + misc.sign(target_pos) * offset, dd) curr_pos.append(new_pos) pos = target_pos xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(target_pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open + misc.sign(target_pos) * offset) #if pos_update and pos != 0: # if curr_pos[0].check_exit(mslice.open, stoploss * mslice.boll_std): # curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) # tradeid += 1 # curr_pos[0].exit_tradeid = tradeid # closed_trades.append(curr_pos[0]) # curr_pos = [] # xdf.set_value(dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) # xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) # pos = 0 # else: # curr_pos[0].update_bar(mslice) xdf.set_value(dd, 'pos', pos) return (xdf, closed_trades)
def aberration_sim(df, config): marginrate = config['marginrate'] offset = config['offset'] win = config['win'] start_equity = config['capital'] tcost = config['trans_cost'] unit = config['unit'] k = config['scaler'] df['ma'] = dh.MA(df, win).shift(1) std = dh.STDDEV(df, win).shift(1) df['upbnd'] = df['ma'] + std * k[0] df['lowbnd'] = df['ma'] - std * k[0] ll = df.shape[0] df['pos'] = pd.Series([0] * ll, index=df.index) df['cost'] = pd.Series([0] * ll, index=df.index) curr_pos = [] closed_trades = [] start_d = df.index[0].date() end_d = df.index[-1].date() tradeid = 0 for idx, dd in enumerate(df.index): mslice = df.ix[dd] min_id = agent.get_min_id(dd) d = dd.date() if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos df.ix[dd, 'pos'] = pos if np.isnan(mslice.ma): continue if (min_id >= config['exit_min']): if (pos != 0) and (d == end_d): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] df.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) continue else: if ((mslice.close >= mslice.ma) and (pos < 0)) or (mslice.close <= mslice.ma) and (pos > 0): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] df.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 if (mslice.close >= mslice.upbnd) or (mslice.close <= mslice.lowbnd): if (pos == 0): target_pos = (mslice.close >= mslice.upbnd) * unit - ( mslice.close <= mslice.lowbnd) * unit target = (mslice.close >= mslice.upbnd) * mslice.upbnd + ( mslice.close <= mslice.lowbnd) * mslice.lowbnd new_pos = strat.TradePos([mslice.contract], [1], target_pos, target, mslice.upbnd + mslice.lowbnd - target) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + misc.sign(target_pos) * offset, dd) curr_pos.append(new_pos) df.ix[dd, 'cost'] -= abs(target_pos) * (offset + mslice.close * tcost) df.ix[dd, 'pos'] = pos else: print "something wrong with position=%s, close =%s, MA=%s, upBnd=%s, lowBnd=%s" % ( pos, mslice.close, mslice.ma, mslice.upbnd, mslice.lowbnd) (res_pnl, ts) = backtest.get_pnl_stats(df, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats(closed_trades) res = dict(res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def turtle_sim( mdf, config ): ddf = config['ddf'] marginrate = config['marginrate'] offset = config['offset'] start_equity = config['capital'] tcost = config['trans_cost'] chan = config['chan'] unit = config['unit'] param = config['param'] max_pos = param[1] max_loss = param[0] ma_ratio = config['ma_ratio'] use_ma = config['use_ma'] chan_func = config['chan_func'] pos_update = config['pos_update'] ddf['ATR'] =dh.ATR(ddf, n=chan[0]).shift(1) ddf['OL_1'] = eval(chan_func['high']['func'])(ddf, chan[0]).shift(1) ddf['OS_1'] = eval(chan_func['low']['func'])(ddf, chan[0]).shift(1) ddf['CL_1'] = eval(chan_func['low']['func'])(ddf, chan[1]).shift(1) ddf['CS_1'] = eval(chan_func['high']['func'])(ddf, chan[1]).shift(1) ddf['MA1'] = dh.MA(ddf, ma_ratio*chan[0]).shift(1) ddf['MA2'] = dh.MA(ddf, chan[1]).shift(1) ll = mdf.shape[0] mdf['pos'] = pd.Series([0]*ll, index = mdf.index) mdf['cost'] = pd.Series([0]*ll, index = mdf.index) curr_pos = [] tradeid = 0 closed_trades = [] end_d = mdf.index[-1].date() curr_atr = 0 for idx, dd in enumerate(mdf.index): mslice = mdf.ix[dd] min_id = mslice.min_id d = dd.date() dslice = ddf.ix[d] tot_pos = sum( [trade.pos for trade in curr_pos] ) mdf.ix[dd, 'pos'] = tot_pos if np.isnan(dslice.ATR): continue if (min_id >= config['exit_min']) : if (tot_pos != 0) and (d == end_d): for trade_pos in curr_pos: trade_pos.close(mslice.close - misc.sign(trade_pos.pos) * offset, dd) tradeid += 1 trade_pos.exit_tradeid = tradeid closed_trades.append(trade_pos) mdf.ix[dd, 'cost'] -= abs(trade_pos.pos) * (offset + mslice.close*tcost) curr_pos = [] tot_pos = 0 else: if tot_pos == 0: curr_atr = dslice.ATR direction = 0 dol = dslice.OL_1 dos = dslice.OS_1 if (mslice.close >= dol) and ((use_ma == False) or (mslice.MA1 >= mslice.MA2)): direction = 1 elif (mslice.close <= dos) and ((use_ma == False) or (mslice.MA1 <= mslice.MA2)): direction = -1 pos = direction * unit if direction != 0: new_pos = strat.TradePos([mslice.contract], [1], pos, mslice.close, mslice.close) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + direction * offset, dd) mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) curr_pos.append(new_pos) else: direction = curr_pos[0].direction #exit position out of channel if (direction == 1 and mslice.close <= dslice.CL_1) or \ (direction == -1 and mslice.close >= dslice.CS_1): for trade_pos in curr_pos: trade_pos.close(mslice.close - misc.sign(trade_pos.pos) * offset, dd) tradeid += 1 trade_pos.exit_tradeid = tradeid closed_trades.append(trade_pos) mdf.ix[dd, 'cost'] -= abs(trade_pos.pos) * (offset + mslice.close*tcost) curr_pos = [] #stop loss position partially elif curr_pos[-1].check_exit( mslice.close, curr_atr * max_loss ): for trade_pos in curr_pos: if trade_pos.check_exit( mslice.close, curr_atr * max_loss ): trade_pos.close(mslice.close - misc.sign(trade_pos.pos) * offset, dd) tradeid += 1 trade_pos.exit_tradeid = tradeid closed_trades.append(trade_pos) mdf.ix[dd, 'cost'] -= abs(trade_pos.pos) * (offset + mslice.close*tcost) curr_pos = [trade for trade in curr_pos if not trade.is_closed] #add positions elif (len(curr_pos) < max_pos) and (mslice.close - curr_pos[-1].entry_price)*direction > curr_atr/max_pos*max_loss: for trade_pos in curr_pos: #trade.exit_target += curr_atr/max_pos*max_loss * direction trade_pos.set_exit( mslice.close ) new_pos = strat.TradePos([mslice.contract], [1], direction*unit, mslice.close, mslice.close) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + direction * offset, dd) mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) curr_pos.append(new_pos) if (len(curr_pos) > 0) and pos_update: for trade_pos in curr_pos: trade_pos.update_price(mslice.close) mdf.ix[dd, 'pos'] = sum( [trade.pos for trade in curr_pos] ) (res_pnl, ts) = backtest.get_pnl_stats( mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats( closed_trades ) res = dict( res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def chanbreak_sim( mdf, config): freq = config['freq'] str_freq = str(freq) + 'Min' xdf = dh.conv_ohlc_freq(mdf, str_freq) start_equity = config['capital'] tcost = config['trans_cost'] unit = config['unit'] #k = config['scaler'] marginrate = config['marginrate'] offset = config['offset'] win = config['win'] pos_class = config['pos_class'] pos_args = config['pos_args'] chan_func = config['channel_func'] upper_chan_func = chan_func[0] lower_chan_func = chan_func[1] entry_chan = win[0] exit_chan = win[1] xdf['H1'] = upper_chan_func(xdf, entry_chan) xdf['L1'] = lower_chan_func(xdf, entry_chan) xdf['H2'] = upper_chan_func(xdf, exit_chan) xdf['L2'] = lower_chan_func(xdf, exit_chan) xdf['ATR'] = dh.ATR(xdf, entry_chan) xdata = pd.concat([xdf['H1'], xdf['L1'], xdf['H2'], xdf['L2'], xdf['ATR'], xdf['high'], xdf['low']], \ axis=1, keys=['H1', 'L1', 'H2', 'L2', 'ATR', 'xhigh', 'xlow']).shift(1) ll = mdf.shape[0] mdf = mdf.join(xdata, how = 'left').fillna(method='ffill') mdf['pos'] = pd.Series([0]*ll, index = mdf.index) mdf['cost'] = pd.Series([0]*ll, index = mdf.index) curr_pos = [] closed_trades = [] end_d = mdf.index[-1].date() tradeid = 0 x_idx = 0 max_idx = len(xdf.index) for idx, dd in enumerate(mdf.index): mslice = mdf.ix[dd] min_id = mslice.min_id cnt_id = count_min_id(dd) if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos #if np.isnan(mslice.ATR): # continue if (min_id >=config['exit_min']): if (pos!=0) and (dd.date() == end_d): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] pos = 0 mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) continue else: if (pos !=0): if (cnt_id % freq) == 0: curr_pos[0].update_bar(mslice) check_price = (pos>0) * mslice.low + (pos<0) * mslice.high if curr_pos[0].check_exit(check_price, 0): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) pos = 0 curr_pos = [] if ((mslice.high >= mslice.H2) and (pos<0)) or ((mslice.low <= mslice.L2) and (pos>0)): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 if ((mslice.high >= mslice.H1) and (pos<=0)) or ((mslice.low <= mslice.L1) and (pos>=0)): if (pos ==0 ): pos = (mslice.high >= mslice.H1) * unit -(mslice.low <= mslice.L1) * unit exit_target = (mslice.high >= mslice.H1) * mslice.L2 + (mslice.low <= mslice.L1) * mslice.H2 new_pos = pos_class([mslice.contract], [1], pos, mslice.close, exit_target, 1, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + misc.sign(pos)*offset, dd) curr_pos.append(new_pos) mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) mdf.ix[dd, 'pos'] = pos (res_pnl, ts) = backtest.get_pnl_stats( mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats( closed_trades ) res = dict( res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def chanbreak_sim(mdf, ddf, config): freq = config['freq'] str_freq = str(freq) + 'Min' xdf = dh.conv_ohlc_freq(mdf, str_freq) start_equity = config['capital'] tcost = config['trans_cost'] unit = config['unit'] k = config['scaler'] marginrate = config['marginrate'] offset = config['offset'] win = config['win'] chan_func = config['channel_func'] upper_chan_func = chan_func[0] lower_chan_func = chan_func[1] entry_chan = win exit_chan = int(entry_chan / k[1]) xdf['H1'] = upper_chan_func(xdf, entry_chan).shift(1) xdf['L1'] = lower_chan_func(xdf, entry_chan).shift(1) xdf['H2'] = upper_chan_func(xdf, exit_chan).shift(1) xdf['L2'] = lower_chan_func(xdf, exit_chan).shift(1) ddf['ATR'] = dh.ATR(ddf, entry_chan) ll = mdf.shape[0] mdf['pos'] = pd.Series([0] * ll, index=mdf.index) mdf['cost'] = pd.Series([0] * ll, index=mdf.index) curr_pos = [] closed_trades = [] end_d = mdf.index[-1].date() tradeid = 0 x_idx = 0 max_idx = len(xdf.index) for idx, dd in enumerate(mdf.index): mslice = mdf.ix[dd] min_id = agent.get_min_id(dd) d = dd.date() dslice = ddf.ix[d] while (x_idx < max_idx - 1) and (xdf.index[x_idx + 1] < dd): x_idx += 1 xslice = xdf.iloc[x_idx] if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if np.isnan(dslice.ATR): continue if (min_id >= config['exit_min']): if (pos != 0) and (d == end_d): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) continue else: if (pos != 0): curr_pos[0].trail_update(mslice.close) if curr_pos[0].trail_check(mslice.close, dslice.ATR * k[0]): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) pos = 0 curr_pos = [] if ((mslice.close >= xslice.H2) and (pos < 0)) or ((mslice.close <= xslice.L2) and (pos > 0)): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 if ((mslice.close >= xslice.H1) and (pos <= 0)) or ((mslice.close <= xslice.L1) and (pos >= 0)): if (pos == 0): target_pos = (mslice.close >= xslice.H1) * unit - ( mslice.close <= xslice.L1) * unit new_pos = strat.TradePos([mslice.contract], [1], target_pos, mslice.close, mslice.close) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + misc.sign(target_pos) * offset, dd) curr_pos.append(new_pos) mdf.ix[dd, 'cost'] -= abs(target_pos) * (offset + mslice.close * tcost) mdf.ix[dd, 'pos'] = pos else: print "something wrong with position=%s, close =%s, upBnd=%s, lowBnd=%s" % ( pos, mslice.close, xslice.H1, xslice.L1) (res_pnl, ts) = backtest.get_pnl_stats(mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats(closed_trades) res = dict(res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def turtle_sim( ddf, mdf, config ): marginrate = config['marginrate'] offset = config['offset'] start_equity = config['capital'] tcost = config['trans_cost'] signals = config['signals'] unit = config['unit'] NN = config['max_loss'] max_pos = config['max_pos'] use_MA = False if signals[2] > 1: use_MA = True start_idx = 0 trail_loss = config['trail_loss'] ddf['ATR'] = pd.Series(dh.ATR(ddf, n=signals[0]).shift(1)) ddf['OL_1'] = pd.Series(dh.DONCH_H(ddf, signals[0]).shift(1)) ddf['OS_1'] = pd.Series(dh.DONCH_L(ddf, signals[0]).shift(1)) ddf['CL_1'] = pd.Series(dh.DONCH_L(ddf, signals[1]).shift(1)) ddf['CS_1'] = pd.Series(dh.DONCH_H(ddf, signals[1]).shift(1)) if use_MA: ddf['MA'] = pd.Series(dh.MA(ddf, signals[2]*signals[0]).shift(1)) else: ddf['MA'] = pd.Series(0, index=ddf.index) ll = mdf.shape[0] mdf['pos'] = pd.Series([0]*ll, index = mdf.index) mdf['cost'] = pd.Series([0]*ll, index = mdf.index) curr_pos = [] tradeid = 0 closed_trades = [] curr_atr = 0 for idx, dd in enumerate(mdf.index): mslice = mdf.ix[dd] d = dd.date() dslice = ddf.ix[d] tot_pos = sum( [trade.pos for trade in curr_pos] ) mdf.ix[dd, 'pos'] = tot_pos if (idx < start_idx) or np.isnan(dslice.ATR): continue if len(curr_pos) == 0 and idx < len(mdf.index)-NO_OPEN_POS_PROTECT: curr_atr = dslice.ATR direction = 0 dol = dslice.OL_1 dos = dslice.OS_1 if use_MA: dol = max(dol, dslice.MA) dos = min(dos, dslice.MA) if mslice.close >= dol: direction = 1 elif mslice.close <= dos: direction = -1 pos = direction * unit if direction != 0: new_pos = strat.TradePos([mslice.contract], [1], pos, mslice.close, mslice.close) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + direction * offset, dd) mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) curr_pos.append(new_pos) curr_atr = dslice.ATR elif (idx >= len(mdf.index)-NO_OPEN_POS_PROTECT): if len(curr_pos)>0: for trade_pos in curr_pos: trade_pos.close(mslice.close - misc.sign(trade_pos.pos) * offset, dd) tradeid += 1 trade_pos.exit_tradeid = tradeid closed_trades.append(trade_pos) mdf.ix[dd, 'cost'] -= abs(trade_pos.pos) * (offset + mslice.close*tcost) curr_pos = [] else: direction = curr_pos[0].direction if trail_loss: for trade_pos in curr_pos: trade_pos.trail_update(mslice.close) #exit position out of channel if (direction == 1 and mslice.close <= dslice.CL_1) or \ (direction == -1 and mslice.close >= dslice.CS_1): for trade_pos in curr_pos: trade_pos.close(mslice.close - misc.sign(trade_pos.pos) * offset, dd) tradeid += 1 trade_pos.exit_tradeid = tradeid closed_trades.append(trade_pos) mdf.ix[dd, 'cost'] -= abs(trade_pos.pos) * (offset + mslice.close*tcost) curr_pos = [] #stop loss position partially elif curr_pos[-1].trail_check( mslice.close, curr_atr * NN ): for trade_pos in curr_pos: if trade_pos.trail_check( mslice.close, curr_atr * NN )>0: trade_pos.close(mslice.close - misc.sign(trade_pos.pos) * offset, dd) tradeid += 1 trade_pos.exit_tradeid = tradeid closed_trades.append(trade_pos) mdf.ix[dd, 'cost'] -= abs(trade_pos.pos) * (offset + mslice.close*tcost) curr_pos = [trade for trade in curr_pos if not trade.is_closed] #add positions elif (len(curr_pos) < max_pos) and (mslice.close - curr_pos[-1].entry_price)*direction > curr_atr/max_pos*NN: for trade_pos in curr_pos: #trade.exit_target += curr_atr/max_pos*NN * direction trade_pos.exit_target = mslice.close new_pos = strat.TradePos([mslice.contract], [1], direction*unit, mslice.close, mslice.close) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + direction * offset, dd) mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) curr_pos.append(new_pos) mdf.ix[dd, 'pos'] = sum( [trade.pos for trade in curr_pos] ) (res_pnl, ts) = backtest.get_pnl_stats( mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats( closed_trades ) res = dict( res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def dual_thrust_sim( mdf, config): close_daily = config['close_daily'] marginrate = config['marginrate'] offset = config['offset'] k = config['k'] f = config['f'] start_equity = config['capital'] win = config['win'] multiplier = config['m'] tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] min_rng = config['min_range'] ma_fast = config['MA_fast'] ll = mdf.shape[0] mdf['min_idx'] = pd.Series(1, index = mdf.index) mdf.loc[mdf['min_id']<1500, 'min_idx'] = 0 mdf['date_idx'] = mdf.index.date xdf = mdf.groupby([mdf['date_idx'], mdf['min_idx']]).apply(dh.ohlcsum).reset_index().set_index('datetime') if win == -1: tr= pd.concat([xdf.high - xdf.low, abs(xdf.close - xdf.close.shift(1))], join='outer', axis=1).max(axis=1).shift(1) elif win == -2: tr= pd.rolling_max(xdf.high, 2) - pd.rolling_min(xdf.low, 2) elif win == 0: tr = pd.concat([(pd.rolling_max(xdf.high, 2) - pd.rolling_min(xdf.close, 2))*multiplier, (pd.rolling_max(xdf.close, 2) - pd.rolling_min(xdf.low, 2))*multiplier, xdf.high - xdf.close, xdf.close - xdf.low], join='outer', axis=1).max(axis=1).shift(1) else: tr= pd.concat([pd.rolling_max(xdf.high, win) - pd.rolling_min(xdf.close, win), pd.rolling_max(xdf.close, win) - pd.rolling_min(xdf.low, win)], join='outer', axis=1).max(axis=1).shift(1) xdf['TR'] = tr xdf['MA'] = pd.rolling_mean(xdf.close, ma_fast).shift(1) ddf = pd.concat([xdf['TR'], xdf['MA'], xdf['open'], xdf['date_idx']], axis=1, keys=['TR','MA','dopen', 'date']).fillna(0) mdf = mdf.join(ddf, how = 'left').fillna(method='ffill') mdf['pos'] = pd.Series([0]*ll, index = mdf.index) mdf['cost'] = pd.Series([0]*ll, index = mdf.index) curr_pos = [] closed_trades = [] start_d = ddf.index[0] end_d = mdf.index[-1].date() #prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 for dd in mdf.index: mslice = mdf.ix[dd] min_id = agent.get_min_id(dd) if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if mslice.TR == 0 or mslice.MA == 0: continue d_open = mslice.dopen #if (prev_d < d): # d_open = mslice.open #else: # d_open = dslice.open rng = max(min_rng * d_open, k * mslice.TR) if (d_open <= 0): continue buytrig = d_open + rng selltrig = d_open - rng if mslice.MA > mslice.close: buytrig += f * rng elif mslice.MA < mslice.close: selltrig -= f * rng if (min_id >= config['exit_min']) and (close_daily or (mslice.date == end_d)): if (pos != 0): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 else: if (pos!=0) and (SL>0): curr_pos[0].trail_update(mslice.close) if (curr_pos[0].trail_check(mslice.close, SL*mslice.close)): curr_pos[0].close(mslice.close-offset*misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 if (mslice.high >= buytrig) and (pos <=0 ): if len(curr_pos) > 0: curr_pos[0].close(mslice.close+offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) new_pos = strat.TradePos([mslice.contract], [1], unit, mslice.close + offset, mslice.close + offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) elif (mslice.low <= selltrig) and (pos >=0 ): if len(curr_pos) > 0: curr_pos[0].close(mslice.close-offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) new_pos = strat.TradePos([mslice.contract], [1], -unit, mslice.close - offset, mslice.close - offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) mdf.ix[dd, 'pos'] = pos (res_pnl, ts) = backtest.get_pnl_stats( mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats( closed_trades ) res = dict( res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def MA_sim(mdf, config): offset = config['offset'] pos_class = config['pos_class'] pos_args = config['pos_args'] pos_update = config.get('pos_update', False) stoploss = config.get('stoploss', 0.0) ma_list = config['ma_list'] param = config['param'] corr_entry = param[0] corr_exit = param[1] pval_entry = param[2] pval_exit = param[3] if len(param) >= 5: channel = param[4] else: channel = 0 if channel == 0: use_chan = False else: use_chan = True close_daily = config['close_daily'] tcost = config['trans_cost'] unit = config['unit'] freq = config['freq'] if int(freq[:-3]) == 1: xdf = mdf else: xdf = dh.conv_ohlc_freq(mdf, freq, extra_cols=['contract']) if use_chan: xdf['chan_high'] = eval(config['channel_func'][0])( xdf, channel, **config['channel_args'][0]).shift(2) xdf['chan_low'] = eval(config['channel_func'][1])( xdf, channel, **config['channel_args'][1]).shift(2) else: xdf['chan_high'] = pd.Series(index=xdf.index) xdf['chan_low'] = pd.Series(index=xdf.index) ma_ribbon = dh.MA_RIBBON(xdf, ma_list) xdf["ribbon_corr"] = ma_ribbon["MARIBBON_CORR"].shift(1) xdf["ribbon_pval"] = ma_ribbon["MARIBBON_PVAL"].shift(1) xdf["ribbon_dist"] = ma_ribbon["MARIBBON_DIST"].shift(1) xdf['prev_close'] = xdf['close'].shift(1) xdf['close_ind'] = np.isnan(xdf['close'].shift(-1)) if close_daily: daily_end = (xdf['date'] != xdf['date'].shift(-1)) xdf['close_ind'] = xdf['close_ind'] | daily_end ll = xdf.shape[0] xdf['pos'] = 0 xdf['cost'] = 0 xdf['traded_price'] = xdf.open curr_pos = [] closed_trades = [] tradeid = 0 for idx, dd in enumerate(xdf.index): mslice = xdf.loc[dd] if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos xdf.set_value(dd, 'pos', pos) if np.isnan(mslice.ribbon_corr): continue if mslice.close_ind: if pos != 0: curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 else: if (((mslice.ribbon_corr >= -corr_exit) or (mslice.ribbon_pval >= pval_exit)) and (pos<0)) or \ (((mslice.ribbon_corr <= corr_exit) or (mslice.ribbon_pval >= pval_exit)) and (pos>0)): curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 if (pos==0) and (mslice.ribbon_corr >= corr_entry) and (mslice.ribbon_pval < pval_entry) \ and ((use_chan == False) or (mslice.open >= mslice.chan_high)): target_pos = unit elif (pos==0) and (mslice.ribbon_corr <= -corr_entry) and (mslice.ribbon_pval < pval_entry) \ and ((use_chan == False) or (mslice.open <= mslice.chan_low)): target_pos = -unit else: target_pos = 0 if target_pos != 0: new_pos = pos_class([mslice.contract], [1], target_pos, mslice.open, mslice.open, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.open + misc.sign(target_pos) * offset, dd) curr_pos.append(new_pos) pos = target_pos xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(target_pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open + misc.sign(target_pos) * offset) xdf.set_value(dd, 'pos', pos) return (xdf, closed_trades)
def aberration_sim( df, config): marginrate = config['marginrate'] offset = config['offset'] win = config['win'] start_equity = config['capital'] tcost = config['trans_cost'] unit = config['unit'] k = config['scaler'] df['ma'] = dh.MA(df, win).shift(1) std = dh.STDDEV(df, win).shift(1) df['upbnd'] = df['ma'] + std * k[0] df['lowbnd'] = df['ma'] - std * k[0] ll = df.shape[0] df['pos'] = pd.Series([0]*ll, index = df.index) df['cost'] = pd.Series([0]*ll, index = df.index) curr_pos = [] closed_trades = [] start_d = df.index[0].date() end_d = df.index[-1].date() tradeid = 0 for idx, dd in enumerate(df.index): mslice = df.ix[dd] min_id = agent.get_min_id(dd) d = dd.date() if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos df.ix[dd, 'pos'] = pos if np.isnan(mslice.ma): continue if (min_id >=config['exit_min']): if (pos!=0) and (d == end_d): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] df.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) continue else: if ((mslice.close >= mslice.ma) and (pos<0)) or (mslice.close <= mslice.ma) and (pos>0 ) : curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] df.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 if (mslice.close>=mslice.upbnd) or (mslice.close <= mslice.lowbnd): if (pos ==0 ): target_pos = (mslice.close>=mslice.upbnd) * unit -(mslice.close<=mslice.lowbnd) * unit target = (mslice.close>=mslice.upbnd) * mslice.upbnd +(mslice.close<=mslice.lowbnd) * mslice.lowbnd new_pos = strat.TradePos([mslice.contract], [1], target_pos, target, mslice.upbnd+mslice.lowbnd-target) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + misc.sign(target_pos)*offset, dd) curr_pos.append(new_pos) df.ix[dd, 'cost'] -= abs(target_pos) * (offset + mslice.close*tcost) df.ix[dd, 'pos'] = pos else: print "something wrong with position=%s, close =%s, MA=%s, upBnd=%s, lowBnd=%s" % ( pos, mslice.close, mslice.ma, mslice.upbnd, mslice.lowbnd) (res_pnl, ts) = backtest.get_pnl_stats( df, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats( closed_trades ) res = dict( res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def bband_chan_sim(mdf, config): start_equity = config['capital'] marginrate = config['marginrate'] offset = config['offset'] pos_class = config['pos_class'] pos_args = config['pos_args'] param = config['param'] #tick_base = config['tick_base'] close_daily = config['close_daily'] win = param[0] k = param[1] chan = param[2] if chan > 0: chan_func = config['chan_func'] tcost = config['trans_cost'] filter_func = config['filter_func']['func'] filter_args = config['filter_func']['args'] filter_param = config['filter_func']['param'] unit = config['unit'] freq = config['freq'] xdf = dh.conv_ohlc_freq(mdf, freq) xdf['boll_ma'] = dh.MA(xdf, win).shift(1) boll_std = dh.STDEV(xdf, win).shift(1) xdf['upbnd'] = xdf['boll_ma'] + boll_std * k xdf['lowbnd'] = xdf['boll_ma'] - boll_std * k if chan > 0: xdf['chan_h'] = eval(chan_func['high']['func'])( xdf, chan, **chan_func['high']['args']).shift(1) xdf['chan_l'] = eval(chan_func['low']['func'])( xdf, chan, **chan_func['low']['args']).shift(1) else: xdf['chan_h'] = 0 xdf['chan_l'] = 10000000 xdf['high_band'] = xdf[['chan_h', 'upbnd']].max(axis=1) xdf['low_band'] = xdf[['chan_l', 'lowbnd']].min(axis=1) xdf['filter'] = eval(filter_func)(xdf, filter_param[0], **filter_args) xdf['filter_ma'] = pd.rolling_mean(xdf['filter'], filter_param[1]) xdf['filter_ind'] = xdf['filter_ma'] >= filter_param[2] xdf['prev_close'] = xdf['close'].shift(1) xdf['close_ind'] = np.isnan(xdf['close'].shift(-1)) if close_daily: daily_end = (xdf['date'] != xdf['date'].shift(-1)) xdf['close_ind'] = xdf['close_ind'] | daily_end ll = xdf.shape[0] xdf['pos'] = 0 xdf['cost'] = 0 xdf['traded_price'] = xdf.open curr_pos = [] closed_trades = [] tradeid = 0 for idx, dd in enumerate(xdf.index): mslice = xdf.loc[dd] if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos xdf.set_value(dd, 'pos', pos) if np.isnan(mslice.boll_ma) or np.isnan(mslice.chan_h): continue if mslice.close_ind: if pos != 0: curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 else: if ((mslice.open > mslice.boll_ma) and (pos < 0)) or ((mslice.open < mslice.boll_ma) and (pos > 0)): curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 if ((mslice.open >= mslice.high_band) or (mslice.open <= mslice.low_band)) and (pos == 0): target_pos = (mslice.open >= mslice.high_band) * unit - ( mslice.open <= mslice.low_band) * unit new_pos = pos_class([mslice.contract], [1], target_pos, mslice.open, mslice.open, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.open + misc.sign(target_pos) * offset, dd) curr_pos.append(new_pos) pos = target_pos xdf.set_value( dd, 'cost', xdf.at[dd, 'cost'] - abs(target_pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open + misc.sign(target_pos) * offset) xdf.set_value(dd, 'pos', pos) return (xdf, closed_trades)
def psar_test_sim(mdf, config): close_daily = config['close_daily'] marginrate = config['marginrate'] offset = config['offset'] pos_update = config['pos_update'] pos_class = config['pos_class'] pos_args = config['pos_args'] proc_func = config['proc_func'] proc_args = config['proc_args'] start_equity = config['capital'] tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] chan = config['chan'] no_trade_set = config['no_trade_set'] ll = mdf.shape[0] xdf = proc_func(mdf, **proc_args) xdf['chan_h'] = pd.rolling_max(xdf.high, chan) xdf['chan_l'] = pd.rolling_min(xdf.low, chan) xdf['MA'] = pd.rolling_mean(xdf.close, chan) psar_data = dh.PSAR(xdf, **config['sar_params']) xdata = pd.concat( [ xdf['MA'], xdf['chan_h'], xdf['chan_l'], psar_data['PSAR_VAL'], psar_data['PSAR_DIR'], xdf['date_idx'] ], axis=1, keys=['MA', 'chanH', 'chanL', 'psar', 'psar_dir', 'date']) xdata = xdata.shift(1).fillna(0) mdf = mdf.join(xdata, how='left').fillna(method='ffill') mdf['pos'] = pd.Series([0] * ll, index=mdf.index) mdf['cost'] = pd.Series([0] * ll, index=mdf.index) curr_pos = [] closed_trades = [] end_d = mdf.index[-1].date #prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 for dd in mdf.index: mslice = mdf.ix[dd] min_id = mslice.min_id min_cnt = (min_id - 300) / 100 * 60 + min_id % 100 + 1 if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if (mslice.MA == 0) or (mslice.chanH == 0) or (mslice.chanL == 0) or (mslice.psar_dir == 0): continue if (min_id >= config['exit_min']) and (close_daily or (mslice.datetime.date == end_d)): if (pos != 0): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 elif min_id not in no_trade_set: if (pos != 0) and pos_update: curr_pos[0].update_price(mslice.close) if (curr_pos[0].check_exit(mslice.close, SL * mslice.close)): curr_pos[0].close(mslice.close - offset * misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 long_close = ((mslice.low <= mslice.chanL) or (mslice.psar_dir < 0)) and (pos > 0) short_close = ((mslice.high >= mslice.chanH) or (mslice.psar_dir > 0)) and (pos < 0) close_price = mslice.close if (short_close or long_close): if (mslice.psar_dir > 0): close_price = max(mslice.psar, mslice.open) elif (mslice.psar_dir < 0): close_price = min(mslice.psar, mslice.open) curr_pos[0].close(mslice.close + offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] pos = 0 mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) buy_trig = (mslice.high >= mslice.chanH) and (mslice.psar_dir > 0) and (pos == 0) sell_trig = (mslice.low <= mslice.chanL) and (mslice.psar_dir < 0) and (pos == 0) if buy_trig: new_pos = pos_class([mslice.contract], [1], unit, mslice.close + offset, mslice.close + offset, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) elif sell_trig: new_pos = pos_class([mslice.contract], [1], -unit, mslice.close - offset, mslice.close - offset, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) mdf.ix[dd, 'pos'] = pos return (mdf, closed_trades)
def move_to(self, newpos): ''' Arguments: newpos: new position vector, the length of this vector sets which channels will be used. ''' channels = len(newpos) pos = [self._posins.get_position(i) for i in range(channels)] stepspos = [0 for i in range(channels)] est = [] for i in range(channels): e = PositionEstimator() e.add(pos[i], stepspos[i]) est.append(e) delta = [newpos[i] - pos[i] for i in range(channels)] dist = [abs(delta[i]) for i in range(channels)] hold = [False for i in range(channels)] increase_steps = True # print 'move_to(): start pos = %r, delta = %r, dist = %r' % \ # (pos, delta, dist) steps = [-misc.sign(delta[i]) * self._startstep for i in range(channels)] j = 0 while j < 1000: # Move for i in range(channels): if not hold[i]: self._moveins.move_steps(i + self._channel_ofs, steps[i]) stepspos[i] += steps[i] time.sleep(self._delay) # Update position pos2 = [self._posins.get_position(i) for i in range(channels)] realpos2 = pos2[0] delta2 = [newpos[i] - pos2[i] for i in range(channels)] dist2 = [abs(delta2[i]) for i in range(channels)] for i in range(channels): pos2[i] = est[i].add(pos2[i], stepspos[i]) # print 'move_to(): pos = %r, delta2 = %r' % (pos2, delta2) # Increase step size exponentially if increase_steps: for i in range(channels): if not hold[i]: if misc.sign(delta2[i]) != misc.sign(delta[i]): hold[i] = True elif abs(steps[i]) != self._maxstep: steps[i] = misc.sign(delta2[i]) * min(abs(steps[i]) * 2, self._maxstep) # print 'move_to(): increasing stepsize for ch%d to %f' % (i, steps[i]) if all_true(hold): # print 'move_to(): increase_steps=False' increase_steps = False for i in range(channels): hold[i] = False if self._use_reset: est[i].reset() # Immediately reverse if we moved too far if not increase_steps: for i in range(channels): if not hold[i]: if misc.sign(delta2[i]) != misc.sign(delta[i]): if abs(steps[i]) == self._minstep: hold[i] = True else: steps[i] = int(misc.sign(delta2[i]) * max(round(abs(steps[i]) / 2), self._minstep)) if self._use_reset: est[i].reset() # print 'move_to(): reversing and decreasing stepsize for ch%d to %f' % (i, steps[i]) if all_true(hold): # print 'move_to(): Moved to position!' return realpos2 # Remember relative position delta = delta2 j += 1
def turtle_sim(ddf, mdf, config): marginrate = config['marginrate'] offset = config['offset'] start_equity = config['capital'] tcost = config['trans_cost'] signals = config['signals'] unit = config['unit'] NN = config['max_loss'] max_pos = config['max_pos'] start_idx = 0 ddf['ATR'] = pd.Series(dh.ATR(ddf, n=signals[0]).shift(1)) ddf['OL_1'] = pd.Series(dh.DONCH_H(ddf, signals[0]).shift(1)) ddf['OS_1'] = pd.Series(dh.DONCH_L(ddf, signals[0]).shift(1)) ddf['CL_1'] = pd.Series(dh.DONCH_L(ddf, signals[1]).shift(1)) ddf['CS_1'] = pd.Series(dh.DONCH_H(ddf, signals[1]).shift(1)) ddf['MA1'] = pd.Series(dh.MA(ddf, signals[2]).shift(1)) ddf['MA2'] = pd.Series(dh.MA(ddf, signals[3]).shift(1)) ll = mdf.shape[0] mdf['pos'] = pd.Series([0] * ll, index=mdf.index) mdf['cost'] = pd.Series([0] * ll, index=mdf.index) curr_pos = [] tradeid = 0 closed_trades = [] curr_atr = 0 for idx, dd in enumerate(mdf.index): mslice = mdf.ix[dd] d = dd.date() dslice = ddf.ix[d] tot_pos = sum([trade.pos for trade in curr_pos]) mdf.ix[dd, 'pos'] = tot_pos if (idx < start_idx) or np.isnan(dslice.ATR): continue if len(curr_pos) == 0 and idx < len(mdf.index) - NO_OPEN_POS_PROTECT: curr_atr = dslice.ATR direction = 0 up_MA = False down_MA = False if np.isnan(dslice.MA1) or (dslice.MA1 < dslice.MA2): up_MA = True if np.isnan(dslice.MA1) or (dslice.MA1 > dslice.MA2): down_MA = True if (mslice.close >= dslice.OL_1) and up_MA: direction = 1 elif (mslice.close <= dslice.OS_1) and down_MA: direction = -1 pos = direction * unit if direction != 0: new_pos = strat.TradePos([mslice.contract], [1], pos, mslice.close, mslice.close - direction * curr_atr * NN) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + direction * offset, dd) mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) curr_pos.append(new_pos) curr_atr = dslice.ATR elif (idx >= len(mdf.index) - NO_OPEN_POS_PROTECT): if len(curr_pos) > 0: for trade_pos in curr_pos: trade_pos.close( mslice.close - misc.sign(trade_pos.pos) * offset, dd) tradeid += 1 trade_pos.exit_tradeid = tradeid closed_trades.append(trade_pos) mdf.ix[dd, 'cost'] -= abs( trade_pos.pos) * (offset + mslice.close * tcost) curr_pos = [] else: direction = curr_pos[0].direction #exit position out of channel if (direction == 1 and mslice.close <= dslice.CL_1) or \ (direction == -1 and mslice.close >= dslice.CS_1): for trade_pos in curr_pos: trade_pos.close( mslice.close - misc.sign(trade_pos.pos) * offset, dd) tradeid += 1 trade_pos.exit_tradeid = tradeid closed_trades.append(trade_pos) mdf.ix[dd, 'cost'] -= abs( trade_pos.pos) * (offset + mslice.close * tcost) curr_pos = [] #stop loss position partially elif (curr_pos[-1].exit_target - mslice.close) * direction >= 0: for trade_pos in curr_pos: if (trade_pos.exit_target - mslice.close) * direction > 0: trade_pos.close( mslice.close - misc.sign(trade_pos.pos) * offset, dd) tradeid += 1 trade_pos.exit_tradeid = tradeid closed_trades.append(trade_pos) mdf.ix[dd, 'cost'] -= abs( trade_pos.pos) * (offset + mslice.close * tcost) curr_pos = [trade for trade in curr_pos if not trade.is_closed] #add positions elif (len(curr_pos) < max_pos) and (mslice.close - curr_pos[-1].entry_price ) * direction > curr_atr / max_pos * NN: for trade_pos in curr_pos: #trade.exit_target += curr_atr/max_pos*NN * direction trade_pos.exit_target = mslice.close - direction * curr_atr * NN new_pos = strat.TradePos( [mslice.contract], [1], direction * unit, mslice.close, mslice.close - direction * curr_atr * NN) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + direction * offset, dd) mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) curr_pos.append(new_pos) mdf.ix[dd, 'pos'] = sum([trade.pos for trade in curr_pos]) (res_pnl, ts) = backtest.get_pnl_stats(mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats(closed_trades) res = dict(res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def chanbreak_sim( mdf, ddf, config): freq = config['freq'] str_freq = str(freq) + 'Min' xdf = dh.conv_ohlc_freq(mdf, str_freq) start_equity = config['capital'] tcost = config['trans_cost'] unit = config['unit'] k = config['scaler'] marginrate = config['marginrate'] offset = config['offset'] win = config['win'] chan_func = config['channel_func'] upper_chan_func = chan_func[0] lower_chan_func = chan_func[1] entry_chan = win exit_chan = int(entry_chan/k[1]) xdf['H1'] = upper_chan_func(xdf, entry_chan).shift(1) xdf['L1'] = lower_chan_func(xdf, entry_chan).shift(1) xdf['H2'] = upper_chan_func(xdf, exit_chan).shift(1) xdf['L2'] = lower_chan_func(xdf, exit_chan).shift(1) ddf['ATR'] = dh.ATR(ddf, entry_chan) ll = mdf.shape[0] mdf['pos'] = pd.Series([0]*ll, index = mdf.index) mdf['cost'] = pd.Series([0]*ll, index = mdf.index) curr_pos = [] closed_trades = [] end_d = mdf.index[-1].date() tradeid = 0 x_idx = 0 max_idx = len(xdf.index) for idx, dd in enumerate(mdf.index): mslice = mdf.ix[dd] min_id = agent.get_min_id(dd) d = dd.date() dslice = ddf.ix[d] while (x_idx<max_idx-1) and (xdf.index[x_idx + 1] < dd): x_idx += 1 xslice = xdf.iloc[x_idx] if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if np.isnan(dslice.ATR): continue if (min_id >=config['exit_min']): if (pos!=0) and (d == end_d): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) continue else: if (pos !=0): curr_pos[0].trail_update(mslice.close) if curr_pos[0].trail_check(mslice.close, dslice.ATR*k[0]): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) pos = 0 curr_pos = [] if ((mslice.close >= xslice.H2) and (pos<0)) or ((mslice.close <= xslice.L2) and (pos>0)): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 if ((mslice.close>=xslice.H1) and (pos<=0)) or ((mslice.close <= xslice.L1) and (pos>=0)): if (pos ==0 ): target_pos = (mslice.close>=xslice.H1) * unit -(mslice.close<=xslice.L1) * unit new_pos = strat.TradePos([mslice.contract], [1], target_pos, mslice.close, mslice.close) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + misc.sign(target_pos)*offset, dd) curr_pos.append(new_pos) mdf.ix[dd, 'cost'] -= abs(target_pos) * (offset + mslice.close*tcost) mdf.ix[dd, 'pos'] = pos else: print "something wrong with position=%s, close =%s, upBnd=%s, lowBnd=%s" % ( pos, mslice.close, xslice.H1, xslice.L1) (res_pnl, ts) = backtest.get_pnl_stats( mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats( closed_trades ) res = dict( res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def dual_thrust_sim(mdf, config): close_daily = config['close_daily'] marginrate = config['marginrate'] offset = config['offset'] k = config['param'][0] win = config['param'][1] multiplier = config['param'][2] f = config['param'][3] pos_update = config['pos_update'] pos_class = config['pos_class'] pos_args = config['pos_args'] proc_func = config['proc_func'] proc_args = config['proc_args'] start_equity = config['capital'] chan_func = config['chan_func'] chan_high = eval(chan_func['high']['func']) chan_low = eval(chan_func['low']['func']) tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] min_rng = config['min_range'] chan = config['chan'] use_chan = config['use_chan'] no_trade_set = config['no_trade_set'] ll = mdf.shape[0] xdf = proc_func(mdf, **proc_args) if win == -1: tr = pd.concat( [xdf.high - xdf.low, abs(xdf.close - xdf.close.shift(1))], join='outer', axis=1).max(axis=1) elif win == 0: tr = pd.concat( [(pd.rolling_max(xdf.high, 2) - pd.rolling_min(xdf.close, 2)) * multiplier, (pd.rolling_max(xdf.close, 2) - pd.rolling_min(xdf.low, 2)) * multiplier, xdf.high - xdf.close, xdf.close - xdf.low], join='outer', axis=1).max(axis=1) else: tr = pd.concat([ pd.rolling_max(xdf.high, win) - pd.rolling_min(xdf.close, win), pd.rolling_max(xdf.close, win) - pd.rolling_min(xdf.low, win) ], join='outer', axis=1).max(axis=1) xdf['TR'] = tr xdf['chan_h'] = chan_high(xdf['high'], chan, **chan_func['high']['args']) xdf['chan_l'] = chan_low(xdf['low'], chan, **chan_func['low']['args']) xdf['MA'] = pd.rolling_mean(xdf.close, chan) xdata = pd.concat([ xdf['TR'].shift(1), xdf['MA'].shift(1), xdf['chan_h'].shift(1), xdf['chan_l'].shift(1), xdf['open'] ], axis=1, keys=['TR', 'MA', 'chanH', 'chanL', 'dopen']).fillna(0) mdf = mdf.join(xdata, how='left').fillna(method='ffill') mdf['pos'] = pd.Series([0] * ll, index=mdf.index) mdf['cost'] = pd.Series([0] * ll, index=mdf.index) curr_pos = [] closed_trades = [] end_d = mdf.index[-1].date #prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 pos_update_idx = 0 for idx, dd in enumerate(mdf.index): mslice = mdf.ix[dd] min_id = mslice.min_id min_cnt = (min_id - 300) / 100 * 60 + min_id % 100 + 1 if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if (mslice.TR == 0) or (mslice.MA == 0): continue d_open = mslice.dopen rng = max(min_rng * d_open, k * mslice.TR) if (d_open <= 0): continue buytrig = d_open + rng selltrig = d_open - rng if 'reset_margin' in pos_args: pos_args['reset_margin'] = mslice.TR * SL if mslice.MA > mslice.close: buytrig += f * rng elif mslice.MA < mslice.close: selltrig -= f * rng if (min_id >= config['exit_min']) and (close_daily or (mslice.date == end_d)): if (pos != 0): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 elif min_id not in no_trade_set: if (pos != 0): exit_flag = False if (curr_pos[0].check_exit(mslice.close, 0)): curr_pos[0].close(mslice.close - offset * misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 elif pos_update and (min_cnt % config['pos_freq'] == 0): if pos > 0: ep = max(mdf['high'][pos_update_idx:idx]) else: ep = max(mdf['low'][pos_update_idx:idx]) curr_pos[0].update_price(ep) pos_update_idx = idx if (mslice.high >= buytrig) and (pos <= 0): if pos < 0: curr_pos[0].close(mslice.close + offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 if (use_chan == False) or (mslice.high > mslice.chanH): new_pos = pos_class([mslice.contract], [1], unit, mslice.close + offset, selltrig, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos_update_idx = idx elif (mslice.low <= selltrig) and (pos >= 0): if pos > 0: curr_pos[0].close(mslice.close - offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 if (use_chan == False) or (mslice.low < mslice.chanL): new_pos = pos_class([mslice.contract], [1], -unit, mslice.close - offset, buytrig, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos_update_idx = idx mdf.ix[dd, 'pos'] = pos return (mdf, closed_trades)
def psar_test_sim( mdf, config): close_daily = config['close_daily'] marginrate = config['marginrate'] offset = config['offset'] pos_update = config['pos_update'] pos_class = config['pos_class'] pos_args = config['pos_args'] proc_func = config['proc_func'] proc_args = config['proc_args'] start_equity = config['capital'] tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] chan = config['chan'] no_trade_set = config['no_trade_set'] ll = mdf.shape[0] xdf = proc_func(mdf, **proc_args) xdf['chan_h'] = pd.rolling_max(xdf.high, chan) xdf['chan_l'] = pd.rolling_min(xdf.low, chan) xdf['MA'] = pd.rolling_mean(xdf.close, chan) psar_data = dh.PSAR(xdf, **config['sar_params']) xdata = pd.concat([xdf['MA'], xdf['chan_h'], xdf['chan_l'], psar_data['PSAR_VAL'], psar_data['PSAR_DIR'], xdf['date_idx']], axis=1, keys=['MA', 'chanH', 'chanL', 'psar', 'psar_dir', 'date']) xdata = xdata.shift(1).fillna(0) mdf = mdf.join(xdata, how = 'left').fillna(method='ffill') mdf['pos'] = pd.Series([0]*ll, index = mdf.index) mdf['cost'] = pd.Series([0]*ll, index = mdf.index) curr_pos = [] closed_trades = [] end_d = mdf.index[-1].date #prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 for dd in mdf.index: mslice = mdf.ix[dd] min_id = mslice.min_id min_cnt = (min_id-300)/100 * 60 + min_id % 100 + 1 if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if (mslice.MA == 0) or (mslice.chanH == 0) or (mslice.chanL == 0) or (mslice.psar_dir ==0): continue if (min_id >= config['exit_min']) and (close_daily or (mslice.datetime.date == end_d)): if (pos != 0): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 elif min_id not in no_trade_set: if (pos!=0) and pos_update: curr_pos[0].update_price(mslice.close) if (curr_pos[0].check_exit( mslice.close, SL * mslice.close )): curr_pos[0].close(mslice.close-offset*misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 long_close = ((mslice.low <= mslice.chanL) or (mslice.psar_dir < 0)) and (pos >0) short_close = ((mslice.high >= mslice.chanH) or (mslice.psar_dir > 0)) and (pos <0) close_price = mslice.close if (short_close or long_close): if (mslice.psar_dir > 0): close_price = max(mslice.psar, mslice.open) elif (mslice.psar_dir < 0): close_price = min(mslice.psar, mslice.open) curr_pos[0].close(mslice.close+offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] pos = 0 mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) buy_trig = (mslice.high >= mslice.chanH) and (mslice.psar_dir > 0) and (pos ==0) sell_trig = (mslice.low <= mslice.chanL) and (mslice.psar_dir < 0) and (pos == 0) if buy_trig: new_pos = pos_class([mslice.contract], [1], unit, mslice.close + offset, mslice.close + offset, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) elif sell_trig: new_pos = pos_class([mslice.contract], [1], -unit, mslice.close - offset, mslice.close - offset, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) mdf.ix[dd, 'pos'] = pos (res_pnl, ts) = backtest.get_pnl_stats( mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats( closed_trades ) res = dict( res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def psar_chan_sim( mdf, config): marginrate = config['marginrate'] offset = config['offset'] tcost = config['trans_cost'] unit = config['unit'] stoploss = config['stoploss'] bar_func = config.get('bar_conv_func', 'dh.bar_conv_func2') param = config['param'] freq = config['freq'] use_HL = config.get('use_HL',False) use_chan = config['use_chan'] chan_func = config['chan_func'] chan_args = config['chan_args'] chan = param[0] sar_param = param[1] pos_update = config.get('pos_update', False) pos_class = config['pos_class'] pos_args = config['pos_args'] close_daily = config['close_daily'] xdf = dh.conv_ohlc_freq(mdf, freq, extra_cols = ['contract'], bar_func = eval(bar_func)) if use_chan: xdf['chanH'] = eval(chan_func[0])(xdf, chan, **chan_args[0]).shift(1) xdf['chanL'] = eval(chan_func[1])(xdf, chan, **chan_args[1]).shift(1) else: xdf['chanH'] = 0 xdf['chanL'] = 10000000 psar_data = dh.PSAR(xdf, **sar_param) xdf['psar_dir'] = psar_data['PSAR_DIR'].shift(1) xdf['psar_val'] = psar_data['PSAR_VAL'].shift(1) xdf['prev_high'] = xdf['high'].shift(1) xdf['prev_low'] = xdf['low'].shift(1) xdf['prev_close'] = xdf['close'].shift(1) xdf['close_ind'] = np.isnan(xdf['close'].shift(-1)) if close_daily: daily_end = (xdf['date']!=xdf['date'].shift(-1)) xdf['close_ind'] = xdf['close_ind'] | daily_end xdf['pos'] = 0 xdf['cost'] = 0 xdf['traded_price'] = xdf.open curr_pos = [] closed_trades = [] tradeid = 0 for idx, dd in enumerate(xdf.index): mslice = xdf.loc[dd] if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos xdf.set_value(dd, 'pos', pos) if np.isnan(mslice.chanH) or np.isnan(mslice.chanL): continue if use_HL: buy_trig = (mslice.prev_high >= mslice.chanH) and (mslice.psar_dir > 0) sell_trig = (mslice.prev_low <= mslice.chanL) and (mslice.psar_dir < 0) long_close = (mslice.prev_low <= mslice.chanL) or (mslice.psar_dir < 0) short_close = (mslice.prev_high >= mslice.chanH) or (mslice.psar_dir > 0) else: buy_trig = (mslice.open >= mslice.chanH) and (mslice.psar_dir > 0) sell_trig = (mslice.open <= mslice.chanL) and (mslice.psar_dir < 0) long_close = (mslice.open <= mslice.chanL) or (mslice.psar_dir < 0) short_close = (mslice.open >= mslice.chanH) or (mslice.psar_dir > 0) if mslice.close_ind: if (pos != 0): curr_pos[0].close(mslice.open - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value(dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * ( mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 else: if (short_close and (pos > 0)) or (long_close and (pos < 0)): curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] xdf.set_value(dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) pos = 0 if (buy_trig or sell_trig) and (pos==0): target_pos = buy_trig * unit - sell_trig * unit new_pos = pos_class([mslice.contract], [1], target_pos, mslice.open, mslice.open, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.open + misc.sign(target_pos)*offset, dd) curr_pos.append(new_pos) pos = target_pos xdf.set_value(dd, 'cost', xdf.at[dd, 'cost'] - abs(target_pos) * (mslice.open * tcost)) xdf.set_value(dd, 'traded_price', mslice.open + misc.sign(target_pos)*offset) #if pos_update and pos != 0: # if curr_pos[0].check_exit(mslice.open, stoploss * mslice.boll_std): # curr_pos[0].close(mslice.open - misc.sign(pos) * offset, dd) # tradeid += 1 # curr_pos[0].exit_tradeid = tradeid # closed_trades.append(curr_pos[0]) # curr_pos = [] # xdf.set_value(dd, 'cost', xdf.at[dd, 'cost'] - abs(pos) * (mslice.open * tcost)) # xdf.set_value(dd, 'traded_price', mslice.open - misc.sign(pos) * offset) # pos = 0 # else: # curr_pos[0].update_bar(mslice) xdf.set_value(dd, 'pos', pos) return (xdf, closed_trades)
def dual_thrust_sim( mdf, config): (pos_class, pos_args) = config['pos_param'] update_freq = config.get('update_freq', 0) ddf = config['ddf'] close_daily = config['close_daily'] offset = config['offset'] k = config['param'][0] win = config['param'][1] multiplier = config['param'][2] f = config['param'][3] chan = config['chan'] chan_func = config['chan_func'] use_chan = config['use_chan'] tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] min_rng = config['min_range'] if win == -1: tr= pd.concat([ddf.high - ddf.low, ddf.close - ddf.close.shift(1)], join='outer', axis=1).max(axis=1).shift(1) elif win == 0: tr = pd.concat([(pd.rolling_max(ddf.high, 2) - pd.rolling_min(ddf.close, 2))*multiplier, (pd.rolling_max(ddf.close, 2) - pd.rolling_min(ddf.low, 2))*multiplier, ddf.high - ddf.close, ddf.close - ddf.low], join='outer', axis=1).max(axis=1).shift(1) else: tr= pd.concat([pd.rolling_max(ddf.high, win) - pd.rolling_min(ddf.close, win), pd.rolling_max(ddf.close, win) - pd.rolling_min(ddf.low, win)], join='outer', axis=1).max(axis=1).shift(1) ddf['TR'] = tr ddf['ATR'] = dh.ATR(ddf, win) if use_chan: ddf['CH_H'] = eval(chan_func['high']['func'])(ddf, chan, **chan_func['high']['args']).shift(1) ddf['CH_L'] = eval(chan_func['low']['func'])(ddf, chan, **chan_func['low']['args']).shift(1) if update_freq > 1: xdf = dh.conv_ohlc_freq(mdf, str(update_freq)+'Min') else: xdf = mdf xdata = pd.concat([xdf['open'], xdf['high'], xdf['low'], xdf['close']], axis=1, keys=['xopen','xhigh', 'xlow', 'xclose']) mdf = mdf.join(xdata, how = 'left').fillna(method='ffill') ll = mdf.shape[0] mdf['pos'] = 0 mdf['cost'] = 0 start_d = ddf.index[0] end_d = mdf.index[-1].date() prev_d = start_d - datetime.timedelta(days=1) curr_pos = [] closed_trades = [] tradeid = 0 for idx, dd in enumerate(mdf.index): mslice = mdf.ix[dd] min_id = mslice.min_id d = mslice.date dslice = ddf.ix[d] if np.isnan(dslice.TR) or (mslice.close == 0): continue if use_chan and np.isnan(dslice.CH_H): continue if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos d_open = dslice.open if (d_open <= 0): continue rng = max(min_rng * d_open, k * dslice.TR) if (prev_d < d): d_open = mslice.open else: d_open = dslice.open prev_d = d buytrig = d_open + rng selltrig = d_open - rng stoploss = SL * dslice.ATR tmp_args = pos_args.copy() if 'reset_margin' in pos_args: tmp_args['reset_margin'] = dslice.ATR * pos_args['reset_margin'] stoploss = tmp_args['reset_margin'] * stoploss close_pos = False if pos != 0: if ((pos > 0) and (mslice.high < buytrig)) or ((pos < 0) and (mslice.low > selltrig)): close_pos = curr_pos[0].check_exit(mslice.close, stoploss) if (close_pos == False) and (update_freq > 0) and ((mslice.min_id + 1) % update_freq == 0): xslice = conv_xslice(mslice) curr_pos[0].update_bar(xslice) if close_pos or ((mslice.min_id >= config['exit_min']) and (close_daily or (d == end_d))): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 if mslice.min_id < config['exit_min']: if (mslice.high >= buytrig) and (pos <=0 ): if len(curr_pos) > 0: curr_pos[0].close(mslice.close+offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) if (use_chan == False) or (use_chan and (mslice.high >= dslice.CH_H)): new_pos = eval(pos_class)([mslice.contract], [1], unit, mslice.close + offset, mslice.close + offset, **tmp_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) elif (mslice.low <= selltrig) and (pos >=0 ): if len(curr_pos) > 0: curr_pos[0].close(mslice.close-offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) if (use_chan == False) or (use_chan and (mslice.low <= dslice.CH_L)): new_pos = eval(pos_class)([mslice.contract], [1], -unit, mslice.close - offset, mslice.close - offset, **tmp_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) mdf.ix[dd, 'pos'] = pos return (mdf, closed_trades)
def dual_thrust_sim( ddf, mdf, config): close_daily = config['close_daily'] marginrate = config['marginrate'] offset = config['offset'] k = config['k'] start_equity = config['capital'] win = config['win'] multiplier = config['m'] tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] min_rng = config['min_range'] if win == -1: tr= pd.concat([ddf.high - ddf.low, ddf.close - ddf.close.shift(1)], join='outer', axis=1).max(axis=1).shift(1) elif win == 0: tr = pd.concat([(pd.rolling_max(ddf.high, 2) - pd.rolling_min(ddf.close, 2))*multiplier, (pd.rolling_max(ddf.close, 2) - pd.rolling_min(ddf.low, 2))*multiplier, ddf.high - ddf.close, ddf.close - ddf.low], join='outer', axis=1).max(axis=1).shift(1) else: tr= pd.concat([pd.rolling_max(ddf.high, win) - pd.rolling_min(ddf.close, win), pd.rolling_max(ddf.close, win) - pd.rolling_min(ddf.low, win)], join='outer', axis=1).max(axis=1).shift(1) ddf['TR'] = tr #ddf['prev_high'] = ddf.high.shift(1) #ddf['prev_low'] = ddf.low.shift(1) ll = mdf.shape[0] mdf['pos'] = pd.Series([0]*ll, index = mdf.index) mdf['cost'] = pd.Series([0]*ll, index = mdf.index) curr_pos = [] closed_trades = [] start_d = ddf.index[0] end_d = mdf.index[-1].date() prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 for dd in mdf.index: mslice = mdf.ix[dd] min_id = agent.get_min_id(dd) d = dd.date() dslice = ddf.ix[d] if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if np.isnan(dslice.TR): continue d_open = dslice.open if (prev_d < d): d_open = mslice.open #d_high = mslice.high #d_low = mslice.low else: d_open = dslice.open #d_high = max(d_high, mslice.high) #d_low = min(d_low, mslice.low) if (d_open <= 0): continue prev_d = d buytrig = d_open + max(min_rng * d_open, dslice.TR * k) selltrig = d_open - max(min_rng * d_open, dslice.TR * k) #d_high = max(d_high, dslice.prev_high) #d_low = min(d_low, dslice.prev_low) if (min_id >= config['exit_min']): if (pos != 0) and (close_daily or (d == end_d)): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 else: if (pos!=0) and (SL>0): curr_pos[0].trail_update(mslice.close) if (curr_pos[0].trail_check(mslice.close, SL*mslice.close)): curr_pos[0].close(mslice.close-offset*misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 if (mslice.high >= buytrig) and (pos <=0 ): if len(curr_pos) > 0: curr_pos[0].close(mslice.close+offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) new_pos = strat.TradePos([mslice.contract], [1], unit, mslice.close + offset, mslice.close + offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) elif (mslice.low <= selltrig) and (pos >=0 ): if len(curr_pos) > 0: curr_pos[0].close(mslice.close-offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) new_pos = strat.TradePos([mslice.contract], [1], -unit, mslice.close - offset, mslice.close - offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) mdf.ix[dd, 'pos'] = pos (res_pnl, ts) = backtest.get_pnl_stats( mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats( closed_trades ) res = dict( res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def fisher_swing_sim(df, xdf, config): marginrate = config['marginrate'] offset = config['offset'] win = config['win'] start_equity = config['capital'] tcost = config['trans_cost'] unit = config['unit'] fisher = dh.FISHER(xdf, win[0]) xdf['FISHER_I'] = fisher['FISHER_I'].shift(1) xdf = xdf.join(dh.BBANDS_STOP(xdf, win[1], 1.0).shift(1)) ha_df = dh.HEIKEN_ASHI(xdf, win[2]).shift(1) xdf['HAopen'] = ha_df['HAopen'] xdf['HAclose'] = ha_df['HAclose'] ll = df.shape[0] df['pos'] = pd.Series([0] * ll, index=df.index) df['cost'] = pd.Series([0] * ll, index=df.index) curr_pos = [] closed_trades = [] end_d = df.index[-1].date() tradeid = 0 for dd in df.index: mslice = df.ix[dd] min_id = agent.get_min_id(dd) d = dd.date() if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos df.ix[dd, 'pos'] = pos if np.isnan(mslice.BBSTOP_lower) or np.isnan( mslice.FISHER_I) or np.isnan(mslice.HAclose): continue end_trading = (min_id >= config['exit_min']) and (d == end_d) stop_loss = (pos > 0) and ((mslice.close < mslice.BBSTOP_lower) or (mslice.FISHER_I < 0)) stop_loss = stop_loss or ((pos < 0) and ((mslice.close > mslice.BBSTOP_upper) or (mslice.FISHER_I > 0))) start_long = (mslice.FISHER_I > 0) and ( mslice.HAclose > mslice.HAopen) and (mslice.BBSTOP_trend > 0) start_short = (mslice.FISHER_I < 0) and ( mslice.HAclose < mslice.HAopen) and (mslice.BBSTOP_trend < 0) if pos != 0: if stop_loss or end_trading: curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] df.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 if (not end_trading) and (pos == 0): if start_long and start_short: print "warning: get both long and short signal, something is wrong!" print mslice continue pos = (start_long == True) * unit - (start_short == True) * unit if abs(pos) > 0: #target = (start_long == True) * mslice.close +(start_short == True) * mslice.close new_pos = strat.TradePos([mslice.contract], [1], pos, mslice.close, mslice.close) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + misc.sign(pos) * offset, dd) curr_pos.append(new_pos) df.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) df.ix[dd, 'pos'] = pos (res_pnl, ts) = backtest.get_pnl_stats(df, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats(closed_trades) res = dict(res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def dual_thrust_sim( ddf, mdf, config): close_daily = config['close_daily'] marginrate = config['marginrate'] offset = config['offset'] k = config['k'] start_equity = config['capital'] win = config['win'] multiplier = config['m'] tcost = config['trans_cost'] unit = config['unit'] SL = config['stoploss'] min_rng = config['min_range'] if win == -1: tr = (ddf.high - ddf.low).shift(1) elif win == 0: tr = pd.concat([(pd.rolling_max(ddf.high, 2) - pd.rolling_min(ddf.close, 2))*multiplier, (pd.rolling_max(ddf.close, 2) - pd.rolling_min(ddf.low, 2))*multiplier, ddf.high - ddf.close, ddf.close - ddf.low], join='outer', axis=1).max(axis=1).shift(1) else: tr= pd.concat([pd.rolling_max(ddf.high, win) - pd.rolling_min(ddf.close, win), pd.rolling_max(ddf.close, win) - pd.rolling_min(ddf.low, win)], join='outer', axis=1).max(axis=1).shift(1) ddf['TR'] = tr ll = mdf.shape[0] mdf['pos'] = pd.Series([0]*ll, index = mdf.index) mdf['cost'] = pd.Series([0]*ll, index = mdf.index) curr_pos = [] closed_trades = [] start_d = ddf.index[0] end_d = mdf.index[-1].date() #prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 for dd in mdf.index: mslice = mdf.ix[dd] min_id = agent.get_min_id(dd) d = dd.date() dslice = ddf.ix[d] if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos if np.isnan(dslice.TR): continue d_open = dslice.open #if (prev_d < d): # d_open = mslice.open #else: # d_open = dslice.open if (d_open <= 0): continue #prev_d = d buytrig = d_open + max(min_rng, dslice.TR * k) selltrig = d_open - max(min_rng, dslice.TR * k) if (min_id >= config['exit_min']): if (pos != 0) and (close_daily or (d == end_d)): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 else: if (pos!=0) and (SL>0) and (curr_pos[0].trail_loss(mslice.close, SL*mslice.close)): curr_pos[0].close(mslice.close-offset*misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0 if (mslice.close >= buytrig) and (pos <=0 ): if len(curr_pos) > 0: curr_pos[0].close(mslice.close+offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) new_pos = strat.TradePos([mslice.contract], [1], unit, buytrig, 0) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) elif (mslice.close <= selltrig) and (pos >=0 ): if len(curr_pos) > 0: curr_pos[0].close(mslice.close-offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) new_pos = strat.TradePos([mslice.contract], [1], -unit, selltrig, 0) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) mdf.ix[dd, 'pos'] = pos (res_pnl, ts) = backtest.get_pnl_stats( mdf, start_equity, marginrate, 'm') res_trade = backtest.get_trade_stats( closed_trades ) res = dict( res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def chanbreak_sim(mdf, config): freq = config['freq'] str_freq = str(freq) + 'Min' xdf = dh.conv_ohlc_freq(mdf, str_freq) tcost = config['trans_cost'] unit = config['unit'] offset = config['offset'] win = config['win'] pos_class = config['pos_class'] pos_args = config['pos_args'] chan_func = config['channel_func'] upper_chan_func = chan_func[0] lower_chan_func = chan_func[1] entry_chan = win[0] exit_chan = win[1] xdf['H1'] = upper_chan_func(xdf, entry_chan) xdf['L1'] = lower_chan_func(xdf, entry_chan) xdf['H2'] = upper_chan_func(xdf, exit_chan) xdf['L2'] = lower_chan_func(xdf, exit_chan) xdf['ATR'] = dh.ATR(xdf, entry_chan) xdata = pd.concat([xdf['H1'], xdf['L1'], xdf['H2'], xdf['L2'], xdf['ATR'], xdf['high'], xdf['low']], \ axis=1, keys=['H1', 'L1', 'H2', 'L2', 'ATR', 'xhigh', 'xlow']).shift(1) ll = mdf.shape[0] mdf = mdf.join(xdata, how='left').fillna(method='ffill') mdf['pos'] = pd.Series([0] * ll, index=mdf.index) mdf['cost'] = pd.Series([0] * ll, index=mdf.index) curr_pos = [] closed_trades = [] end_d = mdf.index[-1].date() tradeid = 0 for idx, dd in enumerate(mdf.index): mslice = mdf.ix[dd] min_id = mslice.min_id cnt_id = count_min_id(dd) if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, 'pos'] = pos #if np.isnan(mslice.ATR): # continue if (min_id >= config['exit_min']): if (pos != 0) and (dd.date() == end_d): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] pos = 0 mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) continue else: if (pos != 0): if (cnt_id % freq) == 0: curr_pos[0].update_bar(mslice) check_price = (pos > 0) * mslice.low + (pos < 0) * mslice.high if curr_pos[0].check_exit(check_price, 0): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) pos = 0 curr_pos = [] if ((mslice.high >= mslice.H2) and (pos < 0)) or ((mslice.low <= mslice.L2) and (pos > 0)): curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 if ((mslice.high >= mslice.H1) and (pos <= 0)) or ((mslice.low <= mslice.L1) and (pos >= 0)): if (pos == 0): pos = (mslice.high >= mslice.H1) * unit - (mslice.low <= mslice.L1) * unit exit_target = (mslice.high >= mslice.H1) * mslice.L2 + ( mslice.low <= mslice.L1) * mslice.H2 new_pos = pos_class([mslice.contract], [1], pos, mslice.close, exit_target, 1, **pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + misc.sign(pos) * offset, dd) curr_pos.append(new_pos) mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) mdf.ix[dd, 'pos'] = pos return (mdf, closed_trades)
def dual_thrust_sim(mdf, config): close_daily = config["close_daily"] marginrate = config["marginrate"] offset = config["offset"] k = config["k"] f = config["f"] start_equity = config["capital"] win = config["win"] multiplier = config["m"] tcost = config["trans_cost"] unit = config["unit"] SL = config["stoploss"] min_rng = config["min_range"] ma_fast = config["MA_fast"] ll = mdf.shape[0] mdf["min_idx"] = pd.Series(1, index=mdf.index) mdf.loc[mdf["min_id"] < 1500, "min_idx"] = 0 mdf["date_idx"] = mdf.index.date xdf = mdf.groupby([mdf["date_idx"], mdf["min_idx"]]).apply(dh.ohlcsum).reset_index().set_index("datetime") if win == -1: tr = ( pd.concat([xdf.high - xdf.low, abs(xdf.close - xdf.close.shift(1))], join="outer", axis=1) .max(axis=1) .shift(1) ) elif win == -2: tr = pd.rolling_max(xdf.high, 2) - pd.rolling_min(xdf.low, 2) elif win == 0: tr = ( pd.concat( [ (pd.rolling_max(xdf.high, 2) - pd.rolling_min(xdf.close, 2)) * multiplier, (pd.rolling_max(xdf.close, 2) - pd.rolling_min(xdf.low, 2)) * multiplier, xdf.high - xdf.close, xdf.close - xdf.low, ], join="outer", axis=1, ) .max(axis=1) .shift(1) ) else: tr = ( pd.concat( [ pd.rolling_max(xdf.high, win) - pd.rolling_min(xdf.close, win), pd.rolling_max(xdf.close, win) - pd.rolling_min(xdf.low, win), ], join="outer", axis=1, ) .max(axis=1) .shift(1) ) xdf["TR"] = tr xdf["MA"] = pd.rolling_mean(xdf.close, ma_fast).shift(1) ddf = pd.concat( [xdf["TR"], xdf["MA"], xdf["open"], xdf["date_idx"]], axis=1, keys=["TR", "MA", "dopen", "date"] ).fillna(0) mdf = mdf.join(ddf, how="left").fillna(method="ffill") mdf["pos"] = pd.Series([0] * ll, index=mdf.index) mdf["cost"] = pd.Series([0] * ll, index=mdf.index) curr_pos = [] closed_trades = [] start_d = ddf.index[0] end_d = mdf.index[-1].date() # prev_d = start_d - datetime.timedelta(days=1) tradeid = 0 for dd in mdf.index: mslice = mdf.ix[dd] min_id = agent.get_min_id(dd) if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos mdf.ix[dd, "pos"] = pos if mslice.TR == 0 or mslice.MA == 0: continue d_open = mslice.dopen # if (prev_d < d): # d_open = mslice.open # else: # d_open = dslice.open rng = max(min_rng * d_open, k * mslice.TR) if d_open <= 0: continue buytrig = d_open + rng selltrig = d_open - rng if mslice.MA > mslice.close: buytrig += f * rng elif mslice.MA < mslice.close: selltrig -= f * rng if (min_id >= config["exit_min"]) and (close_daily or (mslice.date == end_d)): if pos != 0: curr_pos[0].close(mslice.close - misc.sign(pos) * offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, "cost"] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 else: if (pos != 0) and (SL > 0): curr_pos[0].trail_update(mslice.close) if curr_pos[0].trail_check(mslice.close, SL * mslice.close): curr_pos[0].close(mslice.close - offset * misc.sign(pos), dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, "cost"] -= abs(pos) * (offset + mslice.close * tcost) pos = 0 if (mslice.high >= buytrig) and (pos <= 0): if len(curr_pos) > 0: curr_pos[0].close(mslice.close + offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, "cost"] -= abs(pos) * (offset + mslice.close * tcost) new_pos = strat.TradePos([mslice.contract], [1], unit, mslice.close + offset, mslice.close + offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + offset, dd) curr_pos.append(new_pos) pos = unit mdf.ix[dd, "cost"] -= abs(pos) * (offset + mslice.close * tcost) elif (mslice.low <= selltrig) and (pos >= 0): if len(curr_pos) > 0: curr_pos[0].close(mslice.close - offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, "cost"] -= abs(pos) * (offset + mslice.close * tcost) new_pos = strat.TradePos([mslice.contract], [1], -unit, mslice.close - offset, mslice.close - offset) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close - offset, dd) curr_pos.append(new_pos) pos = -unit mdf.ix[dd, "cost"] -= abs(pos) * (offset + mslice.close * tcost) mdf.ix[dd, "pos"] = pos (res_pnl, ts) = backtest.get_pnl_stats(mdf, start_equity, marginrate, "m") res_trade = backtest.get_trade_stats(closed_trades) res = dict(res_pnl.items() + res_trade.items()) return (res, closed_trades, ts)
def turtle_sim(mdf, config): ddf = config['ddf'] marginrate = config['marginrate'] offset = config['offset'] start_equity = config['capital'] tcost = config['trans_cost'] chan = config['chan'] unit = config['unit'] param = config['param'] max_pos = param[1] max_loss = param[0] ma_ratio = config['ma_ratio'] use_ma = config['use_ma'] chan_func = config['chan_func'] pos_update = config['pos_update'] ddf['ATR'] = dh.ATR(ddf, n=chan[0]).shift(1) ddf['OL_1'] = eval(chan_func['high']['func'])(ddf, chan[0]).shift(1) ddf['OS_1'] = eval(chan_func['low']['func'])(ddf, chan[0]).shift(1) ddf['CL_1'] = eval(chan_func['low']['func'])(ddf, chan[1]).shift(1) ddf['CS_1'] = eval(chan_func['high']['func'])(ddf, chan[1]).shift(1) ddf['MA1'] = dh.MA(ddf, ma_ratio * chan[0]).shift(1) ddf['MA2'] = dh.MA(ddf, chan[1]).shift(1) ll = mdf.shape[0] mdf['pos'] = pd.Series([0] * ll, index=mdf.index) mdf['cost'] = pd.Series([0] * ll, index=mdf.index) curr_pos = [] tradeid = 0 closed_trades = [] end_d = mdf.index[-1].date() curr_atr = 0 for idx, dd in enumerate(mdf.index): mslice = mdf.ix[dd] min_id = mslice.min_id d = mslice.date dslice = ddf.ix[d] tot_pos = sum([trade.pos for trade in curr_pos]) mdf.ix[dd, 'pos'] = tot_pos if np.isnan(dslice.ATR): continue if (min_id >= config['exit_min']): if (tot_pos != 0) and (d == end_d): for trade_pos in curr_pos: trade_pos.close( mslice.close - misc.sign(trade_pos.pos) * offset, dd) tradeid += 1 trade_pos.exit_tradeid = tradeid closed_trades.append(trade_pos) mdf.ix[dd, 'cost'] -= abs( trade_pos.pos) * (offset + mslice.close * tcost) curr_pos = [] tot_pos = 0 else: if tot_pos == 0: curr_atr = dslice.ATR direction = 0 dol = dslice.OL_1 dos = dslice.OS_1 if (mslice.close >= dol) and ((use_ma == False) or (mslice.MA1 >= mslice.MA2)): direction = 1 elif (mslice.close <= dos) and ((use_ma == False) or (mslice.MA1 <= mslice.MA2)): direction = -1 pos = direction * unit if direction != 0: new_pos = strat.TradePos([mslice.contract], [1], pos, mslice.close, mslice.close) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + direction * offset, dd) mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) curr_pos.append(new_pos) else: direction = curr_pos[0].direction #exit position out of channel if (direction == 1 and mslice.close <= dslice.CL_1) or \ (direction == -1 and mslice.close >= dslice.CS_1): for trade_pos in curr_pos: trade_pos.close( mslice.close - misc.sign(trade_pos.pos) * offset, dd) tradeid += 1 trade_pos.exit_tradeid = tradeid closed_trades.append(trade_pos) mdf.ix[dd, 'cost'] -= abs( trade_pos.pos) * (offset + mslice.close * tcost) curr_pos = [] #stop loss position partially elif curr_pos[-1].check_exit(mslice.close, curr_atr * max_loss): for trade_pos in curr_pos: if trade_pos.check_exit(mslice.close, curr_atr * max_loss): trade_pos.close( mslice.close - misc.sign(trade_pos.pos) * offset, dd) tradeid += 1 trade_pos.exit_tradeid = tradeid closed_trades.append(trade_pos) mdf.ix[dd, 'cost'] -= abs(trade_pos.pos) * ( offset + mslice.close * tcost) curr_pos = [ trade for trade in curr_pos if not trade.is_closed ] #add positions elif (len(curr_pos) < max_pos ) and (mslice.close - curr_pos[-1].entry_price ) * direction > curr_atr / max_pos * max_loss: for trade_pos in curr_pos: #trade.exit_target += curr_atr/max_pos*max_loss * direction trade_pos.set_exit(mslice.close) new_pos = strat.TradePos([mslice.contract], [1], direction * unit, mslice.close, mslice.close) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(mslice.close + direction * offset, dd) mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close * tcost) curr_pos.append(new_pos) if (len(curr_pos) > 0) and pos_update: for trade_pos in curr_pos: trade_pos.update_price(mslice.close) mdf.ix[dd, 'pos'] = sum([trade.pos for trade in curr_pos]) return (mdf, closed_trades)
def run_loop_sim(self): sim_data = dh.DynamicRecArray(dataframe=self.df) nlen = len(sim_data) positions = [] closed_trades = [] tradeid = 0 curr_date = None for n in range(nlen - 3): cost = 0 pos = sim_data['pos'][n] if sim_data['ma'][n] == 0 or sim_data['chan_h'][ n] == 0 or sim_data['dopen'][n] == 0: continue if curr_date != sim_data['date'][n]: curr_date = sim_data['date'][n] dopen = sim_data['dopen'][n] rng = max(self.min_rng * dopen, self.k * sim_data['tr'][n]) buytrig = dopen + rng selltrig = dopen - rng if sim_data['ma'][n] > dopen: buytrig += self.f * rng else: selltrig -= self.f * rng continue if self.price_mode == 'TP': ref_long = ref_short = (sim_data['close'][n] + sim_data['high'][n] + sim_data['low'][n]) / 3.0 elif self.price_mode == 'HL': ref_long = sim_data['high'][n] ref_short = sim_data['low'][n] elif self.price_mode == 'CL': ref_long = ref_short = sim_data['close'][n] else: ref_long = ref_short = sim_data['open'][n + 1] target_pos = (ref_long > buytrig) - (ref_short < selltrig) if len(positions) > 0: need_close = (self.close_daily or (curr_date == sim_data['date'][-1])) and ( sim_data['min_id'][n] >= config['exit_min']) for tradepos in positions: ep = sim_data['low'][n] if tradepos.pos > 0 else sim_data[ 'high'][n] if need_close or tradepos.check_exit( sim_data['open'][n + 1], 0) or (tradepos.pos * target_pos < 0): tradepos.close( sim_data['open'][n + 1] - self.offset * misc.sign(tradepos.pos), sim_data['datetime'][n + 1]) tradepos.exit_tradeid = tradeid tradeid += 1 pos -= tradepos.pos cost += abs(tradepos.pos) * ( self.offset + sim_data['open'][n + 1] * self.tcost) closed_trades.append(tradepos) elif self.pos_update: tradepos.update_price(ep) positions = [pos for pos in positions if not pos.is_closed] if need_close: continue if target_pos != 0: if (not self.use_chan) or ( ((ref_long > sim_data['chanh'][n]) and target_pos > 0) or ((ref_short < sim_data['chanl'][n]) and target_pos < 0)): new_pos = self.pos_class( [sim_data['contract'][n]], [1], self.unit * target_pos, sim_data['open'][n + 1] + target_pos * self.offset, buytrig, **self.pos_args) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open( sim_data['open'][n + 1] + target_pos * self.offset, sim_data['datetime'][n + 1]) positions.append(new_pos) pos += self.unit * target_pos cost += abs(target_pos) * ( self.offset + sim_data['open'][n + 1] * self.tcost) sim_data['cost'][n + 1] = cost sim_data['pos'][n + 1] = pos out_df = pd.concat([]) return out_df, closed_trades
end_d = df.index[-1].date() tradeid = 0 for idx, dd in enumerate(df.index): mslice = df.ix[dd] min_id = agent.get_min_id(dd) d = dd.date() if len(curr_pos) == 0: pos = 0 else: pos = curr_pos[0].pos df.ix[dd, 'pos'] = pos if np.isnan(mslice.ma): continue if (min_id >=2054): if (pos!=0) and (d == end_d): curr_pos[0].close(mslice.close - misc.sign(pos) * offset , dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) continue else: if ((mslice.close >= mslice.ma) and (pos<0 )) or (mslice.close <= mslice.ma) and (pos>0 ) : curr_pos[0].close(mslice.close+offset, dd) tradeid += 1 curr_pos[0].exit_tradeid = tradeid closed_trades.append(curr_pos[0]) curr_pos = [] mdf.ix[dd, 'cost'] -= abs(pos) * (offset + mslice.close*tcost) pos = 0