量化交易學習筆記(二十三)——自定義Indicator


量化交易學習筆記(二十三)——自定義Indicator

想要將深度學習算法應用於回測過程中,通過查閱資料,發現需要實現自定義技術指標(Indicator)。本文先實現一個簡單的自定義指標,為後續深度學習的應用做個鋪墊。

本文示例策略的買入條件為均線(選取10日線)向上,收陰線,且收盤價在均線上方。賣出條件為筆記(二十)中闡述的保護點賣出策略。

回測初始資金100000元,單筆操作單位1000股,佣金千分之一,回測時間自2018年1月1日至2020年3月20日。

自定義指標代碼如下:

<code>class NegativeIndicator(bt.Indicator):
lines = ('buy_sig',)
params = (('ma_period', 10), ('up_period', 3))
def __init__(self):
self.addminperiod(self.p.ma_period)
ma = bt.ind.SMA(period = self.p.ma_period, plot = True)
# 買入條件
# 收陰線
self.l.buy_sig = bt.And(self.data.close < self.data.open,
# 收在均線上方
self.data.close > ma,
# 均線向上
ma == bt.ind.Highest(ma, period = self.p.up_period)
)/<code>

這裡的自定義指標繼承於backtrader的Indicator類,類內包含一個名為buy_sig的lines對象。參數ma_period用於控制選擇哪條均線,up_period用於控制判斷均線向上的週期。

要注意的是在__init__方法裡所用到的指標都是lines對象,是一系列數值的組合。如果指標的計算挪到next方法裡,那麼要在指標後加上下標[0]來計算,這是由於next方法裡的指標應為單個的數值。

策略類也相對簡單,主要是在__init__方法中引入自定義的指標:

<code>    def __init__(self):
# 買入條件
self.buy_sig = NegativeIndicator().buy_sig
# 為了在最後圖表中顯示均線
bt.ind.SMA(period = NegativeIndicator().p.ma_period)
self.order = None/<code>

回測000001後的最終資產為101893.73元。

量化交易學習筆記(二十三)——自定義Indicator

回測000002後的最終資產為98094.33元。

量化交易學習筆記(二十三)——自定義Indicator

回測601318後的最終資產為87259.10元。

量化交易學習筆記(二十三)——自定義Indicator

友情提示:本系列學習筆記只做數據分析,記錄個人學習過程,不作為交易依據,盈虧自負。


自定義Indicator代碼:

<code>from __future__ import (absolute_import, division, print_function, unicode_literals)
import datetime # 用於datetime對象操作
import os.path # 用於管理路徑
import sys # 用於在argvTo[0]中找到腳本名稱
import backtrader as bt # 引入backtrader框架

# 自定義指標
class NegativeIndicator(bt.Indicator):
lines = ('buy_sig',)
params = (('ma_period', 10), ('up_period', 3))
def __init__(self):
self.addminperiod(self.p.ma_period)
ma = bt.ind.SMA(period = self.p.ma_period, plot = True)
# 買入條件
# 收陰線
self.l.buy_sig = bt.And(self.data.close < self.data.open,
# 收在均線上方
self.data.close > ma,
# 均線向上
ma == bt.ind.Highest(ma, period = self.p.up_period)
)

# 創建策略
class St(bt.Strategy):
params = dict(
stoptype=bt.Order.StopTrail,
trailamount=0.0,
trailpercent=0.05,
)
def __init__(self):
# 買入條件
self.buy_sig = NegativeIndicator().buy_sig
# 為了在最後圖表中顯示均線

bt.ind.SMA(period = NegativeIndicator().p.ma_period)
self.order = None
def notify_order(self, order):
if order.status in [order.Completed, order.Expired]:
self.order = None
def next(self):
# 無場內資產
if not self.position:
# 未提交買單
if None == self.order:
# 到達了買入條件
if self.buy_sig:
self.order = self.buy()
elif self.order is None:
# 提交stoptrail訂單
self.order = self.sell(exectype=self.p.stoptype,
trailamount=self.p.trailamount,
trailpercent=self.p.trailpercent)

cerebro = bt.Cerebro() # 創建cerebro
# 先找到腳本的位置,然後根據腳本與數據的相對路徑關係找到數據位置
# 這樣腳本從任意地方被調用,都可以正確地訪問到數據
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
datapath = os.path.join(modpath, '../TQDat/day/stk/000001.csv')
# 創建價格數據
data = bt.feeds.GenericCSVData(
dataname = datapath,
fromdate = datetime.datetime(2018, 1, 1),
todate = datetime.datetime(2020, 3, 31),
nullvalue = 0.0,
dtformat = ('%Y-%m-%d'),
datetime = 0,
open = 1,
high = 2,
low = 3,
close = 4,
volume = 5,
openinterest = -1
)
# 在Cerebro中添加價格數據
cerebro.adddata(data)

# 設置啟動資金
cerebro.broker.setcash(100000.0)
# 設置交易單位大小
cerebro.addsizer(bt.sizers.FixedSize, stake = 1000)
# 設置佣金為千分之一
cerebro.broker.setcommission(commission=0.001)
cerebro.addstrategy(St) # 添加策略
cerebro.run() # 遍歷所有數據
# 打印最後結果
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
cerebro.plot(style = 'candlestick') # 繪圖/<code>


分享到:


相關文章: