def process_data(self, df):
     if (self.data_freq == 'm') and (self.freq > 1):
         xdf = self.proc_func(df, **self.proc_args)
     else:
         xdf = df
     for i in range(len(self.channel)):
         xdf['chan_h' + str(i)] = self.chan_high(
             xdf, self.channel[i],
             **self.chan_func['high']['args']).shift(1)
         xdf['chan_l' + str(i)] = self.chan_low(
             xdf, self.channel[i], **self.chan_func['low']['args']).shift(1)
     xdf['ATR'] = dh.ATR(xdf, n=self.SL_win).shift(1).fillna(method='bfill')
     xdf.ix[:, 'tr_stop_h'] = xdf.ix[:, 'chan_h0'] - (
         xdf.ix[:, 'ATR'] * self.SL /
         self.tick_base).astype('int') * self.tick_base
     xdf.ix[:, 'tr_stop_l'] = xdf.ix[:, 'chan_l0'] + (
         xdf.ix[:, 'ATR'] * self.SL /
         self.tick_base).astype('int') * self.tick_base
     xdf['long_exit'] = pd.concat([xdf['chan_l1'], xdf['tr_stop_h']],
                                  join='outer',
                                  axis=1).max(axis=1)
     xdf['short_exit'] = pd.concat([xdf['chan_h1'], xdf['tr_stop_l']],
                                   join='outer',
                                   axis=1).min(axis=1)
     if (self.data_freq == 'm') and (self.freq > 1):
         xdf = df.join(
             xdf[['long_exit', 'short_exit', 'chan_h0', 'chan_l0']],
             how='left').fillna(method='ffill')
     self.df = xdf.dropna().copy()
Esempio n. 2
0
 def process_data(self, mdf):
     if self.freq == 1:
         xdf = mdf
     else:
         freq_str = str(self.freq) + "min"
         xdf = dh.conv_ohlc_freq(mdf, freq_str, extra_cols=['contract'])
     xdf['ATR'] = dh.ATR(xdf, n=self.atr_len)
     xdf['ATRMA'] = dh.MA(xdf, n=self.atrma_len, field='ATR')
     xdf['RSI'] = dh.RSI(xdf, n=self.rsi_len)
     self.df = xdf
     self.df['datetime'] = self.df.index
     self.df['cost'] = 0.0
     self.df['pos'] = 0.0
     self.df['traded_price'] = self.df['open']
Esempio n. 3
0
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']
    offset = config['offset']
    win = config['win']
    chan_func = config['channel_func']
    upper_chan_func = eval(chan_func[0])
    lower_chan_func = eval(chan_func[1])
    entry_chan = win[0]
    exit_chan = win[1]
    exit_min = config.get('exit_min', 2057)
    close_daily = config.get('close_daily', False)
    stoploss = config.get('stoploss', 2.0)
    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']], \
                      axis=1, keys=['H1', 'L1', 'H2', 'L2', 'ATR']).shift(1)
    mdf = mdf.join(xdata, how='left').fillna(method='ffill')
    mdf['close_ind'] = np.isnan(mdf['close'].shift(-3))
    if close_daily:
        mdf['close_ind'] = (mdf['min_id'] >= exit_min) | mdf['close_ind']
    long_signal = pd.Series(np.nan, index=mdf.index)
    long_signal[(mdf['open'] >= mdf['H1'])] = 1
    long_signal[(mdf['open'] <= mdf['L2'])] = 0
    if stoploss > 0:
        long_signal[(mdf['open'] <= mdf['H1'] - mdf['ATR'] * stoploss)] = 0
    long_signal[mdf['close_ind']] = 0
    long_signal = long_signal.fillna(method='ffill').fillna(0)
    short_signal = pd.Series(np.nan, index=mdf.index)
    short_signal[(mdf['open'] <= mdf['L1'])] = -1
    short_signal[(mdf['open'] >= mdf['H2'])] = 0
    if stoploss > 0:
        short_signal[(mdf['open'] >= mdf['L1'] + mdf['ATR'] * stoploss)] = 0
    short_signal[mdf['close_ind']] = 0
    short_signal = short_signal.fillna(method='ffill').fillna(0)
    mdf['pos'] = long_signal + short_signal
    mdf['cost'] = abs(mdf['pos'] - mdf['pos'].shift(1)) * (offset +
                                                           mdf['open'] * tcost)
    mdf['cost'] = mdf['cost'].fillna(0.0)
    mdf['traded_price'] = mdf.open + (mdf['pos'] -
                                      mdf['pos'].shift(1)) * offset
    closed_trades = backtest.simdf_to_trades1(mdf, slippage=offset)
    return (mdf, closed_trades)
Esempio n. 4
0
 def process_data(self, mdf):
     xdf = self.proc_func(mdf, **self.proc_args)
     if self.win == -1:
         tr = pd.concat(
             [xdf.high - xdf.low,
              abs(xdf.close - xdf.close.shift(1))],
             join='outer',
             axis=1).max(axis=1)
     elif self.win == 0:
         tr = pd.concat(
             [(pd.rolling_max(xdf.high, 2) - pd.rolling_min(xdf.close, 2)) *
              self.multiplier,
              (pd.rolling_max(xdf.close, 2) - pd.rolling_min(xdf.low, 2)) *
              self.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, self.win) -
             pd.rolling_min(xdf.close, self.win),
             pd.rolling_max(xdf.close, self.win) -
             pd.rolling_min(xdf.low, self.win)
         ],
                        join='outer',
                        axis=1).max(axis=1)
     xdf['TR'] = tr
     xdf['chanh'] = self.chan_high(xdf['high'], self.chan,
                                   **self.chan_func['high']['args'])
     xdf['chanl'] = self.chan_low(xdf['low'], self.chan,
                                  **self.chan_func['low']['args'])
     xdf['ATR'] = dh.ATR(xdf, n=self.atr_len)
     xdf['MA'] = dh.MA(xdf, n=self.atr_len, field='close')
     xdata = pd.concat([
         xdf['TR'].shift(1), xdf['MA'].shift(1), xdf['ATR'].shift(1),
         xdf['chanh'].shift(1), xdf['chanl'].shift(1), xdf['open']
     ],
                       axis=1,
                       keys=['tr', 'ma', 'atr', 'chanh', 'chanl',
                             'dopen']).fillna(0)
     self.df = mdf.join(xdata, how='left').fillna(method='ffill')
     self.df['datetime'] = self.df.index
     self.df['cost'] = 0
     self.df['pos'] = 0
     self.df['traded_price'] = self.df['open']
Esempio n. 5
0
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(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)
Esempio n. 7
0
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)
Esempio n. 8
0
 def run_vec_sim(self):
     xdf = self.proc_func(self.df, **self.proc_args)
     if self.win == -1:
         tr = pd.concat(
             [xdf.high - xdf.low,
              abs(xdf.close - xdf.close.shift(1))],
             join='outer',
             axis=1).max(axis=1)
     elif self.win == 0:
         tr = pd.concat(
             [(pd.rolling_max(xdf.high, 2) - pd.rolling_min(xdf.close, 2)) *
              self.multiplier,
              (pd.rolling_max(xdf.close, 2) - pd.rolling_min(xdf.low, 2)) *
              self.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, self.win) -
             pd.rolling_min(xdf.close, self.win),
             pd.rolling_max(xdf.close, self.win) -
             pd.rolling_min(xdf.low, self.win)
         ],
                        join='outer',
                        axis=1).max(axis=1)
     xdf['tr'] = tr
     xdf['chan_h'] = self.chan_high(xdf, self.chan,
                                    **self.chan_func['high']['args'])
     xdf['chan_l'] = self.chan_low(xdf, self.chan,
                                   **self.chan_func['low']['args'])
     xdf['atr'] = dh.ATR(xdf, self.machan)
     xdf['ma'] = pd.rolling_mean(xdf.close, self.machan)
     xdf['rng'] = pd.DataFrame(
         [self.min_rng * xdf['open'], self.k * xdf['tr'].shift(1)]).max()
     xdf['upper'] = xdf['open'] + xdf['rng'] * (
         1 + (xdf['open'] < xdf['ma'].shift(1)) * self.f)
     xdf['lower'] = xdf['open'] - xdf['rng'] * (
         1 + (xdf['open'] > xdf['ma'].shift(1)) * self.f)
     xdata = pd.concat([
         xdf['upper'], xdf['lower'], xdf['chan_h'].shift(1),
         xdf['chan_l'].shift(1), xdf['open']
     ],
                       axis=1,
                       keys=['upper', 'lower', 'chan_h', 'chan_l',
                             'xopen']).fillna(0)
     mdf = self.df.join(xdata, how='left').fillna(method='ffill')
     mdf['dt_signal'] = np.nan
     if self.price_mode == "HL":
         up_price = mdf['high']
         dn_price = mdf['low']
     elif self.price_mode == "TP":
         up_price = (mdf['high'] + mdf['low'] + mdf['close']) / 3.0
         dn_price = up_price
     elif self.price_mode == "CL":
         up_price = mdf['close']
         dn_price = mdf['close']
     else:
         print "unsupported price mode"
     mdf.ix[up_price >= mdf['upper'], 'dt_signal'] = 1
     mdf.ix[dn_price <= mdf['lower'], 'dt_signal'] = -1
     if self.close_daily:
         mdf.ix[mdf['min_id'] >= self.exit_min, 'dt_signal'] = 0
     addon_signal = copy.deepcopy(mdf['dt_signal'])
     mdf['dt_signal'] = mdf['dt_signal'].fillna(method='ffill').fillna(0)
     mdf['chan_sig'] = np.nan
     if combo_signal:
         mdf.ix[(up_price >= mdf['chan_h']) & (addon_signal > 0),
                'chan_sig'] = 1
         mdf.ix[(dn_price <= mdf['chan_l']) & (addon_signal < 0),
                'chan_sig'] = -1
     else:
         mdf.ix[(mdf['high'] >= mdf['chan_h']), 'chan_sig'] = 1
         mdf.ix[(mdf['low'] <= mdf['chan_l']), 'chan_sig'] = -1
     mdf['chan_sig'] = mdf['chan_sig'].fillna(method='ffill').fillna(0)
     pos = mdf['dt_signal'] * (
         self.unit[0] +
         (mdf['chan_sig'] * mdf['dt_signal'] > 0) * self.unit[1])
     mdf['pos'] = pos.shift(1).fillna(0)
     mdf.ix[-3:, 'pos'] = 0
     mdf['cost'] = abs(mdf['pos'] - mdf['pos'].shift(1)) * (
         self.offset + mdf['open'] * self.tcost)
     mdf['cost'] = mdf['cost'].fillna(0.0)
     mdf['traded_price'] = mdf['open']
     self.closed_trades = backtest.simdf_to_trades1(mdf,
                                                    slippage=self.offset)
     return mdf, self.closed_trades
Esempio n. 9
0
def dual_thrust_sim(mdf, config):
    close_daily = config['close_daily']
    price_mode = config.get('mode', "HL")
    offset = config['offset']
    k = config['param'][0]
    win = config['param'][1]
    multiplier = config['param'][2]
    f = config['param'][3]
    combo_signal = config['combo_signal']
    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']
    machan = config['machan']
    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['atr'] = dh.ATR(xdf, machan)
    xdf['ma'] = pd.rolling_mean(xdf.close, machan)
    xdf['rng'] = pd.DataFrame([min_rng * xdf['open'],
                               k * xdf['tr'].shift(1)]).max()
    xdf['upper'] = xdf['open'] + xdf['rng'] * (
        1 + (xdf['open'] < xdf['ma'].shift(1)) * f)
    xdf['lower'] = xdf['open'] - xdf['rng'] * (
        1 + (xdf['open'] > xdf['ma'].shift(1)) * f)
    xdata = pd.concat([
        xdf['upper'], xdf['lower'], xdf['chan_h'].shift(1),
        xdf['chan_l'].shift(1), xdf['open']
    ],
                      axis=1,
                      keys=['upper', 'lower', 'chan_h', 'chan_l',
                            'xopen']).fillna(0)
    mdf = mdf.join(xdata, how='left').fillna(method='ffill')
    mdf['dt_signal'] = np.nan
    if price_mode == "HL":
        up_price = mdf['high']
        dn_price = mdf['low']
    elif price_mode == "TP":
        up_price = (mdf['high'] + mdf['low'] + mdf['close']) / 3.0
        dn_price = up_price
    elif price_mode == "CL":
        up_price = mdf['close']
        dn_price = mdf['close']
    else:
        print "unsupported price mode"
    mdf.ix[up_price >= mdf['upper'], 'dt_signal'] = 1
    mdf.ix[dn_price <= mdf['lower'], 'dt_signal'] = -1
    if close_daily:
        mdf.ix[mdf['min_id'] >= config['exit_min'], 'dt_signal'] = 0
    addon_signal = copy.deepcopy(mdf['dt_signal'])
    mdf['dt_signal'] = mdf['dt_signal'].fillna(method='ffill').fillna(0)
    mdf['chan_sig'] = np.nan
    if combo_signal:
        mdf.ix[(up_price >= mdf['chan_h']) & (addon_signal > 0),
               'chan_sig'] = 1
        mdf.ix[(dn_price <= mdf['chan_l']) & (addon_signal < 0),
               'chan_sig'] = -1
    else:
        mdf.ix[(mdf['high'] >= mdf['chan_h']), 'chan_sig'] = 1
        mdf.ix[(mdf['low'] <= mdf['chan_l']), 'chan_sig'] = -1
    mdf['chan_sig'] = mdf['chan_sig'].fillna(method='ffill').fillna(0)
    pos = mdf['dt_signal'] * (
        unit[0] + (mdf['chan_sig'] * mdf['dt_signal'] > 0) * unit[1])
    mdf['pos'] = pos.shift(1).fillna(0)
    mdf.ix[-3:, 'pos'] = 0
    mdf['cost'] = abs(mdf['pos'] - mdf['pos'].shift(1)) * (offset +
                                                           mdf['open'] * tcost)
    mdf['cost'] = mdf['cost'].fillna(0.0)
    mdf['traded_price'] = mdf['open']
    closed_trades = backtest.simdf_to_trades1(mdf, slippage=offset)
    return (mdf, closed_trades)
Esempio n. 10
0
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)
Esempio n. 11
0
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)
Esempio n. 12
0
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)