添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

笔记(17) 中,对backtrader多只股票同时进行策略回测的过程进行了记录,当时只进行了少量股票的同时回测,如果增加参与回测的股票数目,就会出现各种异常的情况。

从本文开始,将用几篇笔记记录在多股回测时发现的几个坑,并给出避坑方案。

回测周期内,某些股票的可用K线数量少于计算技术指标时的最小周期数 。当出现这种情况时,backtrader不会对这些股票进行清洗剔除,依然会计算相应的技术指标,从而造成了访问数组越界的情况,典型报错信息为:

IndexError: array assignment index out of range

为了重现上述现象,做如下回测设定:

  • 使用30日均线作为买卖条件的判断标准:
MIN_PERIOD = 30
		params = dict(
        period = MIN_PERIOD,  	# 均线周期
        stake = 100, 			# 单笔交易股票数目
    def __init__(self):
        self.inds = dict()
        for i, d in enumerate(self.datas):
            self.inds[d] = bt.ind.SMA(d.close, period=self.p.period)
  • 买入条件:收盘价高于30日均线
            if not len(pos):                                 # 不在场内,则可以买入
                if d.close[0] > self.inds[d][0]:             # 达到买入条件
                    self.buy(data = d, size = self.p.stake)  # 买买买
  • 卖出条件:收盘价低于30日均线
            elif d.close[0] < self.inds[d][0]:           # 达到卖出条件
                self.close(data = d)                     # 卖卖卖
  • 回测周期:2019年1月1日至2019年12月31日
    fromdate = datetime.datetime(2019, 1, 1)
    todate = datetime.datetime(2019, 12, 31)
  • 股票组合:使用[‘002321’, ‘002322’]的组合与[‘002321’, ‘002322’, ‘002323’]的组合做对比
stk_pools = ['002321', '002322']
#stk_pools = ['002321', '002322', '002323']

在回测周期内(这里面还有坑,后续文章会详细介绍),002321日K线共244根,002322日K线共244根,002323日K线共20根(长期停盘)。显然,使用002323的20根K线,是无法计算30日均线的

当使用组合[‘002321’, ‘002322’]进行回测时,程序可以正常运行;当使用组合[‘002321’, ‘002322’, ‘002323’]进行回测时,程序会报本文开始部分提到的IndexError

为了确保参与回测的每只股票都能计算得到有效的技术指标,可以先计算在回测周期内有效K线的数目,如果K线数目足以计算策略使用的技术指标,则该股票参与回测;否则,剔除该股票。

  • 统计回测周期内K线数量

首先读入股票数据,然后获取在起止日期内的数据长度,代码如下:

# 统计回测周期内K线数量
def bar_size(datapath, fromdate, todate):
    df = pd.read_csv(datapath)
    return len(df[(df['date'] >= fromdate.strftime('%Y-%m-%d')) 
            & (df['date'] <= todate.strftime('%Y-%m-%d'))])
  • 剔除无效股票

通过调用bar_size方法,计算回测周期内有效K线数目,如果有效K线数目能够支持计算回测过程所需的技术指标,则将该股票数据添加到cerebro中参与回测,否则该股票将被剔除不参与回测。

stk_pools = ['002321', '002322']
#stk_pools = ['002321', '002322', '002323']
for stk_code in stk_pools:
    # 读入数据
    datapath = '../TQDat/day/stk/' + stk_code + '.csv'
    fromdate = datetime.datetime(2019, 1, 1)
    todate = datetime.datetime(2019, 12, 31)
    # 剔除无效股票
    if MIN_PERIOD > bar_size(datapath, fromdate, todate):
        continue
    # 创建价格数据
    data = bt.feeds.GenericCSVData(
            dataname = datapath,
            fromdate = fromdate,
            todate = todate,
            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)

通过以上的避坑操作,使用[‘002321’, ‘002322’]的组合与[‘002321’, ‘002322’, ‘002323’]的组合进行回测时,可以得到相同的回测结果。

在对组合[‘002321’, ‘002322’, ‘002323’]进行回测时,由于002323在回测周期内只有20根日K线,无法计算策略中30日均线值,因此被剔除未参与回测

  • 在多股回测中,会对参与回测的所有股票计算策略所使用的技术指标值。

  • 在回测周期中,某些股票由于未上市、停盘的因素,有效K线数量小于计算技术指标所需K线数量,会导致程序报错(IndexError: array assignment index out of range)。

  • 为了保证程序正常运行,可在回测前对数据进行清洗,剔除回测周期内有效K线数量不足的股票。

  • 不同计算指标对K线数目的需要略有不同(后续文章再记录)。

backtrader多股回测避坑1代码:

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import datetime  # 用于datetime对象操作
import os.path  # 用于管理路径
import backtrader as bt # 引入backtrader框架
import pandas as pd
MIN_PERIOD = 30
# 统计回测周期内K线数量
def bar_size(datapath, fromdate, todate):
    df = pd.read_csv(datapath)
    return len(df[(df['date'] >= fromdate.strftime('%Y-%m-%d')) 
            & (df['date'] <= todate.strftime('%Y-%m-%d'))])
# 创建策略
class SmaStrategy(bt.Strategy):
    # 可配置策略参数
    params = dict(
        period = MIN_PERIOD,    # 均线周期
        stake = 100,            # 单笔交易股票数目
    def __init__(self):
        self.inds = dict()
        for i, d in enumerate(self.datas):
            self.inds[d] = bt.ind.SMA(d.close, period=self.p.period)
    def next(self):
        for i, d in enumerate(self.datas):
            pos = self.getposition(d)
            if not len(pos):                                 # 不在场内,则可以买入
                if d.close[0] > self.inds[d][0]:             # 达到买入条件
                    self.buy(data = d, size = self.p.stake)  # 买买买
            elif d.close[0] < self.inds[d][0]:               # 达到卖出条件
                self.close(data = d)                         # 卖卖卖
cerebro = bt.Cerebro()  # 创建cerebro
stk_pools = ['002321', '002322']
#stk_pools = ['002321', '002322', '002323']
for stk_code in stk_pools:
    # 读入数据
    datapath = '../TQDat/day/stk/' + stk_code + '.csv'
    fromdate = datetime.datetime(2019, 1, 1)
    todate = datetime.datetime(2019, 12, 31)
    # 剔除无效股票
    if MIN_PERIOD > bar_size(datapath, fromdate, todate):
        continue
    # 创建价格数据
    data = bt.feeds.GenericCSVData(
            dataname = datapath,
            fromdate = fromdate,
            todate = todate,
            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(1000000.0)                # 设置启动资金
cerebro.addstrategy(SmaStrategy)                 # 添加策略
cerebro.run()                                    # 遍历所有数据
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

为了便于相互交流学习,新建了微信群,感兴趣的读者请加微信。
在这里插入图片描述

</span></p><p> <span>《从编程小白到量化宗师之路</span><span>》系列课程是一套综合性实战课程,涵盖股票,期货,虚拟货币等的交易方法和策略手段。</span> 《BackTrader从数据采集到实盘交易》是本系列的第一个<span>中</span>级课程。<span>本网站的课程宗旨是缩短个人或小型投资者与大型机构投资者之间的的差距。</span> 课程内容从python环境的安装开始使用,到股票数据采集,BackTrader开源软件的应用,并包含一套机构常用策略的讲解和实现。 与市面上的其他理论课程不同,本课程注重实战,学员上课后,将可以达到自动化更新每日股票数据,自动化选股,自动化提示股票交易的的时机的目标。 在3000种股票的中国市场,<span>您</span>将有获得现代化高科技力量的强力支持。 <br /></p> <br /></p> <br /></p> <br /></p> 浏览器打开 01引言海龟交易策略是比较经典的趋势交易系统之一,涵盖了从入场交易(品种选择)、仓位管理(基于ATR加减仓)、离场(触发条件)的整个过程。机械套用海龟交易法则在A股上进行交易可能效果不佳... 浏览器打开 一般量化框架,有这么几种第一种:在存储着trade_date和net_return,selected_stock的矩阵里计算累计收益率和净值。去掉了停牌等不能交易股票交易日,没有因子信息的股票交易日。第二种:核心:在trade_date 的循环判断买卖条件,里更新仓位,净值。逻辑:class memory():#定义一个存储仓位变化的全局类,当然你也可以用其他数据结构或者文件记录 浏览器打开 01引言backtrader是功能非常强大的量化框架之一,得到欧洲很多银行、基金等金融机构的青睐,并应用于实盘交易中。公众号Python金融量化针对backtrader的入门和应用已... 浏览器打开 本文继续记录多股时可能遇到的异常情况。 多股时,当日期达到所有股票的技术指标都能够计算出有效值后,backtrader才开始进行。由于这种逻辑的存在,如果某些股票周期的最后几天才能计算出技术指标,那么就会导致只在最后几天进行,前面大片时间被浪费。 为了重现上述现象,做如下设定(与笔记(35)相同): 使用20日均线作为买卖条件的判断标准: MIN_PERIOD = 20 # 可配置策略参数 params = dict( 浏览器打开 以下策略来自我们编写的教程和视频课程。 多股组合操作,是一种高级的操作模式。多股组合操作通常有两种模式,一种是定期调仓,即定期再平衡,比如每周1调仓,或每月1号调仓等。另一种是非定期调仓,比如每日判断,进行调仓,或者每隔n天进行调仓。 定期调仓(再平衡)通常通过定时器timer来进入调仓逻辑,而非定期调仓通常通过传统的策略next方法进入调仓逻辑。当然,这并非绝对。 这两种多股调仓操作,都不能用backtrader内置的自动确定最小期的方法来做(比如为了求20日均线,自动跳过前20个bar),因为有些 浏览器打开 现在有两只股票000001和000002,在2020年1月2日到2020年8月3号,两者的数据都是全得到。现在尝试把000002的6月份的数据给删除了,然后加载000001和000002到backtrader,观察两者有什么样的表现。 import backtrader as bt from backtrader import num2date import datetime import pandas as pd import numpy as np import os,sys import copy 浏览器打开 11、用backtrader在A股上复利年化收益率超20%的“狗股策略”? 1、什么是攻守兼备的“狗股策略”? ​ 狗股理论是美国基金经理迈克尔·奥希金斯于1991年提出的一种投资策略。具体的做法是,投资者每年年底从道琼斯工业平均指数成份股中找出10只股息率最高的股票,新年买入,一年后再找出10只股息率最高的成分股,卖出手中不在名单中的股票,买入新上榜单的股票,每年年初年底都重复这一投资动作,便可获取超过大盘的报。据有关统计,1975至1999年运用"狗股理论",投资的平均复利报达18%,远高于市 浏览器打开