目錄
0,序
1,BackTrader名額特性
2,名額的繪制
3,名額開發
4,耦合不同時間機關的資料
0,序
名額可以說是對原始資料的預處理,從原始資料無法發現的特征,現象;往往通過對資料進行一定的處理産生一些特别的名額才能顯現出來。比如移動均值,MACD,RSI,布林帶等等。絕大部分的政策都會用到一些特定的名額,特别是一些核心名額對于政策來說是至關重要。BackTrader有一套特有的名額開發方式,開發起來很友善,運作效率也很高。
1,BackTrader名額特性
由于名額是服務于政策的,是以名額一般都是聲明在政策内部。
名額主要存在于BackTrader政策的兩個函數内,__init__()和next()。
在__init__()内,名額會被預計算成line,并且所有對名額的計算都會産生一條新的line。
在next()内,名額以line的形式被通路使用,并且對名額的計算不會産生line,而是産生普通的數值。
hilo_diff = self.data.high - self.data.low
sma = bt.SimpleMovingAverage(self.data.close)
close_sma_diff = self.data.close - sma
close_over_sma = self.data.close > sma
以上三個例子都運作在__init__()中,hilo_diff,close_sma_diff,close_over_sma都是名額,并且是line形式的
相應地,在next()中運作如下代碼
close_over_sma = self.data.close > self.sma
close_over_sma就隻是一個布爾數值
這麼設計的一個好處是,節省了next運作期間的運算壓力。可以看如下的例子
class MyStrategy(bt.Strategy):
def __init__(self):
sma1 = btind.SimpleMovingAverage(self.data)
ema1 = btind.ExponentialMovingAverage()
close_over_sma = self.data.close > sma1
close_over_ema = self.data.close > ema1
sma_ema_diff = sma1 - ema1
buy_sig = bt.And(close_over_sma, close_over_ema, sma_ema_diff > 0)
def next(self):
if buy_sig:
self.buy()
購買的信号也在__init__()中預計算完成,在next()隻做判斷。這樣顯著提高了整個回測的運作效率。
2,名額的繪制
預設的情況下BackTrader會把名額顯示在cerebro.plot ()輸出圖像上,除了布爾型的名額。如果希望顯示布爾型的名額,可以如下操作
close_over_sma = self.data.close > self.sma
LinePlotterIndicator(close_over_sma, name='Close_over_SMA')
當通過繼承Indicator開發名額子類時,可以聲明plotinfo用于控制名額圖像。plotinfo接受元祖的元祖或字典的方式傳參。
class MyIndicator(bt.Indicator):
....
plotinfo = dict(subplot=False)
....
“subplot ”可以通過如下方式進行設定
myind = MyIndicator(self.data, someparam=value)
myind.plotinfo.subplot = True
myind = MyIndicator(self.data, someparams=value, subplot=True)
plotinfo支援以下參數:
- plot (default: True):名額是否需要繪制
- subplot (default: True):是否在其他視窗中繪制名額。
- plotname (default: ''):設定要在繪圖上顯示的繪圖名稱。空值表示将使用名額的規範名稱(class .__ name__)。
- plotabove (default: False):名額通常在其操作的資料下方繪制(帶有subplot = True的名額)。該設定為True将使名額繪制在資料上方。
- plotlinelabels (default: False):标簽顯示生成該名額的源名額。
- plotymargin(預設值:0.0):頂部和底部的留白
- plotyticks (default: []):y軸刻度
- plothlines (default: []):繪制水準線
- plotyhlines (default: []):同時控制plotyticks和plothlines
3,名額開發
開發一個自己的名額基本流程如下:
- 從Indicator基類(或它的子類)進行繼承
- 定義需要的lines
- 一個名額類至少包含一條line,如果被繼承的名額已經有line則可省略
- (可選)定義可修改的參數
- (可選)定義一些參數修改名額的預設繪制
- 在__init__()中提供一個操作,并綁定到名額的line,或者提供next()或once()方法
下面就第6點的三種方式,舉例說明:
class DummyInd(bt.Indicator):
lines = ('dummyline',)
params = (('value', 5),)
def __init__(self):
self.lines.dummyline = bt.Max(0.0, self.params.value)
名額資料的生成在__init__函數内
class DummyInd(bt.Indicator):
lines = ('dummyline',)
params = (('value', 5),)
def next(self):
self.lines.dummyline[0] = max(0.0, self.params.value)
這個例子的效果跟上面那個一樣,隻是資料的生成放在了next()函數内,每次對line的0下标(即目前值)進行指派
class DummyInd(bt.Indicator):
lines = ('dummyline',)
params = (('value', 5),)
def next(self):
self.lines.dummyline[0] = max(0.0, self.params.value)
def once(self, start, end):
dummy_array = self.lines.dummyline.array
for i in xrange(start, end):
dummy_array[i] = max(0.0, self.params.value)
額外的once()可以優化計算。
4,耦合不同時間機關的資料
當名額需要操作兩個不同時間機關的資料,比如日線和月線,如果直接按照通常的方法操作的話會報錯。
pivotpoint = btind.PivotPoint(self.data1)
sellsignal = self.data0.close < pivotpoint.s1
其中“data1”是月線資料,“data0”是日線資料,運作時會報錯
return self.array[self.idx + ago] IndexError: array index out of range
BackTrader提供了一個解決方案來應對這種需求,就是在“s1”後面添加()
pivotpoint = btind.PivotPoint(self.data1)
sellsignal = self.data0.close < pivotpoint.s1()
pivotpoint.s1()會傳回一個内部LinesCoupler對象,它會用最近的s1月線值來進行填充空缺的日線值。
如果要使這個方法生效,必須在建立cerebro時,添加一個參數“runonce=False”,類似這樣
cerebro = bt.Cerebro(runonce=False)
或
cerebro.run(runonce=False)
差別于隻對s1生效,另一種寫法是這樣
pp1 = pp()
self.sellsignal = self.data0.close < pp1.s1
如果pp含有多條lines,那個所有的lines都會進行耦合。
一個完整的示例:
import backtrader as bt
import backtrader.indicators as btind
import inspect
class St(bt.Strategy):
params = dict(multi=True)
def __init__(self):
self.pp = pp = btind.PivotPoint(self.data1)
pp.plotinfo.plot = False # deactivate plotting
if self.p.multi:
pp1 = pp() # couple the entire indicators
self.sellsignal = self.data0.close < pp1.s1
else:
self.sellsignal = self.data0.close < pp.s1()
def next(self):
txt = ','.join(
['%04d' % len(self),
'%04d' % len(self.data0),
'%04d' % len(self.data1),
self.data.datetime.date(0).isoformat(),
'%.2f' % self.data0.close[0],
'%.2f' % self.pp.s1[0],
'%.2f' % self.sellsignal[0]])
print(txt)
cerebro = bt.Cerebro()
data = bt.feeds.GenericCSVData(
dataname='CU1811.csv',
nullvalue=0.0,
dtformat=('%Y%m%d'),
datetime=1,
open=4,
high=5,
low=6,
close=7,
volume=11,
openinterest=-1
)
cerebro.adddata(data)
cerebro.resampledata(data, timeframe=bt.TimeFrame.Months)
cerebro.broker.set_cash(1000000)
cerebro.addstrategy(St, multi=False)
cerebro.run()
cerebro.plot(style='bar',iplot=False)
0012,0012,0001,2017-12-01,54460.00,53516.67,0.00 0013,0013,0001,2017-12-04,55060.00,53516.67,0.00 0014,0014,0001,2017-12-05,53910.00,53516.67,0.00 0015,0015,0001,2017-12-06,52800.00,53516.67,1.00 0016,0016,0001,2017-12-07,52630.00,53516.67,1.00 0017,0017,0001,2017-12-08,53240.00,53516.67,1.00 0018,0018,0001,2017-12-11,52680.00,53516.67,1.00 0019,0019,0001,2017-12-12,53460.00,53516.67,1.00 0020,0020,0001,2017-12-13,53630.00,53516.67,0.00 0021,0021,0001,2017-12-14,53700.00,53516.67,0.00 0022,0022,0001,2017-12-15,54320.00,53516.67,0.00 0023,0023,0001,2017-12-18,54910.00,53516.67,0.00 0024,0024,0001,2017-12-19,54800.00,53516.67,0.00 0025,0025,0001,2017-12-20,55150.00,53516.67,0.00 0026,0026,0001,2017-12-21,55700.00,53516.67,0.00 0027,0027,0001,2017-12-22,55940.00,53516.67,0.00 0028,0028,0001,2017-12-25,56090.00,53516.67,0.00 0029,0029,0001,2017-12-26,56680.00,53516.67,0.00 0030,0030,0001,2017-12-27,56340.00,53516.67,0.00 0031,0031,0001,2017-12-28,57230.00,53516.67,0.00 0032,0032,0001,2017-12-29,56820.00,53516.67,0.00 0033,0033,0002,2018-01-02,56610.00,53890.00,0.00 0034,0034,0002,2018-01-03,56200.00,53890.00,0.00 0035,0035,0002,2018-01-04,56650.00,53890.00,0.00
從輸出可以看出s1值一個月才會變化。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cskXQE1Ue4YVZ0h2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL2ITNxMDMygTM1ATNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)