《backtrader》的發佈1.9.27.105
糾正了一個疏忽。這是一個疏忽,因為拼圖的所有部分都已到位,但啟動並不是在所有角落都進行的。
該機制使用一個名為的屬性_mindatas
,因此讓我們將其稱為: mindatas
。
社區問了這個問題,答案並不是很到位。請參閱此處的對話:
即使談話是關於其他事情的,這個問題也可以很快得到回答:「嘿,它實際上應該有效!但是,這些天誰有時間考慮一個適當而周到的答案。
讓我們考慮一個交叉一個普通的舊數字參數的用例。類似的東西
mycrossover = bt.ind.CrossOver(bt.ind.RSI(), 50.0)
哪個會像
Traceback (most recent call last): File "./cross-over-num.py", line 114, in <module> runstrat() File "./cross-over-num.py", line 70, in runstrat cerebro.run(**eval('dict(' + args.cerebro + ')')) File "d:\dro\01-docs\01-home\src\backtrader\backtrader\cerebro.py", line 810, in run runstrat = self.runstrategies(iterstrat) File "d:\dro\01-docs\01-home\src\backtrader\backtrader\cerebro.py", line 878, in runstrategies strat = stratcls(*sargs, **skwargs) File "d:\dro\01-docs\01-home\src\backtrader\backtrader\metabase.py", line 87, in __call__ _obj, args, kwargs = cls.doinit(_obj, *args, **kwargs) File "d:\dro\01-docs\01-home\src\backtrader\backtrader\metabase.py", line 77, in doinit _obj.__init__(*args, **kwargs) File "./cross-over-num.py", line 35, in __init__ bt.ind.CrossOver(bt.ind.RSI(), 50) File "d:\dro\01-docs\01-home\src\backtrader\backtrader\indicator.py", line 53, in __call__ return super(MetaIndicator, cls).__call__(*args, **kwargs) File "d:\dro\01-docs\01-home\src\backtrader\backtrader\metabase.py", line 87, in __call__ _obj, args, kwargs = cls.doinit(_obj, *args, **kwargs) File "d:\dro\01-docs\01-home\src\backtrader\backtrader\metabase.py", line 77, in doinit _obj.__init__(*args, **kwargs) Typeerror: __init__() takes exactly 1 argument (2 given)
作為 last line 最翔實的,因為它告訴我們,有些東西有太多的論據。這意味著他們正在50.0
傷害我們。
為了解決手頭的問題,給出了一個數位包裝器作為答案。
class ConstantValue(bt.Indicator): lines = ('constant',) params = (('constant', float('NaN')),) def next(self): self.lines.constant[0] = self.p.constant ... mycrossover = bt.ind.CrossOver(bt.ind.RSI(), ConstantValue(50.0))
問題解決了。但是等等,解決方案已經在船上了。有一個內部幫手,要解決問題,就完全忘記了:LineNum
它做了這個名字試圖暗示的事情:取一個數位,並使其成為一個 line。問題解決方案就在那裡,解決方案可能看起來像這樣:
mycrossover = bt.ind.CrossOver(bt.ind.RSI(), bt.LineNum(50.0))
通常的背景線程無論如何都在滴答作響,告訴某些東西仍然不是100%清晰,解決方案應該是顯而易見的,而無需使用者指定包裝器。
這就是疏忽。即使該mindatas
機制存在並應用於回聲系統的某些部分,它也沒有應用於 CrossOver
。它嘗試過,但人類有時會失敗得很慘,認為他們做了一些事情只是為了發現,他們沒有進一步向下滾動。事實也的確如此。一個 line 添加,如下所示:
class CrossOver(Indicator): ... _mindatas = 2 ...
現在,這個問題的解決方案很簡單:
mycrossover = bt.ind.CrossOver(bt.ind.RSI(), 50.0)
它應該一直處於第1位 的方式(請參閱下面的範例和圖表)
mindatas
在工作中
這是一個方便的屬性,旨在用於特定情況,因此是前導_
,以指示應非常謹慎地使用它。指標的預設值為:
-
_mindatas = 1
這告訴系統,如果沒有數據源 傳遞給指標,系統應從父級複製第 1個 數據源。如果沒有這個,例如實例化應該
RelativeStrengthIndicator
像這樣完成:class Strategy(bt.Indicator): def __init__(self): rsi = bt.ind.RSI(self.data0)
但是,使用 給出
_mindatas
的預設指示,以下情況是可能的:class Strategy(bt.Indicator): def __init__(self): rsi = bt.ind.RSI()
結果完全相同,因為策略
self.data0
中的第1個數據源被傳遞給RSI
像這樣的CrossOver
指標需要 2 data feeds,因為它正在檢查一個事物是否正在交叉另一個事物。在本例中,如上所示,預設值已設置為:
_mindatas = 2
這告訴系統如下內容:
-
如果未傳遞任何資料,則從父級複製 2 data feeds (如果可能)
-
如果僅傳遞了 1 個數據,請嘗試將下一個傳入參數轉換為 lines 物件,以便有 2 個 data feeds 可用。Usseful用於 line 穿越普通舊花車的用例。再次供參考:
mycrossover = bt.ind.CrossOver(bt.ind.RSI(), 50.0)
-
如果傳遞到
CrossOver
2 個或更多data feeds,則不執行任何操作並繼續進行
在社區中,該機制最近已被應用於例如1st 草圖以實現 KalmanFilter
對交易。當談論配對時,需要2個 data feeds 並使用它: _mindatas = 2
一個小樣本(儘管有完整的骨架)來測試完整的解決方案:
$ ./cross-over-num.py --plot
哪個輸出這個。
示例用法
$ ./cross-over-num.py --help usage: cross-over-num.py [-h] [--data0 DATA0] [--fromdate FROMDATE] [--todate TODATE] [--cerebro kwargs] [--broker kwargs] [--sizer kwargs] [--strat kwargs] [--plot [kwargs]] Sample Skeleton optional arguments: -h, --help show this help message and exit --data0 DATA0 Data to read in (default: ../../datas/2005-2006-day-001.txt) --fromdate FROMDATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: ) --todate TODATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: ) --cerebro kwargs kwargs in key=value format (default: ) --broker kwargs kwargs in key=value format (default: ) --sizer kwargs kwargs in key=value format (default: ) --strat kwargs kwargs in key=value format (default: ) --plot [kwargs] kwargs in key=value format (default: )
示例代碼
from __future__ import (absolute_import, division, print_function, unicode_literals) import argparse import datetime import backtrader as bt class St(bt.Strategy): params = () def __init__(self): bt.ind.CrossOver(bt.ind.RSI(), 50) def next(self): pass def runstrat(args=None): args = parse_args(args) cerebro = bt.Cerebro() # Data feed kwargs kwargs = dict() # Parse from/to-date dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S' for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']): if a: strpfmt = dtfmt + tmfmt * ('T' in a) kwargs[d] = datetime.datetime.strptime(a, strpfmt) # Data feed data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs) cerebro.adddata(data0) # Broker cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')')) # Sizer cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')')) # Strategy cerebro.addstrategy(St, **eval('dict(' + args.strat + ')')) # Execute cerebro.run(**eval('dict(' + args.cerebro + ')')) if args.plot: # Plot if requested to cerebro.plot(**eval('dict(' + args.plot + ')')) def parse_args(pargs=None): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter, description=( 'Sample Skeleton' ) ) parser.add_argument('--data0', default='../../datas/2005-2006-day-001.txt', required=False, help='Data to read in') # Defaults for dates parser.add_argument('--fromdate', required=False, default='', help='Date[time] in YYYY-MM-DD[THH:MM:SS] format') parser.add_argument('--todate', required=False, default='', help='Date[time] in YYYY-MM-DD[THH:MM:SS] format') parser.add_argument('--cerebro', required=False, default='', metavar='kwargs', help='kwargs in key=value format') parser.add_argument('--broker', required=False, default='', metavar='kwargs', help='kwargs in key=value format') parser.add_argument('--sizer', required=False, default='', metavar='kwargs', help='kwargs in key=value format') parser.add_argument('--strat', required=False, default='', metavar='kwargs', help='kwargs in key=value format') parser.add_argument('--plot', required=False, default='', nargs='?', const='{}', metavar='kwargs', help='kwargs in key=value format') return parser.parse_args(pargs) if __name__ == '__main__': runstrat()