您的位置:首页 > 编程语言 > Python开发

Python量化交易学习笔记(22)——自定义Indicator

2020-03-31 07:22 423 查看

想要将深度学习算法应用于回测过程中,通过查阅资料,发现需要实现自定义技术指标(Indicator)。本文先实现一个简单的自定义指标,为后续深度学习的应用做个铺垫。

本文示例策略的买入条件为均线(选取10日线)向上,收阴线,且收盘价在均线上方。卖出条件为笔记(二十)中阐述的保护点卖出策略。

回测初始资金100000元,单笔操作单位1000股,佣金千分之一,回测时间自2018年1月1日至2020年3月20日。

自定义指标代码如下:

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)
)

这里的自定义指标继承于backtrader的Indicator类,类内包含一个名为buy_sig的lines对象。参数ma_period用于控制选择哪条均线,up_period用于控制判断均线向上的周期。

要注意的是在__init__方法里所用到的指标都是lines对象,是一系列数值的组合。如果指标的计算挪到next方法里,那么要在指标后加上下标[0]来计算,这是由于next方法里的指标应为单个的数值。

策略类也相对简单,主要是在__init__方法中引入自定义的指标:

def __init__(self):
# 买入条件
self.buy_sig = NegativeIndicator().buy_sig
# 为了在最后图表中显示均线
bt.ind.SMA(period = NegativeIndicator().p.ma_period)
self.order = None

回测000001后的最终资产为101893.73元。

回测000002后的最终资产为98094.33元。

回测601318后的最终资产为87259.10元。

友情提示:本系列学习笔记只做数据分析,记录个人学习过程,不作为交易依据,盈亏自负。

自定义Indicator代码:

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')  # 绘图
  • 点赞
  • 收藏
  • 分享
  • 文章举报
码农甲V 发布了23 篇原创文章 · 获赞 1 · 访问量 779 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: