Resampling data twice - Dual Timeframe



  • Hello all,
    I am trying to re-sample minute data into two timeframes I am interested in working on. When I copy the code from the documentation here:

    https://www.backtrader.com/docu/data-multitimeframe/data-multitimeframe.html

    All is good and it works well. However, the example only resamples the data once. In the code, it adds the first data without resampling and then adds the second resampled data.

    I have tried to resample the data twice and the result is the higher TF is not plotted on the graph. I would appreciate it if someone could show me how I should go about this. I am sure it is something I am missing.

    Here is my code: (mostly the same as the example)

    from __future__ import (absolute_import, division, print_function,
                            unicode_literals)
    
    import argparse
    import datetime
    import backtrader as bt
    import backtrader.feeds as btfeeds
    import backtrader.indicators as btind
    
    
    class SMAStrategy(bt.Strategy):
        params = (
            ('period', 10),
            ('onlydaily', False),
        )
    
        def __init__(self):
            self.sma_small_tf = btind.SMA(self.data, period=self.p.period)
            if not self.p.onlydaily:
                self.sma_large_tf = btind.SMA(self.data1, period=self.p.period)
    
        def nextstart(self):
            print('--------------------------------------------------')
            print('nextstart called with len', len(self))
            print('--------------------------------------------------')
    
            super(SMAStrategy, self).nextstart()
    
    
    def runstrat():
        args = parse_args()
    
        # Create a cerebro entity
        cerebro = bt.Cerebro(stdstats=False)
    
        # Add a strategy
        if not args.indicators:
            cerebro.addstrategy(bt.Strategy)
        else:
            cerebro.addstrategy(
                SMAStrategy,
    
                # args for the strategy
                period=args.period,
                onlydaily=args.onlydaily,
            )
    
    
        tframes = dict(minutes=bt.TimeFrame.Minutes,daily=bt.TimeFrame.Days, weekly=bt.TimeFrame.Weeks,
                       monthly=bt.TimeFrame.Months)
    
    
        # Get the dates from the args
        fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
        todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
    
        # Load the Data
        datapath = args.dataname or '../../datas/2006-day-001.txt'
        data = bt.feeds.GenericCSVData(
        dataname=datapath,
        nullvalue=0.0,
        dtformat=('%m/%d/%Y'),
        tmformat=('%H:%M:%S'),
        fromdate=fromdate,
        todate=todate,
        datetime=0,
        time=1,
        high=3,
        low=4,
        open=2,
        close=5,
        volume=6,
        openinterest=-1 #-1 means not used
        )
        #cerebro.adddata(data)  # First add the original data - smaller timeframe
        cerebro.resampledata(data, timeframe=tframes['minutes'],
                             compression=60)
    
    
        # Handy dictionary for the argument timeframe conversion
        # Resample the data
        if args.noresample:
            datapath = args.dataname2 or '../../datas/2006-week-001.txt'
            data2 = data = bt.feeds.GenericCSVData(
            dataname=datapath,
            nullvalue=0.0,
            dtformat=('%m/%d/%Y'),
            tmformat=('%H:%M:%S'),
            fromdate=fromdate,
            todate=todate,
            datetime=0,
            time=1,
            high=3,
            low=4,
            open=2,
            close=5,
            volume=6,
            openinterest=-1 #-1 means not used
            )
            # And then the large timeframe
            cerebro.adddata(data2)
        else:
            cerebro.resampledata(data, timeframe=tframes[args.timeframe],
                                 compression=args.compression)
    
        # Run over everything
        cerebro.run()
    
        # Plot the result
        cerebro.plot(style='bar')
    
    
    def parse_args():
        parser = argparse.ArgumentParser(
            description='Multitimeframe test')
    
        parser.add_argument('--dataname', default='', required=False,
                            help='File Data to Load')
    
        parser.add_argument('--dataname2', default='', required=False,
                            help='Larger timeframe file to load')
    
        parser.add_argument('--noresample', action='store_true',
                            help='Do not resample, rather load larger timeframe')
    
        parser.add_argument('--timeframe', default='weekly', required=False,
                            choices=['daily', 'weekly', 'monhtly'],
                            help='Timeframe to resample to')
    
        parser.add_argument('--compression', default=1, required=False, type=int,
                            help='Compress n bars into 1')
    
        parser.add_argument('--indicators', action='store_true',
                            help='Wether to apply Strategy with indicators')
    
        parser.add_argument('--onlydaily', action='store_true',
                            help='Indicator only to be applied to daily timeframe')
    
        parser.add_argument('--period', default=10, required=False, type=int,
                            help='Period to apply to indicator')
        parser.add_argument('--fromdate', '-f',
                            required=True,
                            help='Starting date in YYYY-MM-DD format')
    
        parser.add_argument('--todate', '-t',
                            required=True,
                            help='Ending date in YYYY-MM-DD format')
    
        return parser.parse_args()
    
    
    if __name__ == '__main__':
        runstrat()
    

    And this is what I get for output:

    When resampling once:
    0_1487738217007_reample once.png

    When Resampling twice:
    0_1487738235256_resample twice.png

    I would really appreciate any pointers.


  • administrators

    1st theory. Check the original chart and see that the platform believes it to have a timeframe/compression of Days/1(you can read 1 Day). This is because the original creation of the GenericCSVData has no timeframe/compression specified.

    But most probably this is due to the current implementation model. If you have read the Community - v1.x -Quick Roadmap post, you may have seen that the plan is to change resampling back to the original model rather than have it implemented as a filter. If the 1st theory fails, there would be 2 options

    • Creating a 2nd GenericCSVData and resampling it to the desired timeframe/compression
      or
    • Manually creating a DataClone or your original feed and using it for resampledata


  • @backtrader , thank you for the pointer.

    Setting the timeframe/compression in the GenericCSVData data seemed to do the trick. I missed that it can be set there in the documents.

    It also sorted out the issue with the chart showing "Days" in the minute data.

    I had to do as you suggested, create 2 separate GenericCSVData instances and re-sample each.

    Really appreciate the help. You saved me a lot of head scratching.



  • For reference if anyone has a similar issue and comes here through google, here is the cleaned up working version

    from __future__ import (absolute_import, division, print_function,
                            unicode_literals)
    
    import argparse
    import datetime
    import backtrader as bt
    import backtrader.feeds as btfeeds
    import backtrader.indicators as btind
    
    
    class SMAStrategy(bt.Strategy):
        params = (
            ('period', 10),
            ('onlydaily', False),
        )
    
        def __init__(self):
            self.sma_small_tf = btind.SMA(self.data, period=self.p.period)
            if not self.p.onlydaily:
                self.sma_large_tf = btind.SMA(self.data1, period=self.p.period)
    
        def nextstart(self):
            print('--------------------------------------------------')
            print('nextstart called with len', len(self))
            print('--------------------------------------------------')
    
            super(SMAStrategy, self).nextstart()
    
    
    def runstrat():
        args = parse_args()
    
        # Create a cerebro entity
        cerebro = bt.Cerebro(stdstats=False)
    
        # Add a strategy
        if not args.indicators:
            cerebro.addstrategy(bt.Strategy)
        else:
            cerebro.addstrategy(
                SMAStrategy,
    
                # args for the strategy
                period=args.period,
                onlydaily=args.onlydaily,
            )
    
    
        tframes = dict(minutes=bt.TimeFrame.Minutes,daily=bt.TimeFrame.Days, weekly=bt.TimeFrame.Weeks,
                       monthly=bt.TimeFrame.Months)
    
    
        # Get the dates from the args
        fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
        todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
    
        # Load the Data
        datapath = args.dataname or '../../datas/2006-day-001.txt'
        data = bt.feeds.GenericCSVData(
        dataname=datapath,
        nullvalue=0.0,
        dtformat=('%m/%d/%Y'),
        tmformat=('%H:%M:%S'),
        timeframe = tframes[args.ltf_resample],
        compression = args.ltf_comp,
        fromdate=fromdate,
        todate=todate,
        datetime=0,
        time=1,
        high=3,
        low=4,
        open=2,
        close=5,
        volume=6,
        openinterest=-1 #-1 means not used
        )
    
        cerebro.resampledata(data, timeframe=tframes[args.ltf_resample],
                             compression=args.ltf_comp)
    
    
        # Handy dictionary for the argument timeframe conversion
        # Resample the data
    
        data2 = bt.feeds.GenericCSVData(
        dataname=datapath,
        nullvalue=0.0,
        timeframe = tframes[args.htf_resample],
        compression = args.htf_comp,
        dtformat=('%m/%d/%Y'),
        tmformat=('%H:%M:%S'),
        fromdate=fromdate,
        todate=todate,
        datetime=0,
        time=1,
        high=3,
        low=4,
        open=2,
        close=5,
        volume=6,
        openinterest=-1 #-1 means not used
        )
    
        cerebro.resampledata(data2, timeframe=tframes[args.htf_resample],
                             compression=args.htf_comp)
    
        # Run over everything
        cerebro.run()
    
        # Plot the result
        cerebro.plot(style='bar')
    
    
    def parse_args():
        parser = argparse.ArgumentParser(
            description='Multitimeframe test')
    
        parser.add_argument('--dataname', default='', required=False,
                            help='File Data to Load')
    
        parser.add_argument('--timeframe', default='weekly', required=False,
                            choices=['daily', 'weekly', 'monhtly'],
                            help='Timeframe to resample to')
    
        parser.add_argument('--indicators', action='store_true',
                            help='Wether to apply Strategy with indicators')
    
        parser.add_argument('--ltf_comp', default=1, type=int,
                            help='Compression setting for lower time frame resampling')
    
        parser.add_argument('--ltf_resample', required=True,
                            help='resample data for LTF. Valid\
                             intervals:\n monthly\n weekly\n daily\n minutes')
    
        parser.add_argument('--htf_comp', default=1, type=int,
                            help='Compression setting for higher time frame resampling')
    
        parser.add_argument('--htf_resample', required=True,
                            help='resample data for HTF. Valid\
                             intervals:\n monthly\n weekly\n daily\n minutes')
    
        parser.add_argument('--period', default=10, required=False, type=int,
                            help='Period to apply to indicator')
    
        parser.add_argument('--fromdate', '-f',
                            required=True,
                            help='Starting date in YYYY-MM-DD format')
    
        parser.add_argument('--todate', '-t',
                            required=True,
                            help='Ending date in YYYY-MM-DD format')
    
        return parser.parse_args()
    
    
    if __name__ == '__main__':
        runstrat()
    
    

Log in to reply
 

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