失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 量化交易学习笔记(十七)——多只股票同时策略回测

量化交易学习笔记(十七)——多只股票同时策略回测

时间:2020-01-22 21:37:56

相关推荐

量化交易学习笔记(十七)——多只股票同时策略回测

假设我们现在有策略A,在股票a的历史数据上进行回测后,发现能够取得稳定收益。但是我们有很长时间要等待股票a达到买入条件后,才能进行买入。这是对时间成本的严重浪费。

我们可以尝试做这样的改进:在股票a,b,c……的历史数据上分别进行策略回测,找到一个能够稳定收益策略B,来避免时间成本浪费的问题。但是这样仍然存在问题,在等待股票a出现买点的时候,股票b,c……的买点可能也没有出现。因此对所有股票依次做单独的策略回测,不足以验证策略的优劣。

鉴于以上两点,我们在验证策略时,需要对多只甚至全部的股票同时进行回测。本文基于backtrader,编写了多股票同时回测程序。

同样,本文旨在验证回测功能,策略依然选择简单的长短期均线金叉买入死叉卖出策略。核心代码位于策略类的init及next方法,先来看init方法:

def __init__(self):

self.inds = dict()

for i, d in enumerate(self.datas):

self.inds[d] = dict()

self.inds[d]["sma1"] = bt.ind.SMA(d.close, period=self.p.pfast) # 短期均线

self.inds[d]["sma2"] = bt.ind.SMA(d.close, period=self.p.pslow) # 长期均线

self.inds[d]["cross"] = bt.ind.CrossOver(self.inds[d]["sma1"], self.inds[d]["sma2"], plot = False) # 交叉信号

这里定义了一个python字典类型变量self.inds,用于存储不同股票数据的技术指标,该字典的key为单支股票的数据,即代码中的d,value对应的该股票对应的技术指标,这些技术指标也存在一个字典内,字典内包含短期均线、长期均线、交叉信号3个指标。

再来看next方法:

def __init__(self):

self.inds = dict()

for i, d in enumerate(self.datas):

self.inds[d] = dict()

self.inds[d]["sma1"] = bt.ind.SMA(d.close, period=self.p.pfast) # 短期均线

self.inds[d]["sma2"] = bt.ind.SMA(d.close, period=self.p.pslow) # 长期均线

self.inds[d]["cross"] = bt.ind.CrossOver(self.inds[d]["sma1"], self.inds[d]["sma2"], plot = False) # 交叉信号

next方法中,循环遍历所有待测的股票,对每只股票,获取时间及股票名称,这样便于后续打印输出、日志留存或者调试。然后通过判断当前股票position的size,判断是否已经买入该股票,如果没有买入,判断短期均线金叉长期均线后,即可买入。如果已经持有了该股票,那么判断长期均线死叉短期均线后即可卖出。

最后要注意的是,向cerebro添加不同股票数据时,补充添加股票名称,以便后续调试及分析使用:

cerebro.adddata(data, name = stk_code) # 在Cerebro中添加股票数据

我们依然选择5日线作为短期均线,60日线作为长期均线,回测初始资金100000,单笔操作单位1000股,佣金千分之一,回测时间自1月1日至3月3日,按股票代码的升序排列依次添加回测股票,即先回测000001, 再加入000002,再加入000004……(000003停牌还是退市了。。。)

当1只股票进行回测时,回测最终资产103355.34:

当2只股票进行回测时,回测最终资产97427.99:

当3只股票进行回测时,回测最终资产120535.95:

此外,还测试了5只股票回测最终资产为118823.75,10只股票最终资产为116871.02,随着回测股票数目的增加,程序运行的时间也越长。

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

多只股票同时策略回测程序:

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框架

import pandas as pd

stk_num = 3 # 回测股票数目

# 创建策略

class SmaCross(bt.Strategy):

# 可配置策略参数

params = dict(

pfast=5, # 短期均线周期

pslow=60, # 长期均线周期

poneplot = False, # 是否打印到同一张图

pstake = 1000 # 单笔交易股票数目

)

def __init__(self):

self.inds = dict()

for i, d in enumerate(self.datas):

self.inds[d] = dict()

self.inds[d]["sma1"] = bt.ind.SMA(d.close, period=self.p.pfast) # 短期均线

self.inds[d]["sma2"] = bt.ind.SMA(d.close, period=self.p.pslow) # 长期均线

self.inds[d]["cross"] = bt.ind.CrossOver(self.inds[d]["sma1"], self.inds[d]["sma2"], plot = False) # 交叉信号

# 跳过第一只股票data,第一只股票data作为主图数据

if i > 0:

if self.p.poneplot:

d.plotinfo.plotmaster = self.datas[0]

def next(self):

for i, d in enumerate(self.datas):

dt, dn = self.datetime.date(), d._name

pos = self.getposition(d).size

if not pos:

if self.inds[d]["cross"] > 0:

self.buy(data = d, size = self.p.pstake)

elif self.inds[d]["cross"] < 0:

self.close(data = d)

cerebro = bt.Cerebro() # 创建cerebro

# 读入股票代码

stk_code_file = "../TQDat/data/tq_stock_code.csv"

stk_pools = pd.read_csv(stk_code_file, encoding = "gbk")

if stk_num > stk_pools.shape[0]:

print("股票数目不能大于%d" % stk_pools.shape[0])

exit()

for i in range(stk_num):

stk_code = stk_pools["code"][stk_pools.index[i]]

stk_code = "%06d" % stk_code

# 读入数据

datapath = "../TQDat/day/stk/" + stk_code + ".csv"

# 创建数据

data = bt.feeds.GenericCSVData(

dataname = datapath,

fromdate = datetime.datetime(, 1, 1),

todate = datetime.datetime(, 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, name = stk_code)

# 设置启动资金

cerebro.broker.setcash(100000.0)

# 设置交易单位大小

#cerebro.addsizer(bt.sizers.FixedSize, stake = 5000)

# 设置佣金为千分之一

cerebro.broker.setcommission(commission=0.001)

cerebro.addstrategy(SmaCross, poneplot = False) # 添加策略

cerebro.run() # 遍历所有数据

# 打印最后结果

print("Final Portfolio Value: %.2f" % cerebro.broker.getvalue())

cerebro.plot(style = "candlestick") # 绘图

如果觉得《量化交易学习笔记(十七)——多只股票同时策略回测》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。