笔记(13)中介绍了在策略中对单个参数进行优化的实现方法,本文将介绍对策略中的多个参数进行优化的方案。
以笔记(14)中介绍的均线交叉策略为例,实现不同长期、短期均线参数组合的优化测试,回测股票为000001平安银行,回测周期为2018年1月1日至2020年4月15日。
strats = cerebro.optstrategy(
SmaCross,
pfast = [5, 10, 15],
pslow = [20, 30, 60])
在策略类中的init函数中,使用相应的参数:
params = dict(
pfast=5, # 短期均线周期
pslow=10 # 长期均线周期
)
def __init__(self):
sma1 = bt.ind.SMA(period=self.p.pfast) # 短期均线
sma2 = bt.ind.SMA(period=self.p.pslow) # 长期均线
self.crossover = bt.ind.CrossOver(sma1, sma2) # 交叉信号
在上面的代码中,短期均线会依次取5、10、15三个值,长期均线会依次取20、30、60三个值,这样就会形成3*3=9种组合,执行程序后输出如下:
(Fast Period 5, Slow Period 20) Ending Value 101321.23
(Fast Period 5, Slow Period 30) Ending Value 109934.13
(Fast Period 5, Slow Period 60) Ending Value 116776.70
(Fast Period 10, Slow Period 20) Ending Value 107225.67
(Fast Period 10, Slow Period 30) Ending Value 107899.79
(Fast Period 10, Slow Period 60) Ending Value 110485.50
(Fast Period 15, Slow Period 20) Ending Value 95051.12
(Fast Period 15, Slow Period 30) Ending Value 104954.36
(Fast Period 15, Slow Period 60) Ending Value 106075.20
strats = cerebro.optstrategy(
SmaCross,
period = [(5, 10), (20, 100), (2, 10)])
在策略类中的init函数中,使用相应的参数:
params = dict(
period = (5, 10), # 元组,(短期均线周期,长期均线周期)
)
def __init__(self):
sma1 = bt.ind.SMA(period=self.p.period[0]) # 短期均线
sma2 = bt.ind.SMA(period=self.p.period[1]) # 长期均线
self.crossover = bt.ind.CrossOver(sma1, sma2) # 交叉信号
在上面的代码中,短期均线和长期均线会形成了3个组合供测试优化,执行程序后输出如下:
(Fast Period 5, Slow Period 10) Ending Value 92377.83
(Fast Period 20, Slow Period 100) Ending Value 107292.25
(Fast Period 2, Slow Period 10) Ending Value 90157.66
方案1和方案2在使用时稍有区别:
策略多参数优化代码(方案2):
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 SmaCross(bt.Strategy):
# 可配置策略参数
params = dict(
period = (5, 10), # 元组,(短期均线周期,长期均线周期)
)
def __init__(self):
sma1 = bt.ind.SMA(period=self.p.period[0]) # 短期均线
sma2 = bt.ind.SMA(period=self.p.period[1]) # 长期均线
self.crossover = bt.ind.CrossOver(sma1, sma2) # 交叉信号
def next(self):
if not self.position: # 不在场内,则可以买入
if self.crossover > 0: # 如果金叉
self.buy() # 买入
elif self.crossover < 0: # 在场内,且死叉
self.close() # 卖出
def stop(self):
print('(Fast Period %3d, Slow Period %3d) Ending Value %.2f' %
(self.params.period[0], self.params.period[1], self.broker.getvalue()))
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, 4, 15),
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 = 5000)
# 设置佣金为千分之一
cerebro.broker.setcommission(commission=0.001)
# 添加策略
strats = cerebro.optstrategy(
SmaCross,
period = [(5, 10), (20, 100), (2, 10)])
cerebro.run(maxcpus = 1) # 遍历所有数据
为了便于相互交流学习,新建了微信群,感兴趣的读者请加微信。