只有當遇到 backtrader 的真實使用者時,人們才能意識到平臺中使用的抽象和Python功能是否有意義。
在不撇開python的座右銘的情況下, backtrader 試圖為使用者提供盡可能多的控制權,同時通過將Python提供的隱藏功能付諸行動來簡化使用。
第一個示例是系列文章的第一篇。
它是一個陣列還是它是什麼?
一個非常簡單的例子:
import backtrader as bt class MyStrategy(bt.Strategy): def __init__(self): self.hi_lo_avg = (self.data.high + self.data.low) / 2.0 def next(self): if self.hi_lo_avg[0] > another_value: print('we have a winner!') ... ... cerebro.addstrategy(MyStrategy) cerebro.run()
其中一個非常迅速彈出的問題是:
- 不能也使用期間
[]
__init__
?。
提出問題是因為用戶已經嘗試過,Python已停止運行,但出現異常。
答案是:
- 不。在
[]
初始化期間不使用。
接下來的問題是:
- 那麼,如果它不是陣列,那麼在期間
__init__
實際存儲self.hi_lo_avg
了什麼呢?
對於程式師來說,答案並不令人費解,但對於使用Python的演算法交易者來說,答案可能很令人困惑。
- 它是一個懶惰評估的物件,它將在階段(
cerebro.run
即:在策略的方法中next
)通過[]
運算元計算和傳遞值。
綜述:在該方法中next
,陣列索引運算子 []
將允許您訪問過去和當前時間時刻的計算值。
秘訣就在醬汁中
操作員覆蓋是真正的調味料。讓我們分解一下 high-low- 平均值的計算:
self.hi_lo_avg = (self.data.high + self.data.low) / 2.0
元件:
self.data.high
並且self.data.low
本身就是物件(backtrader命名方案中的lines)
在許多情況下,它們被錯誤地視為純數位,但事實並非如此。它們成為物件的原因:
-
0
backtrader實施索引-1
計劃和索引計劃 -
控制緩衝區大小調整和連結到其他物件
在這種情況下,最重要的方面是:
- 重寫運算子以返回物件
這就是為什麼下面的操作返回一個 lines 物件。讓我們開始:
temp = self.data.high - self.data.low
然後,將臨時物件除以2.0
成員變數並將其分配給成員變數:
self.hi_lo_avg = temp / 2.0
這將再次返回另一個 lines 物件。因為運算子重寫不僅適用於直接在 lines 對象之間執行的操作,還適用於例如,像這種除法這樣的算術運算。
這意味著 具有self.hi_lo_avg
對 lines 物件的引用。此物件在 next
策略方法中很有用,或者作為指標或其他計算的輸入。
邏輯運算符示例
上面的範例在 中__init__
使用了算術運算子和邏輯操作器的組合[0]
。 >
next
由於運算子重寫不僅限於算術,因此讓我們再舉一個示例,在組合中添加一個指標。第一次嘗試是:
import backtrader as bt class MyStrategy(bt.Strategy): def __init__(self): self.hi_lo_avg = (self.data.high + self.data.low) / 2.0 self.sma = bt.indicators.SMA(period=30) def next(self): if self.hi_lo_avg[0] > self.sma[0]: print('we have a winner!') ... ... cerebro.addstrategy(MyStrategy) cerebro.run()
但是在這種情況下,只需從another_value
更改為 self.sma[0]
。讓我們改進它:
import backtrader as bt class MyStrategy(bt.Strategy): def __init__(self): self.hi_lo_avg = (self.data.high + self.data.low) / 2.0 self.sma = bt.indicators.SMA(period=30) def next(self): if self.hi_lo_avg > self.sma: print('we have a winner!') ... ... cerebro.addstrategy(MyStrategy) cerebro.run()
一個給好人。運算子覆蓋也確實有效next
,用戶實際上可以刪除 [0]
並直接比較物件。
如果所有這一切都是真正可能的,那實際上似乎有點過分了。但好消息是還有更多。請參閱此範例:
import backtrader as bt class MyStrategy(bt.Strategy): def __init__(self): hi_lo_avg = (self.data.high + self.data.low) / 2.0 sma = bt.indicators.SMA(period=30) self.signal = hi_lo_avg > sma def next(self): if self.signal: print('we have a winner!') ... ... cerebro.addstrategy(MyStrategy) cerebro.run()
我們做了兩件事:
-
創建一個名為 lines 物件,該物件
self.signal
將 high-low- 平均值與簡單移動平均值的值進行比較如上所述,當計算出此物件時,此物件在
next
-
在檢查 if
signal
True
時刪除 innext
的使用[0]
。這是可能的,因為布爾運算也覆蓋了運算符
結論
希望這能為執行__init__
操作時實際發生的情況以及運算元重寫的實際發生方式增加一些線索。