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:
When Resampling twice:
I would really appreciate any pointers.
-
1st theory. Check the original chart and see that the platform believes it to have a
timeframe/compression
ofDays/1
(you can read 1 Day). This is because the original creation of theGenericCSVData
has notimeframe/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 desiredtimeframe/compression
or - Manually creating a
DataClone
or your original feed and using it forresampledata
- Creating a 2nd
-
@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()
-
@thatblokedave it works good if the data source is csv,but what happen if the datasource is real time data,may be the return data0 and data1 is not equal