Data - Multiple Timeframes
Sometimes investing decisions are taken using different timeframes:
有時候,投資策略采用不同的時間框架
-
Weekly to evaluate the trend
- 每周的評估趨勢
-
Daily to execute the entry
- 每天執行錄入
Or 5 minutes vs 60 minutes.
或者5分鍾對比60分鍾
That implies that combining datas of multiple timeframes in backtrader
is needed to support such combinations.
這意味着需要在backtrader中組合多個時間段的數據來支持這種配置。
Native support for it is already built-in. The end user must only follow these rules:
平台已經支持該配置,並且內置在系統。終端用戶必須遵守以下規則:
-
The data with the smallest timeframe (and thus the larger number of bars) must be the 1st one to be added to the Cerebro instance
- 具有最小時間幀的數據(因此條數更多)必須是第一個添加到Cerebro實例的數據
-
The datas must be properly date-time aligned for the platform to make any sense out of them
- 數據必須正確地與日期和時間對齊,以便平台能夠理解它們
Beyond that, the end-user is free to apply indicators as wished on the shorter/larger timeframes. Of course:
除此之外,終端用戶可以自由地在較短/較大的時間框架上應用指標。當然,
- Indicators applied to larger timeframes will produce less bars
- 應用於較大時間框架的指標將產生較少的bars
The platform will also have the following into account
該平台還將考慮以下因素
- The minimum period for larger timeframes
- 大時間框架的最小周期
Minimum period which will probably have the side effect of having to consume several orders of magnitude of the smaller timeframe bars before a Strategy added to Cerebro kicks into action.
最小時間周期,這可能會有副作用,在大腦的策略開始行動之前,必須消耗幾個數量級的小時間框架。[重構時間框架要用到]
The built-in cerebro.resample
is going to be used to create a larger timeframe.
內置cerebro.resample將用於創建更大的時間框架。
Some examples below, but first the sauce of the test script.
下面是一些示例,但首先是測試腳本。
# Load the Data datapath = args.dataname or '../../datas/2006-day-001.txt' data = btfeeds.BacktraderCSVData(dataname=datapath) cerebro.adddata(data) # First add the original data - smaller timeframe 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/2006-week-001.txt' data2 = btfeeds.BacktraderCSVData(dataname=datapath) # And then the large timeframe cerebro.adddata(data2) else: cerebro.resampledata(data, timeframe=tframes[args.timeframe], compression=args.compression) # Run over everything cerebro.run()
The steps:
步驟
-
Load a data
- 讀取數據
-
Resample it according to the user specified arguments
The script also allows for loading a 2nd data
- 根據用戶指定的參數重新取樣
該腳本還允許加載第二個數據 -
Add the data to cerebro
- 將數據添加到cerebro
-
Add the resampled data (larger timeframe) to cerebro
- 將重新采樣的數據(更大的時間框架)添加到cerebro
-
run
Example 1 - Daily and Weekly
The invocation of the script:
$ ./multitimeframe-example.py --timeframe weekly --compression 1
轉換成周線
Example 2 - Daily and Daily Compression (2 bars to 1)
The invocation of the script:
$ ./multitimeframe-example.py --timeframe daily --compression 2
And the output chart:
壓縮日線
Example 3 - Strategy with SMA
Although plotting is nice, the key issue here is showing how the larger timeframe influences the system, especially when it comes down to the starting point
雖然繪制很好,但這里的關鍵問題是顯示較大的時間框架如何影響系統,特別是當它到達起點時
The script can take a --indicators
to add a strategy which creates simple moving averages of period 10 on the smaller an larger timeframe datas.
腳本可以采用—給策略添加一個指標,該指標在較小的時間段數據上創建10期的簡單移動平均線。
If only the smaller timeframe was taken into account:
如果只考慮較小的時間框架:
-
next
would be called first after 10 bars, which is the time the Simple Moving Average needs to produce a value -
next將在10個bar之后首先調用,這是簡單移動平均值產生值所需的時間
NOTE: Remember that Strategy monitors created indicators and only calls
next
when all indicators have produced a value. The rationale is that the end user has added the indicators to use them in the logic and thus no logic should take place if the indicators have produced no values - 注意:記住,策略監視創建了指標,只有當所有指標都產生了值時才會調用next。其基本原理是,最終用戶添加了指標以在邏輯中使用它們,因此,如果指標沒有產生任何值,則不應產生邏輯
But in this case the larger timeframe (weekly) delays the invocation of next
until the Simple Moving Average oon the weekly data has produced a value, which takes … 10 weeks.
但在這種情況下,較大的時間范圍(每周)會延遲next的調用,直到每周數據的簡單移動平均值產生值,這需要…10周
The script overrides nextstart
which is only called once and which defaults to calling next
to show when it is first called.[小周期的會覆蓋掉,只會調用一次nextstart]
該腳本覆蓋只調用一次的nextstart,它默認在第一次調用時調用next來顯示。
Invocation 1:
Only the smaller timeframe, daily, gets a Simple Moving Average
只選擇小時間框架日線,取得平均線
The command line and output
$ ./multitimeframe-example.py --timeframe weekly --compression 1 --indicators --onlydaily -------------------------------------------------- nextstart called with len 10 --------------------------------------------------
And the chart.
Invocation 2:
Both timeframes get a Simple Moving Average
The command line:
$ ./multitimeframe-example.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 --------------------------------------------------
Two things to notice here:
這里需要注意兩件事:
-
Instead of being called after 10 periods, the strategy is 1st called after 50 periods.
- 策略不是在10個周期之后調用,而是在50個周期之后第一次調用。
-
It is so because the Simple Moving Average applied on the larger (weekly) timeframe produces a value after 10 weeks … and that is
10 weeks * 5 days / week … 50 days
- 之所以如此,是因為應用於較大(周)時間框架的簡單移動平均線在10周后會產生一個值,即10周* 5天/周…50天
-
nextstart
gets called 5 times rather than only 1. - nextstart被調用5次,而不是只有1次。
-
This is a natural side effect of having mixed the timeframe and having (in this case only one) indicators applied to the larger timeframe.
- 這是混合時間框架和應用於更大時間框架的指標(在本例中只有一個)的自然副作用。
-
The larger timeframe Simple Moving Average produces 5 times the same value whilst 5 daily bars are being consumed.
- 更大的時間框架簡單移動平均線產生5倍的相同的價值,而5條每天被消耗。
-
And because the start of the period is being controlled by the larger timeframe
nextstart
gets called 5 times. - 因為周期的開始是由更大的時間框架控制的,所以nextstart被調用5次。
- 讀取數據幀的時候,還是按照小的數據幀讀取,len(self)也是小的數據幀
And the chart.
還有就是當開始畫SMA之后--compression參數就失效了,實例代碼中的圖也有問題,我這里compression參數變大,大周期的周期就變大了,但案例中是變小
Conclusion
Multiple Timeframe Datas can be used in backtrader
with no special objects or tweaking: just add the smaller timeframes first.
The test script.
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/2006-day-001.txt' data = btfeeds.BacktraderCSVData(dataname=datapath) cerebro.adddata(data) # First add the original data - smaller timeframe 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/2006-week-001.txt' data2 = btfeeds.BacktraderCSVData(dataname=datapath) # 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') return parser.parse_args() if __name__ == '__main__': runstrat()
總結:數據可以直接進去兩個不同的時間序列,系統會自動按照最小序列進行讀取。
可以通過cerebro.resampledata的方法,重采樣原始數據,在輸入數據中會多一份self.data1。
示例中重采樣用的是讀取csv文件,后續如果采用自定義的數據能否重采樣未知。