VNPY - CTA策略模块策略回测

作者:魔元

目录

量化策略主要是从历史数据统计或者发现规律然后应用于实盘交易。当然历史不是简单的重复,这就要求策略需要根据市场调整和优化参数。通过回测历史数据可以验证策略的有效性,了解策略的历史收益、最大回撤和回撤时长,对策略参数进行优化等等。CTA策略模块的主要回测目标是验证交易信号是否正确,仓位大小的问题在实盘中则由交易员来确定。

使用回测引擎

vnpy的回测引擎位于vnpy/trader/app/ctaStrategy/ctaBacktesting.py,此文件中主要包含以下几个类:

  • BacktestingEngine

    • 回测引擎类,主要功能是设置回测参数,初始化策略对象,运行回测并输出结果。类接口和实盘引擎类(CtaEngine)保持一致,从而实现同一套策略代码从回测到实盘。用户主要是调用本类的接口来回测策略
  • TradingResult

    • 撮合好的交易结果类,由回测引擎计算回测结果时使用。类成员包含开仓价格,平仓价格,交易数量,成交金额,滑点成本,手续费成本及净盈亏等。

    这里面有一点注意是交易数量的正负代表开仓方向。以股指IF为例,3000点时开1手多单,3010点平仓,这时就会生成一个TradingResult实例,交易数量为1。若3000点时开1手空单,3010点平仓,这时生成的TradingResult实例的交易数量为-1。
    代码如下:

      ```Python
      self.entryPrice = entryPrice    # 开仓价格
      self.exitPrice = exitPrice      # 平仓价格
    
      self.entryDt = entryDt          # 开仓时间datetime    
      self.exitDt = exitDt            # 平仓时间
    
      self.volume = volume    # 交易数量(+/-代表方向)
    
      self.turnover = (self.entryPrice+self.exitPrice)*size*abs(volume)   # 成交金额
      self.commission = self.turnover*rate                                # 手续费成本
      self.slippage = slippage*2*size*abs(volume)                         # 滑点成本
      self.pnl = ((self.exitPrice - self.entryPrice) * volume * size
                  - self.commission - self.slippage)                      # 净盈亏
      ```
    
  • OptimizationSetting

    • 参数优化设置类,主要是生成优化参数组合。每个参数组合都由回测引擎执行一遍,以得到不同参数组合的回测结果。优化参数回测时会使用此类。

回测引擎API介绍

由于用户主要是调用本类的接口来回测策略,所以将对本类的接口做逐一介绍。一方面回测引擎类的接口跟实盘策略引擎保持一样,这方面的接口主要是被策略调用; 另一方面回测引擎类也要提供回测相关的接口,所以将回测引擎类的接口从功能性分成这几个方面介绍:

  • 用户回测策略接口

    • 配置相关接口

      • setBacktestingMode

        • 设置回测模式,支持两种模式,一种是Tick模式,另一种是K线模式

        • 参数类型说明
          modestring回测模式,支持两种模式:BacktestingEngine.TICK_MODE和BacktestingEngine.BAR_MODE

          返回值:None

      • setStartDate

        • 设置回测开始日期

        • 参数类型说明
          startDatestring回测开始日期
          initDaysint策略回测开始前需要准备多少日的数据。默认是10日。举个例子,假设策略是日K线回测,数据库里的数据是日K线,如果策略里需要5日均线,这里此参数设为4。假设策略是1分钟K线回测,数据库里的数据是1分钟K线,如果策略里需要5分钟均线,这里此参数则设为1。因为1日里的1分钟K线数据远远大于4,已经足够满足策略开始的准备数据了。

          返回值:None

      • setEndDate

        • 设置回测结束日期

        • 参数类型说明
          endDatestring回测结束日期。默认是''。若使用默认参数,则是数据在数据库里的最近日期。

          返回值:None

      • setDatabase

        • 设置产品(合约)数据的数据库名及表名,这样回测引擎可以载入对应的数据。

        • 参数类型说明
          dbNamestring数据库名
          symbolstring数据库表名

          返回值:None

      • setSlippage

        • 设置每一手产品(合约)的滑点,单位是产品(合约)的价格

        • 参数类型说明
          slippagefloat滑点数值

          返回值:None

      • setRate

        • 设置佣金比例,交易手续费=成交金额X佣金比例

        • 参数类型说明
          ratefloat佣金比例

          返回值:None

      • setSize

        • 设置产品(合约)大小,单位为元。成交金额=合约价格(面值)X合约大小

        • 参数类型说明
          sizefloat合约大小

          返回值:None

      • setPriceTick

        • 设置产品(合约)的最小价格变动,单位是产品(合约)的价格

        • 参数类型说明
          priceTickfloat最小价格变动

          返回值:None

    • 回测相关接口

      • initStrategy

        • 根据策略参数,实例化回测策略对象。

        • 参数类型说明
          strategyClassclass策略类
          settingdict策略参数配置,若使用策略的默认参数则为None

          返回值:None

      • runBacktesting

        • 运行回测。从数据库里载入数据,逐条推入策略做回测,同时模拟委托和成交,并保存回测过程的中间数据,以此可以计算回测结果并显示。

        • 参数:无

          返回值:None

      • calculateBacktestingResult

        • 逐条匹配交易,并计算回测结果。由于回测策略是假设初始资金为0,这样交易后资金可能为负值。这里跟实盘有区别,实盘需要保证金,回测时只考虑每笔交易的盈亏。

        • 参数:无

          返回值:dict

          键值值的类型说明
          capitalfloat当前资金,单位是元
          maxCapitalfloat资金最高净值,单位是元
          drawdownfloat当前回撤,非正值,单位是元
          totalResultint总成交次数
          totalTurnoverfloat总成交金额
          totalCommissionfloat总手续费
          totalSlippagefloat所有交易产生的滑点费用,单位是元
          timeListlist每笔交易的时间序列,时间为交易出场时间
          pnlListlist每笔盈亏序列
          capitalListlist每笔交易后的资金序列
          drawdownListlist每笔交易后的回撤序列
          winningRatefloat胜率(%)
          averageWinningfloat盈利交易平均值,单位是元
          averageLosingfloat亏损交易平均值,单位是元
          profitLossRatiofloat盈亏比
      • showBacktestingResult

        • 计算回测结果,输出回测报告,并显示回测结果图:资金子图,回撤子图,每笔交易盈亏子图

        • 参数:无

          返回值:None

      • calculateDailyResult

        • 按照逐日盯市的方式计算每日的交易盈亏和持仓盈亏,并汇总成最终按日统计的盈亏情况。

        • 参数:无

          返回值:dict

      • showDailyResult

        • 显示按照逐日盯市方式统计的回测结果和资金曲线,提供Sharpe Ratio的统计结果。

        • 参数:无

          返回值:None

    • 优化参数相关接口

      • runOptimization

        • 运行普通模式的优化参数,也就是说python主进程循环回测每一个参数组合,并输出每个参数组合的优化结果。普通模式下只能使用CPU的一个核。

        • 参数类型说明
          strategyClassclass策略类
          optimizationSettingclassOptimizationSetting对象,基于它生成优化参数组合,并获取优化目标

          返回值:None

      • runParallelOptimization

        • 运行多进程模式的优化参数,也就是说并行运行多个进程(等于CPU的核个数)回测每一个参数组合,并输出每个参数组合的优化结果。

        • 参数类型说明
          strategyClassclass策略类
          optimizationSettingclassOptimizationSetting对象,基于它生成优化参数组合,并获取优化目标

          返回值:None

  • 策略相关接口

    • 由于策略既可以跑在回测引擎又可以跑在实盘引擎,所以这部分接口保持跟实盘引擎一致。这部分接口只做功能介绍,不做具体参数的介绍,因为对用户回测策略来讲,这是一个黑盒。根据交易相关和非交易相关,这部分接口可以分为两类:
      • 交易相关接口

        • sendOrder
          • 模拟限价委托单,并把限价单保存在限价单字典和工作限价单字典中。工作限价单字典里是需要撮合成交的委托。限价单字典里则是所有委托。
        • cancelOrder
          • 模拟撤销限价委托单,并从工作限价单字典中删除。
        • sendStopOrder
          • 模拟本地停止单,并把停止单保存在停止单字典和工作停止单字典中。工作停止单字典里是需要撮合成交的委托。停止单字典里则是所有委托。
        • cancelStopOrder
          • 模拟撤销停止委托单,并从工作停止单字典中删除。
      • 非交易相关接口

        • insertData
          • 插入数据到数据库,回测时直接pass
        • loadTick
          • 载入初始化列表中的数据,即策略回测开始前的准备数据
        • loadBar
          • 载入初始化列表中的数据,即策略回测开始前的准备数据
        • writeCtaLog
          • 记录日志到日志列表
        • putStrategyEvent
          • 发送策略更新事件,回测中忽略
  • 内部接口

    • 这部分接口为回测引擎自己调用。后面在讲接口使用的时候,会通过流程图做细节介绍。这里先逐一简单做下介绍:
      • output
        • 输出到控制台
      • newTick
        • 生成新的Tick,完成撮合交易并推送给策略
      • newBar
        • 生成新的Bar,完成撮合交易并推送给策略
      • crossLimitOrder
        • 基于最新数据撮合限价单
      • crossStopOrder
        • 基于最新数据撮合停止单

如何使用回测引擎API

本节结合代码和流程图讲解如何使用回测引擎API。

回测过程流程图

下图为基于策略特定参数的回测过程

Markdown

回测过程详解

  1. 对用户来讲,首先要创建回测引擎实例
# 创建回测引擎
engine = BacktestingEngine()
  1. 设置回测引擎的相关参数(回测模式,回测起始日期,数据库)。历史数据得预先存储在MongoDB中,若没有, 则可执行vnpy/vn.trader/ctaAlgo/ctaHistroyData.py里的代码,把回测数据插入到数据库中, 如下
# 这里将项目中包含的股指日内分钟线csv导入MongoDB,作者电脑耗时大约3分钟
import os
loadMcCsv(os.path.join(os.path.dirname(__file__), 'IF0000_1min.csv'), MINUTE_DB_NAME, 'IF0000')

如果数据已经在数据库中,则运行下面的代码设置回测引擎的相关参数

# 设置引擎的回测模式为K线
engine.setBacktestingMode(engine.BAR_MODE)

# 设置回测用的数据起始日期和结束日期
engine.setStartDate('20110101')
engine.setEndDate('20161231')

# 设置使用的历史数据库
engine.setDatabase(MINUTE_DB_NAME, 'IF0000')

这里MINUTE_DB_NAME

MINUTE_DB_NAME = 'VnTrader_1Min_Db'
  1. 设置产品(合约)相关参数(滑点,佣金,合约大小)。这里回测的合约是股指,滑点设为股指1跳,股指一手每点价格为300元
# 设置产品相关参数
engine.setSlippage(0.2)     # 股指1跳
engine.setRate(0.3/10000)   # 万0.3
engine.setSize(300)         # 股指合约大小    
  1. 在回测引擎中传入策略参数创建策略对象。这里回测vnpy/vn.trader/ctaAlgo/strategyAtrRsi.py里的AtrRsiStrategy策略,策略参数只设置了'atrLength'为11,其它则用策略默认参数。
# 在引擎中创建策略对象
d = {'atrLength': 11}
engine.initStrategy(AtrRsiStrategy, d)

策略的默认参数如下:

# 策略参数
atrLength = 22          # 计算ATR指标的窗口数   
atrMaLength = 10        # 计算ATR均线的窗口数
rsiLength = 5           # 计算RSI的窗口数
rsiEntry = 16           # RSI的开仓信号
trailingPercent = 0.8   # 百分比移动止损
initDays = 10           # 初始化数据所用的天数
fixedSize = 1           # 每次交易的数量
  1. 跑回测
# 开始跑回测
engine.runBacktesting()
  1. 显示回测结果
# 显示回测结果
# spyder或者ipython notebook中运行时,会弹出盈亏曲线图
# 直接在cmd中回测则只会打印一些回测数值
engine.showBacktestingResult()

回测过程中主要步骤的流程图

下面是回测过程主要步骤的流程图,这部分实现对用户回测策略来讲是黑盒,可以不关注。

跑回测主要流程图

Markdown

显示回测结果主要流程图

Markdown

计算回测结果主要流程图

计算回测结果是采用贪婪算法将成交单按时间顺序逐一做开平仓清算。下图只是给出主要的逻辑步骤,具体细节参考代码,即:

def calculateBacktestingResult(self):
    """
    计算回测结果
    """
    ...

Markdown

读懂回测报告

在IPython下运行AtrRsiStrategy策略的回测,示例中使用的是VS2013下的IPython环境。示例中的vnpy代码位于F:\vnpy。读者可自行调整为自己机器上的vnpy代码所在目录。

In [2]: import sys
   ...: sys.path.append('F:\\vnpy\\vn.trader')
   ...: sys.path.append('F:\\vnpy\\vn.trader\ctaAlgo')
   ...: from __future__ import division
   ...: from datetime import datetime, timedelta
   ...: from collections import OrderedDict
   ...: from itertools import product
   ...: import multiprocessing
   ...: import pymongo
   ...: from ctaBase import *
   ...: from ctaSetting import *
   ...: from vtConstant import *
   ...: from vtGateway import VtOrderData, VtTradeData
   ...: from vtFunction import loadMongoSetting
   ...: from ctaBacktesting import *
   ...: from strategyAtrRsi import *
   ...:

In [3]: # 创建回测引擎
   ...: engine = BacktestingEngine()
   ...:

In [4]: # 设置引擎的回测模式为K线
   ...: engine.setBacktestingMode(engine.BAR_MODE)
   ...:
   ...: # 设置回测用的数据起始日期和结束日期
   ...: engine.setStartDate('20110101')
   ...: engine.setEndDate('20161231')
   ...:
   ...: # 设置使用的历史数据库
   ...: engine.setDatabase(MINUTE_DB_NAME, 'IF0000')
   ...:

In [5]: # 设置产品相关参数
   ...: engine.setSlippage(0.2)     # 股指1跳
   ...: engine.setRate(0.3/10000)   # 万0.3
   ...: engine.setSize(300)         # 股指合约大小
   ...:

In [6]: # 在引擎中创建策略对象
   ...: d = {'atrLength': 11}
   ...: engine.initStrategy(AtrRsiStrategy, d)
   ...:

In [7]: # 开始跑回测
   ...: engine.runBacktesting()
   ...:
2017-02-08 19:01:03.243000	开始载入数据
2017-02-08 19:01:03.383000	载入完成,数据量:341851
2017-02-08 19:01:03.383000	开始回测
2017-02-08 19:01:03.396000	策略初始化完成
2017-02-08 19:01:03.396000	策略启动完成
2017-02-08 19:01:03.396000	开始回放数据
2017-02-08 19:01:17.451000	数据回放结束

In [8]: # 显示回测结果
   ...: engine.showBacktestingResult()
   ...:
2017-02-08 19:01:24.706000	计算回测结果
2017-02-08 19:01:24.790000	------------------------------
2017-02-08 19:01:24.790000	第一笔交易:	2011-01-11 13:19:00
2017-02-08 19:01:24.790000	最后一笔交易:	2016-04-01 13:17:00
2017-02-08 19:01:24.790000	总交易次数:	3,965.0
2017-02-08 19:01:24.790000	总盈亏:	695,298.02
2017-02-08 19:01:24.791000	最大回撤: 	-197,106.11
2017-02-08 19:01:24.791000	平均每笔盈利:	175.36
2017-02-08 19:01:24.791000	平均每笔滑点:	120.0
2017-02-08 19:01:24.791000	平均每笔佣金:	57.01
2017-02-08 19:01:24.791000	胜率		36.39%
2017-02-08 19:01:24.791000	盈利交易平均值	8,721.64
2017-02-08 19:01:24.791000	亏损交易平均值	-4,714.52
2017-02-08 19:01:24.791000	盈亏比:	1.85

Markdown

回测报告说明

首先先解释一下回测报告里的交易是什么意思:

  • 以股指IF为例,3000点时开1手多单,3010点平仓,这1手开平仓即为一笔交易。若3000点时开2手多单,3010点平1手,这1手开平仓即为一笔交易;接下来3020点再平1手,这1手开平仓为另一笔交易。
  • 交易时间为平仓时间

计算回测结果字段说明

字段说明
第一笔交易第一笔交易的平仓时间
最后一笔交易最后一笔交易的平仓时间
总交易次数整个回测的总交易次数
总盈亏整个回测的总盈亏,由于回测时初始资金为0,总盈亏其实就是当前资金
最大回撤每次交易后的回撤 = 每笔交易后的资金 - 回测中最大资金。由于回撤为非正值,所以最大回撤为所有交易后的回撤绝对值最大的
平均每笔盈利总盈亏/总交易次数
平均每笔滑点总滑点成本/总交易次数
平均每笔佣金总佣金成本/总交易次数
胜率盈利交易次数/总交易次数*100(%)
盈利交易平均值总盈利交易的盈利/总盈利交易次数
亏损交易平均值总亏损交易的盈利/总亏损交易次数
盈亏比盈利交易平均值/亏损交易平均值

计算回测结果图说明

图里的X轴没有采用交易时间刻度,而是将每笔交易按时间顺序从0开始标成0,1,2,3,4,...

子图名说明
capital每笔交易后的资金序列图
DDdropdown,每笔交易后的回撤序列图
pnlprofit&loss,每笔交易的盈亏直方图(概率分布图)

优化策略参数

策略的参数优化是对指定的优化目标(比如胜率,总盈亏,盈亏比等),回测每个参数的网格组合,从而找到使优化目标最优的参数组合。比如AtrRsiStrategy策略,有七个参数:

# 策略参数
atrLength = 22          # 计算ATR指标的窗口数   
atrMaLength = 10        # 计算ATR均线的窗口数
rsiLength = 5           # 计算RSI的窗口数
rsiEntry = 16           # RSI的开仓信号
trailingPercent = 0.8   # 百分比移动止损
initDays = 10           # 初始化数据所用的天数
fixedSize = 1           # 每次交易的数量

这里面'initDays'可以忽略。如果'atrLength'的取值范围是12-20,步长2;'atrMa'的取值范围是20-30,步长5。这样对于'atrLength'有5个取值[12,14,16,18,20],对于'atrMaLength'有3个取值[20,25,30],总共有5X3, 15个参数组合需要回测。如果设置更多的参数和更小的步长,由于参数的组合数量是幂次方,可想而知需要回测的参数组合的数量相当大,这样就要耗费大量的时间。 优化参数有两种模式:

  • 普通模式
    • Python主进程循环回测每一个参数组合,并输出每个参数组合的运行结果。由于GIL,普通模式下只能使用CPU的一个核。
  • 多进程模式
    • 并行运行多个进程(等于CPU的核个数)回测每一个参数组合,并输出每个参数组合的运行结果。

本节主要讲解普通模式的参数优化。下图为普通模式的参数优化流程图:

Markdown

下表为支持的优化目标键值:

键值值的类型说明
capitalfloat当前资金,单位是元
maxCapitalfloat资金最高净值,单位是元
drawdownfloat当前回撤,单位是元
totalResultint总成交次数
totalTurnoverfloat总成交金额
totalCommissionfloat总手续费
totalSlippagefloat所有交易产生的滑点费用,单位是元
winningRatefloat胜率(%)
averageWinningfloat盈利交易平均值,单位是元
averageLosingfloat亏损交易平均值,单位是元
profitLossRatiofloat盈亏比

参数优化主流程详解

用户只需关注参数优化主流程,这里以AtrRsiStrategy策略为例,对每个步骤结合代码做以下详解:

  1. 对用户来讲,首先要创建回测引擎实例
# 创建回测引擎
engine = BacktestingEngine()
  1. 设置回测引擎的相关参数(回测模式,回测起始日期,数据库)。
# 设置引擎的回测模式为K线
engine.setBacktestingMode(engine.BAR_MODE)

# 设置回测用的数据起始日期和结束日期
engine.setStartDate('20110101')
engine.setEndDate('20161231')

# 载入历史数据到引擎中
engine.setDatabase(MINUTE_DB_NAME, 'IF0000')
  1. 设置产品(合约)相关参数(滑点,佣金,合约大小)。这里回测的合约是股指,滑点设为股指1跳,股指一手每点价格为300元
# 设置产品相关参数
engine.setSlippage(0.2)     # 股指1跳
engine.setRate(0.3/10000)   # 万0.3
engine.setSize(300)         # 股指合约大小    
  1. 创建优化参数实例
# 创建优化参数设置实例
setting = OptimizationSetting()                 # 新建一个优化任务设置对象
  1. 设置优化目标和参数
setting.setOptimizeTarget('capital')            # 设置优化排序的目标是策略净盈利
setting.addParameter('atrLength', 12, 20, 2)    # 增加第一个优化参数atrLength,起始12,结束20,步进2
setting.addParameter('atrMaLength', 20, 30, 5)  # 增加第二个优化参数atrMaLength,起始20,结束30,步进5
setting.addParameter('rsiLength', 5)            # 增加一个固定数值的参数
  1. 运行单进程优化
## 运行单进程优化函数,自动输出结果
engine.runOptimization(AtrRsiStrategy, setting)        

示例在IPython下的运行结果

浮点数由于精度问题,可能会出现误差。由于参数组合是无序字典,所以可能参数组合的回测顺序跟笔者的不一样。笔者电脑上,单进程优化耗时约3分40秒。

In [12]: import sys
   ....: sys.path.append('F:\\vnpy\\vn.trader')
   ....: sys.path.append('F:\\vnpy\\vn.trader\ctaAlgo')
   ....: from __future__ import division
   ....: from datetime import datetime, timedelta
   ....: from collections import OrderedDict
   ....: from itertools import product
   ....: import multiprocessing
   ....: import pymongo
   ....: from ctaBase import *
   ....: from ctaSetting import *
   ....: from vtConstant import *
   ....: from vtGateway import VtOrderData, VtTradeData
   ....: from vtFunction import loadMongoSetting
   ....: from ctaBacktesting import *
   ....: from strategyAtrRsi import *
   ....:

In [13]: # 创建回测引擎
   ....: engine = BacktestingEngine()
   ....:

In [14]: # 设置引擎的回测模式为K线
   ....: engine.setBacktestingMode(engine.BAR_MODE)
   ....:
   ....: # 设置回测用的数据起始日期和结束日期
   ....: engine.setStartDate('20110101')
   ....: engine.setEndDate('20161231')
   ....:
   ....: # 载入历史数据到引擎中
   ....: engine.setDatabase(MINUTE_DB_NAME, 'IF0000')
   ....:

In [15]: # 设置产品相关参数
   ....: engine.setSlippage(0.2)     # 股指1跳
   ....: engine.setRate(0.3/10000)   # 万0.3
   ....: engine.setSize(300)         # 股指合约大小
   ....:

In [16]: # 创建优化参数设置实例
   ....: setting = OptimizationSetting()                 # 新建一个优化任务设置对象
   ....:

In [17]: setting.setOptimizeTarget('capital')            # 设置优化排序的目标是策略净盈利
   ....: setting.addParameter('atrLength', 12, 20, 2)    # 增加第一个优化参数atrLength,起始12,结束20,步进2
   ....: setting.addParameter('atrMaLength', 20, 30, 5)  # 增加第二个优化参数atrMaLength,起始20,结束30,步进5
   ....: setting.addParameter('rsiLength', 5)            # 增加一个固定数值的参数
   ....:

In [18]: ## 运行单进程优化函数,自动输出结果
   ....: engine.runOptimization(AtrRsiStrategy, setting)    
   ....:
2017-02-08 19:06:19.279000	------------------------------
2017-02-08 19:06:19.280000	setting: {'atrMaLength': 20, 'rsiLength': 5, 'atrLength': 12}
2017-02-08 19:06:19.282000	开始载入数据
2017-02-08 19:06:21.034000	载入完成,数据量:341851
2017-02-08 19:06:21.034000	开始回测
2017-02-08 19:06:21.050000	策略初始化完成
2017-02-08 19:06:21.050000	策略启动完成
2017-02-08 19:06:21.050000	开始回放数据
2017-02-08 19:06:35.728000	数据回放结束
2017-02-08 19:06:35.728000	计算回测结果
2017-02-08 19:06:35.923000	------------------------------
2017-02-08 19:06:35.924000	setting: {'atrMaLength': 25, 'rsiLength': 5, 'atrLength': 12}
2017-02-08 19:06:35.925000	开始载入数据
2017-02-08 19:06:36.015000	载入完成,数据量:341851
2017-02-08 19:06:36.015000	开始回测
2017-02-08 19:06:36.030000	策略初始化完成
2017-02-08 19:06:36.030000	策略启动完成
2017-02-08 19:06:36.030000	开始回放数据
2017-02-08 19:06:50.140000	数据回放结束
2017-02-08 19:06:50.140000	计算回测结果
...
2017-02-08 19:09:30.237000	------------------------------
2017-02-08 19:09:30.237000	setting: {'atrMaLength': 25, 'rsiLength': 5, 'atrLength': 20}
2017-02-08 19:09:30.239000	开始载入数据
2017-02-08 19:09:30.330000	载入完成,数据量:341851
2017-02-08 19:09:30.330000	开始回测
2017-02-08 19:09:30.343000	策略初始化完成
2017-02-08 19:09:30.343000	策略启动完成
2017-02-08 19:09:30.343000	开始回放数据
2017-02-08 19:09:44.499000	数据回放结束
2017-02-08 19:09:44.499000	计算回测结果
2017-02-08 19:09:44.696000	------------------------------
2017-02-08 19:09:44.696000	setting: {'atrMaLength': 30, 'rsiLength': 5, 'atrLength': 20}
2017-02-08 19:09:44.697000	开始载入数据
2017-02-08 19:09:44.787000	载入完成,数据量:341851
2017-02-08 19:09:44.787000	开始回测
2017-02-08 19:09:44.801000	策略初始化完成
2017-02-08 19:09:44.801000	策略启动完成
2017-02-08 19:09:44.801000	开始回放数据
2017-02-08 19:09:58.942000	数据回放结束
2017-02-08 19:09:58.942000	计算回测结果
2017-02-08 19:09:59.242000	------------------------------
2017-02-08 19:09:59.242000	优化结果:
2017-02-08 19:09:59.242000	["{'atrMaLength': 30, 'rsiLength': 5, 'atrLength': 20}"]: 1127713.85011
2017-02-08 19:09:59.242000	["{'atrMaLength': 30, 'rsiLength': 5, 'atrLength': 18}"]: 1030743.75807
2017-02-08 19:09:59.242000	["{'atrMaLength': 25, 'rsiLength': 5, 'atrLength': 16}"]: 983294.726285
2017-02-08 19:09:59.242000	["{'atrMaLength': 20, 'rsiLength': 5, 'atrLength': 18}"]: 975329.10312
2017-02-08 19:09:59.242000	["{'atrMaLength': 30, 'rsiLength': 5, 'atrLength': 12}"]: 949746.520421
2017-02-08 19:09:59.242000	["{'atrMaLength': 25, 'rsiLength': 5, 'atrLength': 12}"]: 914875.145592
2017-02-08 19:09:59.243000	["{'atrMaLength': 30, 'rsiLength': 5, 'atrLength': 16}"]: 899113.140024
2017-02-08 19:09:59.243000	["{'atrMaLength': 20, 'rsiLength': 5, 'atrLength': 14}"]: 896378.557181
2017-02-08 19:09:59.243000	["{'atrMaLength': 30, 'rsiLength': 5, 'atrLength': 14}"]: 893726.622984
2017-02-08 19:09:59.243000	["{'atrMaLength': 20, 'rsiLength': 5, 'atrLength': 16}"]: 883947.771514
2017-02-08 19:09:59.243000	["{'atrMaLength': 25, 'rsiLength': 5, 'atrLength': 14}"]: 873221.532605
2017-02-08 19:09:59.243000	["{'atrMaLength': 20, 'rsiLength': 5, 'atrLength': 12}"]: 857260.355525
2017-02-08 19:09:59.243000	["{'atrMaLength': 20, 'rsiLength': 5, 'atrLength': 20}"]: 852615.557093
2017-02-08 19:09:59.243000	["{'atrMaLength': 25, 'rsiLength': 5, 'atrLength': 20}"]: 790618.233326
2017-02-08 19:09:59.243000	["{'atrMaLength': 25, 'rsiLength': 5, 'atrLength': 18}"]: 726949.447939

优化结果的输出格式是:参数组合:优化目标值

多进程优化

本节主要讲解参数的优化的多进程模式。由于Python的GIL原因,多进程模式可以更好的利用CPU的多核,提高优化参数速度。由于vnpy已经提供RPC模块,所以可以基于RPC模块实现分布式参数优化。

多进程参数优化主流程图和优化函数流程图 Markdown

多进程参数优化主流程详解

用户只需关注多进程参数优化主流程,这里以AtrRsiStrategy策略为例,对每个步骤结合代码做以下详解。跟普通模式的参数优化的区别是最后调用多进程优化接口。笔者电脑上,示例中AtrRsiStrategy策略多进程回测的耗时约为52秒。

  1. 对用户来讲,首先要创建回测引擎实例
# 创建回测引擎
engine = BacktestingEngine()
  1. 设置回测引擎的相关参数(回测模式,回测起始日期,数据库)。
# 设置引擎的回测模式为K线
engine.setBacktestingMode(engine.BAR_MODE)

# 设置回测用的数据起始日期和结束日期
engine.setStartDate('20110101')
engine.setEndDate('20161231')

# 载入历史数据到引擎中
engine.setDatabase(MINUTE_DB_NAME, 'IF0000')
  1. 设置产品(合约)相关参数(滑点,佣金,合约大小)。这里回测的合约是股指,滑点设为股指1跳,股指一手每点价格为300元
# 设置产品相关参数
engine.setSlippage(0.2)     # 股指1跳
engine.setRate(0.3/10000)   # 万0.3
engine.setSize(300)         # 股指合约大小    
  1. 创建优化参数实例
# 创建优化参数设置实例
setting = OptimizationSetting()                 # 新建一个优化任务设置对象
  1. 设置优化目标和参数
setting.setOptimizeTarget('capital')            # 设置优化排序的目标是策略净盈利
setting.addParameter('atrLength', 12, 20, 2)    # 增加第一个优化参数atrLength,起始12,结束20,步进2
setting.addParameter('atrMaLength', 20, 30, 5)  # 增加第二个优化参数atrMaLength,起始20,结束30,步进5
setting.addParameter('rsiLength', 5)            # 增加一个固定数值的参数
  1. 运行多进程优化
## 运行多进程优化函数,自动输出结果
engine.runParallelOptimization(AtrRsiStrategy, setting)   
  • 7
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
首先,需要安装好vnpy库,并在vnpy的安装目录下找到vn.trader\app\cta_strategy\strategy_template.py文件,这是vnpy策略模板文件。 接下来,我们根据期货套利策略的需求,对策略模板进行修改。具体而言,我们需要重写以下方法: 1. on_init(self): 用于策略初始化,包括设置参数、订阅合约等。 2. on_start(self): 策略启动时执行的方法。 3. on_stop(self): 策略停止时执行的方法。 4. on_tick(self, tick: TickData): 处理行情数据的方法,用于更新策略的状态。 5. on_trade(self, trade: TradeData): 处理成交数据的方法。 6. on_order(self, order: OrderData): 处理委托数据的方法。 7. on_bar(self, bar: BarData): 处理K线数据的方法,用于实现基于K线的策略。 下面是一个简单的期货套利策略示例,以两个相同品种但不同到期日的期货合约为例。假设当前时间为t,合约A的到期日为t1,合约B的到期日为t2,我们的策略目标是通过买入A合约,卖出B合约来实现套利。当t1-t2的时间差小于某个阈值时,我们就认为A和B之间存在套利机会,此时我们就执行套利交易。 ```python from vnpy.app.cta_strategy import ( CtaTemplate, StopOrder, TickData, BarData, TradeData, OrderData, Direction ) class FuturesArbitrageStrategy(CtaTemplate): """""" author = "Your name" strategy_name = "FuturesArbitrageStrategy" # 策略参数 spread_threshold = 5 # 时间差阈值,以分钟为单位 # 策略变量 long_pos = 0 # 多头持仓 short_pos = 0 # 空头持仓 last_tick_A = None # A合约最新tick数据 last_tick_B = None # B合约最新tick数据 last_trade_A = None # A合约最新成交数据 last_trade_B = None # B合约最新成交数据 parameters = ["spread_threshold"] variables = [ "long_pos", "short_pos", "last_tick_A", "last_tick_B", "last_trade_A", "last_trade_B" ] def on_init(self): """ 策略初始化 """ self.write_log("策略初始化") # 订阅合约 self.subscribe(self.symbol_A, "") self.subscribe(self.symbol_B, "") def on_start(self): """ 策略启动 """ self.write_log("策略启动") def on_stop(self): """ 策略停止 """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ 处理行情数据 """ if tick.vt_symbol == self.symbol_A: self.last_tick_A = tick else: self.last_tick_B = tick # 如果A和B的最新tick数据都存在,就进行套利判断 if self.last_tick_A is not None and self.last_tick_B is not None: t1 = self.last_tick_A.datetime t2 = self.last_tick_B.datetime if abs((t1 - t2).total_seconds() / 60) < self.spread_threshold: self.arbitrage() def on_trade(self, trade: TradeData): """ 处理成交数据 """ if trade.vt_symbol == self.symbol_A: self.last_trade_A = trade else: self.last_trade_B = trade def on_order(self, order: OrderData): """ 处理委托数据 """ pass def on_bar(self, bar: BarData): """ 处理K线数据 """ pass def arbitrage(self): """ 套利交易 """ # 如果A和B的最新成交数据都存在,就进行套利交易 if self.last_trade_A is not None and self.last_trade_B is not None: price_A = self.last_trade_A.price price_B = self.last_trade_B.price if price_A > price_B: # A合约价格高于B合约,执行买入A合约,卖出B合约 self.buy(self.symbol_A, 1, price_A) self.short(self.symbol_B, 1, price_B) else: # A合约价格低于B合约,执行卖出A合约,买入B合约 self.short(self.symbol_A, 1, price_A) self.buy(self.symbol_B, 1, price_B) ``` 以上就是一个简单的期货套利策略的实现,可以使用vnpy回测引擎进行回测。需要注意的是,这个策略只是一个示例,实际的套利策略需要根据具体的市场情况和交易规则进行设计。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值