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 instrategy.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
-
Your scripts show use of
resampledata
, which implies and therefore data feed is signaled by means of a change in thelen
of the data feed.A potential approach:
- Create an array during
__init__
orstart
with a0
for each of the data feeds: for exampleself.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 tonext
- Create an array during
-
@backtrader
So I have implemented your suggestion and it seems to accomplish the goal. I've added the following bit of code instrategy.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
-
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, from1
ton
(wheren
is equal tolen(self.datas)
)
If several data feeds deliver a tick simultaneously and seeing in the code that
SPY
isdata1
,dlidx
, could contain for example[0, 1]
. The test would effectively be doingself.datas[0]._name != 'SPY'
, which will fail becauseSPY
isdata1
(akaself.datas[1]
)You would need to traverse the
dlidx
array to see if any of the indices points to yourSPY
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 symbolI want to apply trade execution logic in
next()
to values presented bydata0
and execute trades ondata1
if the logic conditions are met at the closing bar values fordata0
. (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 fordata1
seen before the close ofdata0
, 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
anddata1
.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 putdata1
anddata2
in "reference" classification so I know that values seen innext()
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
-
Iterating over
dlidx
and then checkingdlidx[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!