数据 - 多个时间框架
原文:
www.backtrader.com/blog/posts/2015-08-24-data-multitimeframe/data-multitimeframe/
有时,使用不同的时间框架进行投资决策:
- 周线用于评估趋势
- 每日执行进入
或者 5 分钟对比 60 分钟。
这意味着在 backtrader 中需要组合多个时间框架的数据以支持这样的组合。
本地支持已经内置。最终用户只需遵循以下规则:
- 具有最小时间框架的数据(因此是较大数量的条)必须是添加到 Cerebro 实例的第一个数据
- 数据必须正确地对齐日期时间,以便平台能够理解它们的任何含义
此外,最终用户可以自由地在较短/较大的时间框架上应用指标。当然:
- 应用于较大时间框架的指标将产生较少的条
平台也将考虑以下内容
- 较大时间框架的最小周期
最小周期可能会导致在策略添加到 Cerebro 之前需要消耗几个数量级的较小时间框架的数据。
内置的DataResampler
将用于创建较大的时间框架。
一些示例如下,但首先是测试脚本的来源。
# Load the Data datapath = args.dataname or '../datas/sample/2006-day-001.txt' data = btfeeds.BacktraderCSVData( dataname=datapath) tframes = dict( daily=bt.TimeFrame.Days, weekly=bt.TimeFrame.Weeks, monthly=bt.TimeFrame.Months) # Handy dictionary for the argument timeframe conversion # Resample the data if args.noresample: datapath = args.dataname2 or '../datas/sample/2006-week-001.txt' data2 = btfeeds.BacktraderCSVData( dataname=datapath) else: data2 = bt.DataResampler( dataname=data, timeframe=tframes[args.timeframe], compression=args.compression)
步骤:
- 加载数据
- 根据用户指定的参数重新采样它
脚本还允许加载第二个数据 - 将数据添加到 cerebro
- 将重新采样的数据(较大的时间框架)添加到 cerebro
- 运行
示例 1 - 每日和每周
脚本的调用:
$ ./data-multitimeframe.py --timeframe weekly --compression 1
和输出图表:
示例 2 - 日间和日间压缩(2 根变成 1 根)
脚本的调用:
$ ./data-multitimeframe.py --timeframe daily --compression 2
和输出图表:
示例 3 - 带有 SMA 的策略
虽然绘图很好,但这里的关键问题是显示较大的时间框架如何影响系统,特别是当涉及到起始点时
脚本可以采用--indicators
来添加一个策略,该策略在较小时间框架和较大时间框架的数据上创建10 周期的简单移动平均线。
如果只考虑较小的时间框架:
next
将在 10 个条之后首先被调用,这是简单移动平均需要产生值的时间
注意
请记住,策略监视创建的指标,并且只有在所有指标都产生值时才调用next
。理由是最终用户已经添加了指标以在逻辑中使用它们,因此如果指标尚未产生值,则不应进行任何逻辑
但在这种情况下,较大的时间框架(每周)会延迟调用next
,直到每周数据的简单移动平均产生值为止,这需要… 10 周。
脚本覆盖了nextstart
,它只被调用一次,默认调用next
以显示首次调用的时间。
调用 1:
只有较小的时间框架,即每日,才有一个简单移动平均值。
命令行和输出
$ ./data-multitimeframe.py --timeframe weekly --compression 1 --indicators --onlydaily -------------------------------------------------- nextstart called with len 10 --------------------------------------------------
以及图表。
调用 2:
两个时间框架都有一个简单移动平均。
命令行:
$ ./data-multitimeframe.py --timeframe weekly --compression 1 --indicators -------------------------------------------------- nextstart called with len 50 -------------------------------------------------- -------------------------------------------------- nextstart called with len 51 -------------------------------------------------- -------------------------------------------------- nextstart called with len 52 -------------------------------------------------- -------------------------------------------------- nextstart called with len 53 -------------------------------------------------- -------------------------------------------------- nextstart called with len 54 --------------------------------------------------
注意这里的两件事:
- 不是在10个周期之后被调用,而是在 50 个周期之后第一次被调用。
这是因为在较大(周)时间框架上应用简单移动平均值后产生了一个值,… 这是 10 周* 5 天/周… 50 天。 nextstart
被调用了 5 次,而不是仅 1 次。
这是将时间框架混合并(在这种情况下仅有一个)指标应用于较大时间框架的自然副作用。
较大时间框架的简单移动平均值在消耗 5 个日间条时产生 5 倍相同的值。
由于周期的开始由较大的时间框架控制,nextstart
被调用了 5 次。
以及图表。
结论
多时间框架数据可以在backtrader
中使用,无需特殊对象或调整:只需先添加较小的时间框架。
测试脚本。
from __future__ import (absolute_import, division, print_function, unicode_literals) import argparse 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, ) # Load the Data datapath = args.dataname or '../datas/sample/2006-day-001.txt' data = btfeeds.BacktraderCSVData( dataname=datapath) tframes = dict( daily=bt.TimeFrame.Days, weekly=bt.TimeFrame.Weeks, monthly=bt.TimeFrame.Months) # Handy dictionary for the argument timeframe conversion # Resample the data if args.noresample: datapath = args.dataname2 or '../datas/sample/2006-week-001.txt' data2 = btfeeds.BacktraderCSVData( dataname=datapath) else: data2 = bt.DataResampler( dataname=data, timeframe=tframes[args.timeframe], compression=args.compression) # First add the original data - smaller timeframe cerebro.adddata(data) # And then the large timeframe cerebro.adddata(data2) # Run over everything cerebro.run() # Plot the result cerebro.plot(style='bar') def parse_args(): parser = argparse.ArgumentParser( description='Pandas test script') 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') return parser.parse_args() if __name__ == '__main__': runstrat()
数据重新取样
原文:
www.backtrader.com/blog/posts/2015-08-23-data-resampling/data-resampling/
当数据仅在一个时间段可用,而分析必须针对不同的时间段进行时,就是时候进行一些重新取样了。
“重新取样”实际上应该称为“向上取样”,因为要从一个源时间段转换到一个较大的时间段(例如:从天到周)
“向下采样”目前还不可能。
backtrader
通过将原始数据传递给一个智能命名为 DataResampler
的过滤器对象来支持重新取样。
该类具有两个功能:
- 更改时间框架
- 压缩条柱
为此,DataResampler
在构造过程中使用标准的 feed.DataBase
参数:
timeframe
(默认:bt.TimeFrame.Days)
目标时间段必须与源时间段相等或更大才能有用compression
(默认:1)
将所选值 “n” 压缩到 1 条柱
让我们看一个从每日到每周的手工脚本示例:
$ ./data-resampling.py --timeframe weekly --compression 1
输出结果:
我们可以将其与原始每日数据进行比较:
$ ./data-resampling.py --timeframe daily --compression 1
输出结果:
这是通过执行以下步骤来完成的魔术:
- 像往常一样加载数据
- 将数据馈送到具有所需的
DataResampler
中
- 时间框架
- 压缩
示例代码(底部的整个脚本)。
# Load the Data datapath = args.dataname or '../datas/sample/2006-day-001.txt' data = btfeeds.BacktraderCSVData( dataname=datapath) # Handy dictionary for the argument timeframe conversion tframes = dict( daily=bt.TimeFrame.Days, weekly=bt.TimeFrame.Weeks, monthly=bt.TimeFrame.Months) # Resample the data data_resampled = bt.DataResampler( dataname=data, timeframe=tframes[args.timeframe], compression=args.compression) # Add the resample data instead of the original cerebro.adddata(data_resampled)
最后一个例子中,我们首先将时间框架从每日更改为每周,然后应用 3 到 1 的压缩:
$ ./data-resampling.py --timeframe weekly --compression 3
输出结果:
从原始的 256 个每日条柱变为 18 个 3 周条柱。具体情况如下:
- 52 周
- 52 / 3 = 17.33 因此为 18 条柱
这不需要太多。当然,分钟数据也可以进行重新取样。
重新取样测试脚本的示例代码。
from __future__ import (absolute_import, division, print_function, unicode_literals) import argparse import backtrader as bt import backtrader.feeds as btfeeds def runstrat(): args = parse_args() # Create a cerebro entity cerebro = bt.Cerebro(stdstats=False) # Add a strategy cerebro.addstrategy(bt.Strategy) # Load the Data datapath = args.dataname or '../datas/sample/2006-day-001.txt' data = btfeeds.BacktraderCSVData( dataname=datapath) # Handy dictionary for the argument timeframe conversion tframes = dict( daily=bt.TimeFrame.Days, weekly=bt.TimeFrame.Weeks, monthly=bt.TimeFrame.Months) # Resample the data data_resampled = bt.DataResampler( dataname=data, timeframe=tframes[args.timeframe], compression=args.compression) # Add the resample data instead of the original cerebro.adddata(data_resampled) # Run over everything cerebro.run() # Plot the result cerebro.plot(style='bar') def parse_args(): parser = argparse.ArgumentParser( description='Pandas test script') 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('--compression', default=1, required=False, type=int, help='Compress n bars into 1') return parser.parse_args() if __name__ == '__main__': runstrat()
BackTrader 中文文档(二十七)(2)https://developer.aliyun.com/article/1505478