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 = trade_position.TradePos(insts=[cont], volumes=[1], pos=pos - prev_pos, entry_target=tprice, exit_target=tprice) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(tprice, pos - prev_pos, 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, 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 = trade_position.TradePos(insts=[cont], volumes=[1], pos=pos - prev_pos, entry_target=tprice, exit_target=tprice) tradeid += 1 new_pos.entry_tradeid = tradeid new_pos.open(tprice, pos - prev_pos, 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, 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 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 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