Backtrader简单均线交易策略“金叉和死叉”
1、使用5日均线和10日均线
MA5和MA10的交叉点作为买入和卖出信号
交易策略是量化交易的核心,MA均线策略也称为SMA均线策略,是量化交易的最简单的量化交易策略之一,当5日均线向上穿过10日均线的时候,我们称为金叉,当5日均线向上穿过10日均线的时候,我们成为死叉。本使用的是极宽量化交易的包。
2、导入包
import sys;
sys.path.append("topqt/")
#
import matplotlib as mpl
import matplotlib.pyplot as plt
#
import os,time,arrow,math,random,pytz
import datetime as dt
#
import backtrader as bt
import topquant2019 as tq
3、设置交易策略
Backtrader的策略函数源自Strategy类函数,一个完整的策略函数至少要包括以下两个策略函数。
(1)init:策略初始化函数
(2)next:策略执行函数
(3)notify_order:订单信息管理函数
(4)notify_trade:交易信息管理函数
(5)stop:策略回测结束函数
(6)log:自定义输出函数
本案例中时间周期为5天和10天,在init初始化函数的重点是增加了一组MA均线指标。
程序调用的是Backtrader内部指标模块indicators,周期参数变量是均线函数内部的变量名称period,不同指标参数变量名称是不同的。周期参数数值。使用的是策略定义的周期变量,数值为5天和10天。
#----------------------
# # 创建一个自定义策略类class
# class TQSta001(bt.Strategy):
class TQSta001(bt.Strategy):
"""
继承并构建自己的bt策略
"""
# 定义MA均线策略周期参数变量
def log(self, txt, dt=None, doprint=True):
''' 日志函数,用于统一输出日志格式 '''
if doprint:
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
def __init__(self):
# 初始化相关数据
self.dataclose = self.datas[0].close
self.order = None
self.buyprice = None
self.buycomm = None
# 五日移动平均线
self.sma5 = bt.indicators.SimpleMovingAverage(
self.datas[0], period=5)
# 十日移动平均线
self.sma10 = bt.indicators.SimpleMovingAverage(
self.datas[0], period=10)
def notify_order(self, order):
"""
订单状态处理
Arguments:
order {object} -- 订单状态
"""
if order.status in [order.Submitted, order.Accepted]:
# 如订单已被处理,则不用做任何事情
return
# 检查订单是否完成
if order.status in [order.Completed]:
if order.isbuy():
self.log('买单执行BUY EXECUTED,成交价: %.2f,小计 Cost: %.2f,佣金 Comm %.2f'
% (order.executed.price,order.executed.value,order.executed.comm))
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
elif order.issell():
self.log('卖单执行SELL EXECUTED,成交价: %.2f,小计 Cost: %.2f,佣金 Comm %.2f'
% (order.executed.price,order.executed.value,order.executed.comm))
self.bar_executed = len(self)
# 订单因为缺少资金之类的原因被拒绝执行
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('Order Canceled/Margin/Rejected')
# 订单状态处理完成,设为空
self.order = None
def notify_trade(self, trade):
"""
交易成果
Arguments:
trade {object} -- 交易状态
"""
if not trade.isclosed:
return
# 显示交易的毛利率和净利润
self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
(trade.pnl, trade.pnlcomm), doprint=True)
def next(self):
''' 下一次执行 '''
# 记录收盘价
self.log('Close, %.2f' % self.dataclose[0])
# 是否正在下单,如果是的话不能提交第二次订单
if self.order:
return
# 是否已经买入
if not self.position:
# 还没买,如果 MA5 > MA10 说明涨势,买入
if self.sma5[0] > self.sma10[0]:
self.order = self.buy()
else:
# 已经买了,如果 MA5 < MA10 ,说明跌势,卖出
if self.sma5[0] < self.sma10[0]:
self.order = self.sell()
def stop(self):
self.log(u'(金叉死叉有用吗) Ending Value %.2f' %
(self.broker.getvalue()), doprint=True)
4、设置交易策略
if __name__ == '__main__':
cerebro = bt.Cerebro()
dmoney = 100000.0
cerebro.broker.setcash(dmoney)
dcash0 = cerebro.broker.startingcash
rs0 = 'data/stk/'
xcod = '002046'
fdat = rs0 + xcod + '.csv'
t0str,t9str='2018-01-01','2018-12-31'
data=tq.pools_get4fn(fdat,t0str,t9str)
cerebro.adddata(data)
cerebro.addstrategy(TQSta001)
# 设置佣金
cerebro.broker.setcommission(commission=0.01)
cerebro.addsizer(bt.sizers.FixedSize,stake=10)
cerebro.run()
dval9 = cerebro.broker.getvalue()
kret = (dval9 - dcash0)/dcash0*100
print('\t起始资金 Starting Portfolio Value: %.2f' % dcash0)
print('\t资产总值 Final Portfolio Value: %.2f' % dval9)
print('\tROI投资回报率 Return on investment: %.2f %%' % kret)
cerebro.plot()
5、结果展示
参考链接:
https://zhuanlan.zhihu.com/p/133637955