For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

Back Testing two time frame with large time frame candle partially created



  • We are trying to back-test out strategy with two time frame 5 Min and 1 Hour . As per following documentation i can do by passing two time frame data .
    https://www.backtrader.com/docu/data-multitimeframe/data-multitimeframe/

    But Large time frame is getting updated when candle completely formed what i want. I need to access 1 Hour candle partially created and what is indicator value for current hourly candle . Is that possible . I am new to backtrader so just trying to figure it out . any help would be really appreciated



  • @bhavishya-goyal said in Back Testing two time frame with large time frame candle partially created:

    But Large time frame is getting updated when candle completely formed what i want. I need to access 1 Hour candle partially created and what is indicator value for current hourly candle .

    Are you looking for the the indicator value on the 5 minute data then?



  • @run-out yes you are right



  • @run-out Hi, ay i request to please help if that is possible



  • @bhavishya-goyal said in Back Testing two time frame with large time frame candle partially created:

    But Large time frame is getting updated when candle completely formed what i want. I need to access 1 Hour candle partially created and what is indicator value for current hourly candle . Is that possible . I am new to backtrader so just trying to figure it out . any help would be really appreciated

    You can access indicators in both time frames. You input two datalines with the smaller timeframe first. Create an indicator for each time frame, and then you can access the information in each indicator at the shortest timeframe. If you implement the following:

    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()
    

    You get output like:

    2020-01-08 11:00:00, sma small 3232.25,  sma large 3228.93
    2020-01-08 11:05:00, sma small 3231.62,  sma large 3228.93
    2020-01-08 11:10:00, sma small 3231.40,  sma large 3228.93
    2020-01-08 11:15:00, sma small 3231.45,  sma large 3228.93
    2020-01-08 11:20:00, sma small 3231.78,  sma large 3228.93
    2020-01-08 11:25:00, sma small 3232.12,  sma large 3228.93
    2020-01-08 11:30:00, sma small 3232.78,  sma large 3228.93
    2020-01-08 11:35:00, sma small 3233.35,  sma large 3228.93
    2020-01-08 11:40:00, sma small 3234.75,  sma large 3228.93
    2020-01-08 11:45:00, sma small 3236.50,  sma large 3228.93
    2020-01-08 11:50:00, sma small 3238.25,  sma large 3228.93
    2020-01-08 11:55:00, sma small 3240.20,  sma large 3228.93
    2020-01-08 12:00:00, sma small 3241.55,  sma large 3229.22
    2020-01-08 12:05:00, sma small 3243.00,  sma large 3229.22
    2020-01-08 12:10:00, sma small 3244.22,  sma large 3229.22
    2020-01-08 12:15:00, sma small 3245.40,  sma large 3229.22
    2020-01-08 12:20:00, sma small 3246.28,  sma large 3229.22
    2020-01-08 12:25:00, sma small 3247.45,  sma large 3229.22
    2020-01-08 12:30:00, sma small 3248.03,  sma large 3229.22
    2020-01-08 12:35:00, sma small 3247.97,  sma large 3229.22
    2020-01-08 12:40:00, sma small 3247.75,  sma large 3229.22
    2020-01-08 12:45:00, sma small 3247.40,  sma large 3229.22
    2020-01-08 12:50:00, sma small 3247.53,  sma large 3229.22
    2020-01-08 12:55:00, sma small 3247.45,  sma large 3229.22
    2020-01-08 13:00:00, sma small 3247.43,  sma large 3229.74
    2020-01-08 13:05:00, sma small 3247.55,  sma large 3229.74
    2020-01-08 13:10:00, sma small 3247.43,  sma large 3229.74
    2020-01-08 13:15:00, sma small 3247.28,  sma large 3229.74
    2020-01-08 13:20:00, sma small 3246.97,  sma large 3229.74
    2020-01-08 13:25:00, sma small 3246.82,  sma large 3229.74
    2020-01-08 13:30:00, sma small 3246.85,  sma large 3229.74
    2020-01-08 13:35:00, sma small 3246.90,  sma large 3229.74
    2020-01-08 13:40:00, sma small 3246.88,  sma large 3229.74
    2020-01-08 13:45:00, sma small 3246.82,  sma large 3229.74
    2020-01-08 13:50:00, sma small 3246.75,  sma large 3229.74
    2020-01-08 13:55:00, sma small 3246.57,  sma large 3229.74
    2020-01-08 14:00:00, sma small 3246.43,  sma large 3230.25
    2020-01-08 14:05:00, sma small 3246.45,  sma large 3230.25
    2020-01-08 14:10:00, sma small 3246.62,  sma large 3230.25
    


  • @run-out Thanks but issue is large time frame SMA should be updated in each 5 min as well since close price of last candle(Present 1 Hour candle which is being constructed ) is getting changed with each 5 minute data and that should change SMA as well for Hourly data.



  • I could be mistaken, but I don't think the one hour candle is 'being constructed'. It just gets constructed at the end of the hour. For what you are trying to do I think you would need to code a custom indicator that builds the one hour candle every five minutes and starts over every hour?



  • @run-out If we talk about Live trading every candle is continuously getting update like on each 5min or 1 min, hourly candle would have new high,low,close so basically i want to use latest value of current hourly candle so any indicator can be applied on that .

    If I build custom indicator then for each indicator i need to change



  • As @run-out said, if you just inspect the resampled hourly data every 5 minutes - you will see the same old bar until the next hour bar will be available.

    However, theoretically, you are right - the resampled bar is updated every time the underlying data is updated (and not only in live trading). The only thing is that this update is kept in internal implementation and is not easily accessible.

    TL;DR

    Inside the Backtrader framework resampling is implemented using filters.

    So when the resampledata method is used, like in your code:

    cerebro.resampledata(data, timeframe=bt.TimeFrame.Minutes, compression=5)
    

    what actually happens is that a special filter - Resampler is added to the data.

    Multiple filters could be attached to the data - so the Resampler filter is just one such filter.

    The accumulated resampled bar is maintained as an internal state of such a filter. So in order to access this bar, you actually need to dive deeply into the private state of the Resampler filter - but first, you need to find it among other filters.

    The internals of the Resampler filter is not documented since the framework author probably does not see a good reason to support your use case.



  • @bhavishya-goyal I found this to be an interesting question and made a custom indicator for it.

    import argparse
    from collections import deque
    
    import backtrader as bt
    import backtrader.feeds as btfeeds
    
    
    class SMAExpand(bt.Indicator):
        """
        Custom indicator for hourly simple moving average, expanding with each bar in the hour.
        Period must divide into an hour and be minimum of the resample
        :param compression: The compression used for the minute data in the datafeed. e.g. 5 minutes.
        :param period: number of hours to use in the SMA.
        :result sma_large: Simple moving average line.
        """
    
        lines = ("sma_large",)
    
        def __init__(self, compression=5, period=10):
            self.compression = compression
            self.period = period
            self.addminperiod = self.period
    
            self.hourly_close = deque([], maxlen=int(self.period - 1))
            self.close = self.datas[0].close
    
        def next(self):
            # Current bar datetime, time.
            dt = self.data.datetime[0]
            if isinstance(dt, float):
                dt = bt.num2date(dt)
            minutes = dt.minute
    
            if len(self.hourly_close) >= self.period - 1:
                self.l.sma_large[0] = (sum(self.hourly_close) + self.close[0]) / self.period
    
            if minutes == 0:
                self.hourly_close.append(self.close[0])
    
    class Strategy(bt.Strategy):
        params = dict(compression=5, period=30)
    
        def __init__(self):
            print(f"check params: {self.p.period}")
            self.sma_expand = SMAExpand(compression=self.p.compression, period=self.p.period)
            self.sma_hour = bt.ind.SMA(self.datas[1], period=self.p.period)
    
        def log(self, txt, dt=None):
            """ Logging function for this strategy"""
            dt = dt or self.data.datetime[0]
            if isinstance(dt, float):
                dt = bt.num2date(dt)
            print("%s, %s" % (dt, txt))
    
        def print_signal(self):
            """Print to terminal ohlcv."""
            self.log(
                "o {} \th {} \tl {} \tc {}\tv {}".format(
                    self.datas[0].open[0],
                    self.datas[0].high[0],
                    self.datas[0].low[0],
                    self.datas[0].close[0],
                    self.datas[0].volume[0],
                )
            )
    
        def next(self):
            # self.print_signal()
            self.log(
                f"close {self.sma_expand.close[0]:8.2f}, "
                f"\tsma expand {self.sma_expand.sma_large[0]:8.2f}"
                f"\tsma hour {self.sma_hour[0]:8.2f}"
            )
    
    def runstrat(args=None):
        args = parse_args(args)
    
        cerebro = bt.Cerebro()
    
        cerebro.addstrategy(Strategy, compression=args.compression, period=args.period)
    
        # Data feed kwargs
        kwargs = dict(
            dataname=args.data0,
            timeframe=bt.TimeFrame.Minutes,
            compression=1,
            format="%Y-%m-%d %H:%M:%S",
            datetime=0,
            time=-1,
            open=3,
            high=1,
            low=2,
            close=4,
            cumvol=5,
            volume=6,
        )
    
        data = btfeeds.GenericCSVData(**kwargs)
    
        cerebro.resampledata(data, timeframe=bt.TimeFrame.Minutes, compression=args.compression)
        cerebro.resampledata(data, timeframe=bt.TimeFrame.Minutes, compression=60)
    
        cerebro.run()
    
    def parse_args(pargs=None):
        parser = argparse.ArgumentParser(
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            description=(
                'Cheat-On-Open Sample'
            )
        )
    
        parser.add_argument('--data0', default='data/dev.csv',
                            required=False, help='Data to read in')
    
        parser.add_argument('--period', type=int, required=False, default=30, help='Lookback period for sma integer in hours.')
        parser.add_argument('--compression', type=int, required=False, default=5, help='Main data compression.')
    
        return parser.parse_args(pargs)
    
    
    if __name__ == "__main__":
        runstrat()
    
    


  • @run-out Here's some output for the above indicator.

    2020-01-08 11:00:00, close  3231.25, 	sma expand  3228.93	sma hour  3228.93
    2020-01-08 11:05:00, close  3230.75, 	sma expand  3228.68	sma hour  3228.93
    2020-01-08 11:10:00, close  3233.25, 	sma expand  3228.77	sma hour  3228.93
    2020-01-08 11:15:00, close  3234.00, 	sma expand  3228.79	sma hour  3228.93
    2020-01-08 11:20:00, close  3235.50, 	sma expand  3228.84	sma hour  3228.93
    2020-01-08 11:25:00, close  3234.50, 	sma expand  3228.81	sma hour  3228.93
    2020-01-08 11:30:00, close  3238.75, 	sma expand  3228.95	sma hour  3228.93
    2020-01-08 11:35:00, close  3236.00, 	sma expand  3228.86	sma hour  3228.93
    2020-01-08 11:40:00, close  3242.75, 	sma expand  3229.08	sma hour  3228.93
    2020-01-08 11:45:00, close  3248.25, 	sma expand  3229.27	sma hour  3228.93
    2020-01-08 11:50:00, close  3248.75, 	sma expand  3229.28	sma hour  3228.93
    2020-01-08 11:55:00, close  3250.25, 	sma expand  3229.33	sma hour  3228.93
    2020-01-08 12:00:00, close  3246.75, 	sma expand  3229.22	sma hour  3229.22
    2020-01-08 12:05:00, close  3248.50, 	sma expand  3229.78	sma hour  3229.22
    2020-01-08 12:10:00, close  3247.75, 	sma expand  3229.75	sma hour  3229.22
    2020-01-08 12:15:00, close  3246.25, 	sma expand  3229.70	sma hour  3229.22
    2020-01-08 12:20:00, close  3247.50, 	sma expand  3229.74	sma hour  3229.22
    2020-01-08 12:25:00, close  3247.75, 	sma expand  3229.75	sma hour  3229.22
    2020-01-08 12:30:00, close  3248.50, 	sma expand  3229.78	sma hour  3229.22
    2020-01-08 12:35:00, close  3247.75, 	sma expand  3229.75	sma hour  3229.22
    2020-01-08 12:40:00, close  3246.50, 	sma expand  3229.71	sma hour  3229.22
    2020-01-08 12:45:00, close  3246.75, 	sma expand  3229.72	sma hour  3229.22
    2020-01-08 12:50:00, close  3248.00, 	sma expand  3229.76	sma hour  3229.22
    2020-01-08 12:55:00, close  3247.75, 	sma expand  3229.75	sma hour  3229.22
    2020-01-08 13:00:00, close  3247.50, 	sma expand  3229.74	sma hour  3229.74
    2020-01-08 13:05:00, close  3247.50, 	sma expand  3230.34	sma hour  3229.74
    2020-01-08 13:10:00, close  3246.25, 	sma expand  3230.30	sma hour  3229.74
    2020-01-08 13:15:00, close  3246.25, 	sma expand  3230.30	sma hour  3229.74
    2020-01-08 13:20:00, close  3245.50, 	sma expand  3230.28	sma hour  3229.74
    2020-01-08 13:25:00, close  3246.25, 	sma expand  3230.30	sma hour  3229.74
    2020-01-08 13:30:00, close  3246.75, 	sma expand  3230.32	sma hour  3229.74
    2020-01-08 13:35:00, close  3247.25, 	sma expand  3230.33	sma hour  3229.74
    2020-01-08 13:40:00, close  3247.75, 	sma expand  3230.35	sma hour  3229.74
    2020-01-08 13:45:00, close  3247.25, 	sma expand  3230.33	sma hour  3229.74
    2020-01-08 13:50:00, close  3246.75, 	sma expand  3230.32	sma hour  3229.74
    2020-01-08 13:55:00, close  3245.75, 	sma expand  3230.28	sma hour  3229.74
    2020-01-08 14:00:00, close  3244.75, 	sma expand  3230.25	sma hour  3230.25
    2020-01-08 14:05:00, close  3246.50, 	sma expand  3230.72	sma hour  3230.25
    


  • @run-out Thanks for that. Can this be made generic so it can work with any indicator ? With this i have to create new indicator for each Indicator .

    Another thing can we call one indicator from other indicator ?



  • You can definitely call one indicator from another indicator. Just treat it like a 'data line' in your new indicator.


Log in to reply
 

});