Is there a way to differentiate 2 streams of sampled data in the next function ?
-
Hello All,
Imagine you have something that looks like that:
import backtrader as bt import backtrader.feeds as btfeeds import backtrader.indicators as btind class TimeFrameStrategy(bt.Strategy): def __init__(self): self.sma_small_tf = btind.SMA(self.data, period=10) self.sma_large_tf = btind.SMA(self.data1, period=30) def next(self): print("{}, sma small {:.2f}, sma large {:.2f}".format(self.data.datetime.datetime(), self.sma_small_tf[0], self.sma_large_tf[0])) def runstrat(): cerebro = bt.Cerebro() cerebro.addstrategy(TimeFrameStrategy) datapath = "data/dev.csv" data = btfeeds.GenericCSVData( dataname=datapath, timeframe=bt.TimeFrame.Minutes, compression=1, format="%Y-%m-%d %H:%M:%S", ) cerebro.resampledata(data, timeframe=bt.TimeFrame.Minutes, compression=5) cerebro.resampledata(data, timeframe=bt.TimeFrame.Minutes, compression=60) cerebro.run() if __name__ == "__main__": runstrat()
How can one handle the data differently based on the sampled compression ?
For instance, I might want to use the 60min for executing trades and the 5min candle for stoploss.Any help would be appreciated!
-
A more concrete example is having 1 SMA and needing to write logic that's different based on the compression you're viewing
-
You may examine the
self.data.p.compression
and base your logic accordingly. -
thanks for the reply! unfortunately self.data.p.compression always returns the shorter timeframe
2017-08-18 00:00:00, EMA PRICE 4357.05, CLOSE PRICE 4286.53, TIME FRAME : 60 2017-08-18 01:00:00, EMA PRICE 4346.73, CLOSE PRICE 4243.59, TIME FRAME : 60 2017-08-18 02:00:00, EMA PRICE 4339.54, CLOSE PRICE 4267.59, TIME FRAME : 60 2017-08-18 03:00:00, EMA PRICE 4335.25, CLOSE PRICE 4292.39, TIME FRAME : 60 2017-08-18 04:00:00, EMA PRICE 4330.95, CLOSE PRICE 4287.92, TIME FRAME : 60 2017-08-18 05:00:00, EMA PRICE 4329.37, CLOSE PRICE 4313.56, TIME FRAME : 60 2017-08-18 06:00:00, EMA PRICE 4324.83, CLOSE PRICE 4279.46, TIME FRAME : 60 2017-08-18 07:00:00, EMA PRICE 4322.60, CLOSE PRICE 4300.25, TIME FRAME : 60 2017-08-18 08:00:00, EMA PRICE 4318.97, CLOSE PRICE 4282.73, TIME FRAME : 60 2017-08-18 09:00:00, EMA PRICE 4317.62, CLOSE PRICE 4304.15, TIME FRAME : 60 2017-08-18 10:00:00, EMA PRICE 4321.14, CLOSE PRICE 4356.31, TIME FRAME : 60 2017-08-18 11:00:00, EMA PRICE 4322.88, CLOSE PRICE 4340.31, TIME FRAME : 60 2017-08-18 12:00:00, EMA PRICE 4323.69, CLOSE PRICE 4331.71, TIME FRAME : 60 2017-08-18 13:00:00, EMA PRICE 4320.90, CLOSE PRICE 4293.09, TIME FRAME : 60 2017-08-18 14:00:00, EMA PRICE 4315.31, CLOSE PRICE 4259.40, TIME FRAME : 60 2017-08-18 15:00:00, EMA PRICE 4308.18, CLOSE PRICE 4236.89, TIME FRAME : 60 2017-08-18 16:00:00, EMA PRICE 4302.93, CLOSE PRICE 4250.34, TIME FRAME : 60 2017-08-18 17:00:00, EMA PRICE 4292.96, CLOSE PRICE 4193.35, TIME FRAME : 60 2017-08-18 18:00:00, EMA PRICE 4277.00, CLOSE PRICE 4117.41, TIME FRAME : 60 2017-08-18 19:00:00, EMA PRICE 4264.21, CLOSE PRICE 4136.28, TIME FRAME : 60 2017-08-18 20:00:00, EMA PRICE 4242.11, CLOSE PRICE 4021.11, TIME FRAME : 60 2017-08-18 21:00:00, EMA PRICE 4217.89, CLOSE PRICE 3975.69, TIME FRAME : 60 2017-08-18 22:00:00, EMA PRICE 4208.42, CLOSE PRICE 4113.75, TIME FRAME : 60 2017-08-18 23:00:00, EMA PRICE 4199.33, CLOSE PRICE 4108.37, TIME FRAME : 60 2017-08-19 00:00:00, EMA PRICE 4196.07, CLOSE PRICE 4163.49, TIME FRAME : 60 2017-08-19 01:00:00, EMA PRICE 4191.75, CLOSE PRICE 4148.53, TIME FRAME : 60 2017-08-19 02:00:00, EMA PRICE 4188.53, CLOSE PRICE 4156.39, TIME FRAME : 60
-
correction: the longer timeframe
-
In case you have multiple data feeds (not indicators) - you may examine each one:
self.datas[0].p.compresson
,self.datas[1].p.compression
....In case of indicator, examining the compression of the underlying data feed could be more involved, since indicator may use another indicator as it underlying data.
-
this doesn't work, won't tell you anything about the current tick compression
-
after you add datas to
cerebro
they are accessible in the strategy in the same sequence.say, you added non-resampled data, then added data resampled to
compression_1
, then added data resampled tocompression_2
. in the strategyself.datas[0]
will be non-resampled data,self.datas[1]
will be the data resampled tocompression_1
, andself.datas[2]
will be the data resampled tocompression_2
.@joeyy said in Is there a way to differentiate 2 streams of sampled data in the next function ?:
For instance, I might want to use the 60min for executing trades and the 5min candle for stoploss.
bt
treats all datafeeds separately even they can be for the same ticker. so if you want to open the trade on one data feed, than stop loss or closing order should be applied on the same data feed. otherwise you will have bunch of open trades on both data feeds. -
thank you ab_trader!
your answer got me most of the way. I can split the logic in my next function based on the index of the self.datas object.
There is one caveat though. If I want to compare the indicator's value to one of the timeframe, it will get evaluated for every tick, and might satisfy a greater than / less than condition in the wrong tick. In other words, if I have an SMA, and 2 candles: one is 5min, the other 60min, and I want to buy based on the SMA cross with the 60min candle, it will still get checked every 5min and the SMA will change in every iteration. Therefore I might be making trades without waiting for the 60min tick.I solved it by adding a flag that checks if the slow indicator value has changed, which stays the same for every fast tick, i.e -
if(self.last_candle_ref_price != self.data1.lines.close[0]): if self.sma.lines.sma[0] < self.data1.lines.close[0]: <do something> self.last_candle_ref_price = self.data1.lines.close[0]
-
next()
is called on both timeframes, so at certain point you have twonext()
calls at the same time - one for 5 min and one for 60 min data feed. i believebt
author proposed to compare length of the strategy and length of the data feeds in order to define what time framenext()
is called. i am not able to find the link, but t was somewhere in the docs or in the blog posts.yiour approach can be broken in rare cases when the indicator doesn't changes the value due to prices go steady, for example. approach using lengths seems to me more reliable.
-
That makes sense, I do wish to replace my hack with something more sustainable. Perhaps the link you were looking for was this one -
https://community.backtrader.com/topic/1329/how-to-determine-if-the-data-is-being-replayed-in-strategy -
i didn't find the link, but the idea is to track length of the 60 min data feed. when it changes, it means that one hour bar completed and next bar started. try to do the following in the
next()
and you will see the pattern:print(len(self.data0), self.data0.close[0], len(self.data1), self.data1.close[0])
where
data0
id 5 min data anddata1
is min data. -
this is def. better, thanks!