Filtering out ticks in strategy.next()



  • @backtrader
    What is the appropriate way to filter out ticks for instruments that I am not trading off of in strategy.next()?

    I am getting multiple executions on a strategy with two different datasets. Case where the logic of the entries are still true when a signaling (or reference data) tick is coming through strategy.next().

    I've tried something like the following, but that has the effect of turning off all logic processing after that point for any tick.

    if self.data._name == 'BLAH': 
        return
    

  • administrators

    Your scripts show use of resampledata, which implies and therefore data feed is signaled by means of a change in the len of the data feed.

    A potential approach:

    • Create an array during __init__ or start with a 0 for each of the data feeds: for example self.dl = [0] * len(self.datas)
    • Create a temporary equivalent on entry to next with actual lens: dl = [len(d) for d in self.datas]
    • Check which ones have actually changed: dlnew = [x - y for x, y in zip(dl, self.dl)]
    • Get the indices to it: dlidx = [i for i, x in enumerate(dlnew) if x]
    • Keep actual lenghts: self.dl = dl

    Now dlidx contains the indices to the data feeds which have changed. since the last call to next



  • @backtrader
    So I have implemented your suggestion and it seems to accomplish the goal. I've added the following bit of code in strategy.next() to return if the current tick is not for the instrument I am using to execute the strategy.

    # looking for ticks on data1 (SPY)
    if self.datas[dlidx[0]]._name != 'SPY':
        return
    

    Was that the intended way to apply this?



  • @backtrader any comment on the appropriate use of the conditional above?

    It seems now that I am not letting ticks past this point while live trading, but it works as expected in running a backtest with static data.

    Here again is the conditional I put in place:

            # looking for ticks on data1 (SPY)
            if self.datas[dlidx[0]]._name != 'SPY':
                return
    

  • administrators

    The conditional as written will probably miss things. Rationale:

    • The approach is meant to gather the indices into the datas array for all data feeds whose length has changed

    • That means that the array dlidx[] will have a varying length, from 1 to n (where n is equal to len(self.datas))

    If several data feeds deliver a tick simultaneously and seeing in the code that SPY is data1, dlidx, could contain for example [0, 1]. The test would effectively be doing self.datas[0]._name != 'SPY', which will fail because SPY is data1 (aka self.datas[1])

    You would need to traverse the dlidx array to see if any of the indices points to your SPY data.



  • Maybe I am doing something very wrong as I continue to struggle to solve my use case, which I would expect to be fairly common.

    I have datas 0,1 and 2.

    data0 = daily timeframe of X symbol
    data1 = minute timeframe of Y symbol
    data2 = daily timeframe of Y symbol

    I want to apply trade execution logic in next() to values presented by data0 and execute trades on data1 if the logic conditions are met at the closing bar values for data0. (I'm using data2 to feed the Sizer FWIW)

    if buysignal:
        self.buy(data1)
    elif sellsignal:
        self.sell(data1)
    else:
       "trade entry signals not met"
    

    In order to prevent an entry or exit to be executed before the closing bar for data0 is seen (since data1 ticks are flowing through every minute), I must put some time check in this logic to filter out ticks for data1 seen before the close of data0, or some way to exclude the data feed itself from that logic.

    If relying on the bar time, I still run the risk of sending duplicate orders for the 16:00 bar on data0 and data1.

    So it seems common that we would need to be able to easily filter out ticks we don't want to evaluate logic for trade execution. Unless I am missing the obvious which is possible...

    This goes back to my comments about a need to put certain data in classification "reference" to avoid seeing it in next(). In this example, I would put data1 and data2 in "reference" classification so I know that values seen in next() are those that I care about. Since it is daily timeframe, I know that any bar I see I must evaluate the trade logic and thereby avoid filters for time and dataname.

    Am I missing something?



  • So this is where I am at at this point to try to accomplish this goal. Is there a cleaner way?

            # looking for ticks on data1 (SPY)
            dlist = []
            for i in iter(dlidx):
                dlist.append(self.datas[dlidx[i - 1]]._name)
    
            if 'SPY' not in dlist:
                return
    
            if self.p.live:
                mclose = dt.datetime.combine(dt.datetime.today().date(),
                                             dt.time(16, 0))
                bartime = self.data.datetime.datetime(tz=EST)
                print('%s == %s', (bartime, mclose))
                if bartime != mclose:
                    return
    

  • administrators

    Iterating over dlidx and then checking dlidx[i - 1] seems odd.

    dlist = [self.datas[i]._name for i in dlidx]
    

    The above could should actually suffice (although it's not shown how dlidx is actually generated)



  • My hack above worked today, so I will take your much more elegant bit of python and replace a few lines. My python foo is still a bit green... Thanks!


Log in to reply
 

Looks like your connection to Backtrader Community was lost, please wait while we try to reconnect.