@Channelchan
2018-11-30T00:09:46.000000Z
字数 6226
阅读 61165
安装vnpy_fxdayu:
https://github.com/xingetouzi/vnpy_fxdayu
from vnpy.trader.app.ctaStrategy import BacktestingEngine
# 创建回测引擎对象
engine = BacktestingEngine()
# 设置回测使用的数据
engine.setBacktestingMode(engine.BAR_MODE) # 设置引擎的回测模式为K线
engine.setDatabase('VnTrader_1Min_Db') # 设置使用的历史数据库
engine.setStartDate('20180901 12:00',initHours=200) # 设置回测用的数据起始日期
engine.setEndDate('20181123 12:00') # 设置回测用的数据终止日期
# 配置回测引擎参数
engine.setSlippage(0.002) # 设置滑点
engine.setRate(5/10000) # 设置手续费千1
engine.setCapital(1000000) # 设置回测本金
参数与变量的区别: 参数用来传递并且可以优化,变量是随着过程的赋值改变的
"""
这里的Demo是一个最简单的双均线策略实现
"""
from __future__ import division
from vnpy.trader.vtConstant import *
from vnpy.trader.app.ctaStrategy import CtaTemplate
import talib as ta
########################################################################
# 策略继承CtaTemplate
class DoubleMaStrategy(CtaTemplate):
"""双指数均线策略Demo"""
className = 'DoubleMaStrategy'
author = 'ChannelCMT'
# 策略参数
fastPeriod = 20 # 快速均线参数
slowPeriod = 55 # 慢速均线参数
lot = 1 # 设置手数
# 策略变量
transactionPrice = {} # 记录成交价格
# 参数列表
paramList = ['fastPeriod',
'slowPeriod']
# 变量列表
varList = ['transactionPrice']
# 同步列表,保存了需要保存到数据库的变量名称
syncList = ['posDict', 'eveningDict']
#----------------------------------------------------------------------
def __init__(self, ctaEngine, setting):
# 首先找到策略的父类(就是类CtaTemplate),然后把DoubleMaStrategy的对象转换为类CtaTemplate的对象
super().__init__(ctaEngine, setting)
#----------------------------------------------------------------------
def onInit(self):
"""初始化策略"""
self.writeCtaLog(u'策略初始化')
self.transactionPrice = {s:0 for s in self.symbolList} # 生成成交价格的字典
self.putEvent()
#----------------------------------------------------------------------
def onStart(self):
"""启动策略(必须由用户继承实现)"""
self.writeCtaLog(u'策略启动')
self.putEvent()
#----------------------------------------------------------------------
def onStop(self):
"""停止策略"""
self.writeCtaLog(u'策略停止')
self.putEvent()
#----------------------------------------------------------------------
def onTick(self, tick):
"""收到行情TICK推送"""
pass
#----------------------------------------------------------------------
def on60MinBar(self, bar):
"""收到60分钟Bar推送"""
symbol = bar.vtSymbol
am60 = self.getArrayManager(symbol, "60m") # 获取历史数组
if not am60.inited:
return
# 计算策略需要的信号-------------------------------------------------
fastMa = ta.EMA(am60.close, self.fastPeriod)
slowMa = ta.EMA(am60.close, self.slowPeriod)
crossOver = (fastMa[-1]>slowMa[-1]) and (fastMa[-2]<=slowMa[-2]) # 金叉上穿
crossBelow = (fastMa[-1]<slowMa[-1]) and (fastMa[-2]>=slowMa[-2]) # 死叉下穿
# 构建进出场逻辑-------------------------------------------------
# 如果金叉时手头没有多头持仓
if (crossOver) and (self.posDict[symbol+'_LONG']==0):
# 如果没有空头持仓,则直接做多
if self.posDict[symbol+'_SHORT']==0:
self.buy(symbol, bar.close*1.01, self.lot) # 成交价*1.01发送高价位的限价单,以最优市价买入进场
# 如果有空头持仓,则先平空,再做多
elif self.posDict[symbol+'_SHORT'] > 0:
self.cancelAll() # 撤销挂单
self.cover(symbol, bar.close*1.01, self.posDict[symbol+'_SHORT'])
self.buy(symbol, bar.close*1.01, self.lot)
# 如果金叉时手头没有空头持仓
elif (crossBelow) and (self.posDict[symbol+'_SHORT']==0):
if self.posDict[symbol+'_LONG']==0:
self.short(symbol, bar.close*0.99, self.lot) # 成交价*0.99发送低价位的限价单,以最优市价卖出进场
elif self.posDict[symbol+'_LONG'] > 0:
self.cancelAll() # 撤销挂单
self.sell(symbol, bar.close*0.99, self.posDict[symbol+'_LONG'])
self.short(symbol, bar.close*0.99, self.lot)
# 发出状态更新事件
self.putEvent()
#----------------------------------------------------------------------
def onOrder(self, order):
"""收到委托变化推送"""
# 对于无需做细粒度委托控制的策略,可以忽略onOrder
pass
#----------------------------------------------------------------------
def onTrade(self, trade):
"""收到成交推送"""
symbol = trade.vtSymbol
if trade.offset == OFFSET_OPEN: # 判断成交订单类型
self.transactionPrice[symbol] = trade.price # 记录成交价格
#----------------------------------------------------------------------
def onStopOrder(self, so):
"""停止单推送"""
pass
# 在引擎中创建策略对象
parameterDict = {'symbolList':['EOSUSDT:binance']} # 策略参数配置
engine.initStrategy(DoubleMaStrategy, parameterDict) # 创建策略对象
engine.runBacktesting()
import pandas as pd
tradeReport = pd.DataFrame([obj.__dict__ for obj in engine.tradeDict.values()])
tradeDf = tradeReport.set_index('dt')
tradeDf.tail()
# 显示逐日回测结果
engine.showDailyResult()
2018-11-27 16:38:28.461857 计算按日统计结果
2018-11-27 16:38:28.481836 ------------------------------
2018-11-27 16:38:28.481836 首个交易日: 2018-09-01 00:00:00
2018-11-27 16:38:28.481836 最后交易日: 2018-11-23 00:00:00
2018-11-27 16:38:28.481836 总交易日: 84
2018-11-27 16:38:28.481836 盈利交易日 39
2018-11-27 16:38:28.481836 亏损交易日: 42
2018-11-27 16:38:28.481836 起始资金: 1000000
2018-11-27 16:38:28.481836 结束资金: 1,000,002.22
2018-11-27 16:38:28.481836 总收益率: 0.0%
2018-11-27 16:38:28.481836 年化收益: 0.0%
2018-11-27 16:38:28.481836 总盈亏: 2.22
2018-11-27 16:38:28.481836 最大回撤: -1.26
2018-11-27 16:38:28.481836 百分比最大回撤: -0.0%
2018-11-27 16:38:28.481836 总手续费: 0.14
2018-11-27 16:38:28.481836 总滑点: 0.1
2018-11-27 16:38:28.482835 总成交金额: 271.25
2018-11-27 16:38:28.482835 总成交笔数: 49
2018-11-27 16:38:28.482835 日均盈亏: 0.03
2018-11-27 16:38:28.482835 日均手续费: 0.0
2018-11-27 16:38:28.482835 日均滑点: 0.0
2018-11-27 16:38:28.482835 日均成交金额: 3.23
2018-11-27 16:38:28.482835 日均成交笔数: 0.58
2018-11-27 16:38:28.482835 日均收益率: 0.0%
2018-11-27 16:38:28.482835 收益标准差: 0.0%
2018-11-27 16:38:28.482835 Sharpe Ratio: 2.21
# 显示逐笔回测结果
engine.showBacktestingResult()
2018-11-27 16:38:29.848438 计算回测结果
2018-11-27 16:38:29.854432 ------------------------------
2018-11-27 16:38:29.854432 第一笔交易: 2018-09-05 00:00:00
2018-11-27 16:38:29.854432 最后一笔交易: 2018-11-23 11:58:00
2018-11-27 16:38:29.854432 总交易次数: 25
2018-11-27 16:38:29.854432 总盈亏: 2.21
2018-11-27 16:38:29.854432 最大回撤: -1.02
2018-11-27 16:38:29.854432 平均每笔盈利: 0.09
2018-11-27 16:38:29.854432 平均每笔滑点: 0.0
2018-11-27 16:38:29.854432 平均每笔佣金: 0.01
2018-11-27 16:38:29.854432 胜率 40.0%
2018-11-27 16:38:29.854432 盈利交易平均值 0.44
2018-11-27 16:38:29.854432 亏损交易平均值 -0.15
2018-11-27 16:38:29.854432 盈亏比: 2.99
df = engine.calculateDailyResult()
df1, result = engine.calculateDailyStatistics(df)
2018-11-27 16:38:30.473799 计算按日统计结果
print(pd.Series(result)) # 显示绩效指标
annualizedReturn 0.000633478
dailyCommission 0.00161459
dailyNetPnl 0.0263949
dailyReturn 2.63949e-06
dailySlippage 0.00116667
dailyTradeCount 0.583333
dailyTurnover 3.22919
endBalance 1e+06
endDate 2018-11-23 00:00:00
lossDays 42
maxDdPercent -0.000125684
maxDrawdown -1.25684
profitDays 39
returnStd 1.85059e-05
sharpeRatio 2.20961
startDate 2018-09-01 00:00:00
totalCommission 0.135626
totalDays 84
totalNetPnl 2.21717
totalReturn 0.000221717
totalSlippage 0.098
totalTradeCount 49
totalTurnover 271.252
dtype: object