@Channelchan
2018-11-28T10:09:02.000000Z
字数 20120
阅读 63510
1、金字塔加仓法
2、 金字塔加仓法优化
金字塔加仓法是一种逐级加仓模式,其加仓数量与盈利(亏损)幅度成反比,加仓手数如图,图中数值分别为每次加仓手数占总仓位百分比:

见 onBar ‘金字塔加仓模块’以及on30MinBar‘进出场逻辑模块’
用参数 n 控制加仓次数,参数 Ratio 控制加仓的进场位置,参数fixsize控制最大仓位手数
则第一次开仓到第五次加满仓的手数分别为fixsize*0.3,fixsize*0.25,fixsize*0.20,fixsize*0.15,fixsize*0.10
if 持多头仓位 and 当前加仓次数 nPos < 3:
if 亏损达到Ratio/100:
nPos = nPos+1
加仓fixsize*(0.3-0.05*nPos)手数
elif 持空头仓位 and 当前加仓次数 nPos < 3:
if 亏损达到Ratio:
nPos = nPos+1
加仓fixsize*(0.3-0.05*nPos)手数
if 持有多头仓位 and 死叉:
nPos = 0
elif 持有空头仓位 and 金叉:
nPos = 0
## 大的价格除以小的价格减1lastOrder=self.transactionPrice[symbol]## 多头亏损大于一个百分比(self.transactionPrice[symbol] - bar.close)/bar.close= lastOrder/bar.close-1## 多头盈利大于一个百分比(bar.close-self.transactionPrice[symbol])/self.transactionPrice[symbol]= bar.close/lastOrder-1## 空头亏损大于一个百分比(bar.close - self.transactionPrice[symbol])/self.transactionPrice[symbol]= bar.close/lastOrder-1## 空头盈利大于一个百分比(self.transactionPrice[symbol] - bar.close)/bar.close= lastOrder/bar.close-1
# 设置参数nPos = 0fixsize = 100transactionPrice = {}Ratio = 0.02# 设置变量self.transactionPrice = {s: 0 for s in self.symbolList}#----------------------------------------------------------------------def onBar(self, bar):"""收到Bar推送"""symbol = bar.vtSymbollastOrder=self.transactionPrice[symbol]# 金字塔加仓模块______________________________________if (self.posDict[symbol+'_LONG']!=0 and self.nPos < 3): # 持有多头仓位并且加仓次数不超过3次if bar.close/lastOrder-1>= self.Ratio: # 计算盈利比例,达到2%self.nPos += 1 # 加仓次数减少 1 次self.buy(symbol,bar.close*1.02,self.fixsize*(0.3-0.05*self.nPos)) # 目标仓位100手,分别加仓25手、20手、15手,10手elif (self.posDict[symbol + "_SHORT"] != 0 and self.nPos < 3): # 持有空头仓位并且加仓次数不超过3次if lastOrder/bar.close-1 >= self.Ratio: # 计算盈利比例,达到2%self.nPos += 1 # 加仓次数减少 1 次self.short(symbol,bar.close*0.98,self.fixsize*(0.3-0.05*self.nPos)) # 目标仓位100手,分别加仓25手、20手、15手,10手# 发出状态更新事件self.putEvent()def on30MinBar(self, bar):"""30分钟K线推送"""symbol = bar.vtSymbolam30 = self.getArrayManager(symbol, "30m")if not am30.inited:return# 计算策略需要的信号-------------------------------------------------fastMa = ta.EMA(am30.close, self.fastWindow)slowMa = ta.EMA(am30.close, self.slowWindow)crossOver = fastMa[-1]>slowMa[-1] and fastMa[-2]<=slowMa[-2] # 金叉上穿crossBelow = fastMa[-1]<slowMa[-1] and fastMa[-2]>=slowMa[-2] # 死叉下穿if crossOver:print('crossOver:',crossOver)elif crossBelow:print('crossBelow:',crossBelow)# 构建进出场逻辑-------------------------------------------------# 金叉和死叉的条件是互斥if crossOver:# 如果金叉时手头没有持仓,则直接做多if (self.posDict[symbol+'_LONG']==0) and (self.posDict[symbol+'_SHORT']==0):self.buy(symbol, bar.close*1.02, self.fixsize*0.3)# 如果有空头持仓,则先平空,再做多elif self.posDict[symbol+'_SHORT'] >0:self.cancelAll()self.cover(symbol,bar.close*1.02, self.posDict[symbol+'_SHORT'])self.nPos = 0self.buy(symbol,bar.close*1.02, self.fixsize*0.3)# 死叉和金叉相反elif crossBelow :if (self.posDict[symbol+'_LONG']==0) and (self.posDict[symbol+'_SHORT']==0):self.short(symbol,bar.close*0.98, self.fixsize*0.3)elif self.posDict[symbol+'_LONG'] >0:self.cancelAll()self.sell(symbol,bar.close*0.98, self.posDict[symbol+'_LONG'])self.nPos = 0self.short(symbol,bar.close*0.98, self.fixsize*0.3)# 发出状态更新事件self.putEvent()
"""这里的Demo是一个最简单的双均线策略实现"""from __future__ import divisionfrom vnpy.trader.vtConstant import *from vnpy.trader.app.ctaStrategy.ctaBarManager import CtaTemplateimport numpy as npimport talib as tafrom datetime import timedelta######################################################################### 策略继承CtaTemplateclass DoubleMaStrategy(CtaTemplate):"""双指数均线策略Demo"""className = 'DoubleMaStrategy'author = 'ChannelCMT'# 策略参数barPeriod = 200fastWindow = 60 # 快速均线参数slowWindow = 120 # 慢速均线参数# 参数列表,保存了参数的名称paramList = ['name','className','author','fastWindow','slowWindow']# 变量列表,保存了变量的名称varList = ['barPeriod']nPos = 0fixsize = 100transactionPrice = {}Ratio = 0.02# 同步列表,保存了需要保存到数据库的变量名称syncList = ['posDict', 'eveningDict']#----------------------------------------------------------------------def __init__(self, ctaEngine, setting):# 首先找到策略的父类(就是类CtaTemplate),然后把DoubleMaStrategy的对象转换为类CtaTemplate的对象super().__init__(ctaEngine, setting)#----------------------------------------------------------------------def onInit(self):"""初始化策略(必须由用户继承实现)"""self.writeCtaLog(u'双EMA演示策略初始化')# 生成Bar数组self.setArrayManagerSize(self.barPeriod)self.transactionPrice = {s: 0 for s in self.symbolList}self.mail("chushihuaaaaaaaaaaaaaaaaaaaaaaaaa")self.putEvent()#----------------------------------------------------------------------def onStart(self):"""启动策略(必须由用户继承实现)"""self.writeCtaLog(u'双EMA演示策略启动')self.putEvent()#----------------------------------------------------------------------def onStop(self):"""停止策略(必须由用户继承实现)"""self.writeCtaLog(u'策略停止')self.putEvent()#----------------------------------------------------------------------def onTick(self, tick):"""收到行情TICK推送(必须由用户继承实现)"""pass#----------------------------------------------------------------------def onBar(self, bar):"""收到Bar推送"""symbol = bar.vtSymbollastOrder=self.transactionPrice[symbol]# 金字塔加仓模块______________________________________if (self.posDict[symbol+'_LONG']!=0 and self.nPos < 3): # 持有多头仓位并且加仓次数不超过3次if bar.close/lastOrder-1>= self.Ratio: # 计算盈利比例,达到2%self.nPos += 1 # 加仓次数减少 1 次self.buy(symbol,bar.close*1.02,self.fixsize*(0.3-0.05*self.nPos)) # 目标仓位100手,分别加仓25手、20手、15手,10手elif (self.posDict[symbol + "_SHORT"] != 0 and self.nPos < 3): # 持有空头仓位并且加仓次数不超过3次if lastOrder/bar.close-1 >= self.Ratio: # 计算盈利比例,达到2%self.nPos += 1 # 加仓次数减少 1 次self.short(symbol,bar.close*0.98,self.fixsize*(0.3-0.05*self.nPos)) # 目标仓位100手,分别加仓25手、20手、15手,10手# 发出状态更新事件self.putEvent()def on30MinBar(self, bar):"""30分钟K线推送"""symbol = bar.vtSymbolam30 = self.getArrayManager(symbol, "30m")if not am30.inited:return# 计算策略需要的信号-------------------------------------------------fastMa = ta.EMA(am30.close, self.fastWindow)slowMa = ta.EMA(am30.close, self.slowWindow)crossOver = fastMa[-1]>slowMa[-1] and fastMa[-2]<=slowMa[-2] # 金叉上穿crossBelow = fastMa[-1]<slowMa[-1] and fastMa[-2]>=slowMa[-2] # 死叉下穿if crossOver:print('crossOver:',crossOver)elif crossBelow:print('crossBelow:',crossBelow)# 构建进出场逻辑-------------------------------------------------# 金叉和死叉的条件是互斥if crossOver:# 如果金叉时手头没有持仓,则直接做多if (self.posDict[symbol+'_LONG']==0) and (self.posDict[symbol+'_SHORT']==0):self.buy(symbol, bar.close*1.02, self.fixsize*0.3)# 如果有空头持仓,则先平空,再做多elif self.posDict[symbol+'_SHORT'] >0:self.cancelAll()self.cover(symbol,bar.close*1.02, self.posDict[symbol+'_SHORT'])self.nPos = 0self.buy(symbol,bar.close*1.02, self.fixsize*0.3)# 死叉和金叉相反elif crossBelow :if (self.posDict[symbol+'_LONG']==0) and (self.posDict[symbol+'_SHORT']==0):self.short(symbol,bar.close*0.98, self.fixsize*0.3)elif self.posDict[symbol+'_LONG'] >0:self.cancelAll()self.sell(symbol,bar.close*0.98, self.posDict[symbol+'_LONG'])self.nPos = 0self.short(symbol,bar.close*0.98, self.fixsize*0.3)# 发出状态更新事件self.putEvent()#----------------------------------------------------------------------def onOrder(self, order):"""收到委托变化推送(必须由用户继承实现)"""# 对于无需做细粒度委托控制的策略,可以忽略onOrder# print(u'出现未知订单,需要策略师外部干预,ID:%s, symbol:%s,direction:%s,offset:%s'% (order.vtOrderID, order.vtSymbol, order.direction, order.offset))pass#----------------------------------------------------------------------def onTrade(self, trade):"""收到成交推送(必须由用户继承实现)"""symbol = trade.vtSymbolself.transactionPrice[symbol] = trade.pricepass#----------------------------------------------------------------------def onStopOrder(self, so):"""停止单推送"""pass
from vnpy.trader.app.ctaStrategy.ctaBarManager import BacktestingEngineimport pandas as pddef runBacktesting(strategyClass, settingDict,startDate, endDate, size, slippage, rate):engine = BacktestingEngine()engine.setBacktestingMode(engine.BAR_MODE)engine.setDatabase('VnTrader_1Min_Db')engine.setStartDate(startDate, initHours=200)engine.setEndDate(endDate)engine.setSize(size)engine.setSlippage(slippage)engine.setRate(rate)engine.initStrategy(strategyClass, settingDict)engine.setCapital(100000)engine.setLog(True, 'E://log//')engine.runBacktesting()#显示逐日回测结果engine.showDailyResult()#显示逐笔回测结果engine.showBacktestingResult()# 计算回测结果perfromance = engine.calculateDailyResult()perfromanceDf , result = engine.calculateDailyStatistics(perfromance)tradeReport = pd.DataFrame([obj.__dict__ for obj in engine.tradeDict.values()])tradeDf = tradeReport.set_index('dt')return perfromanceDf, tradeDfif __name__ == '__main__':# 同时传入信号与执行的数据performanceReport, tradeReport = \runBacktesting(DoubleMaStrategy, {'symbolList': ['BTCUSDT:binance']},'20181001 12:00', '20181031 16:00', 100, 0, 5/10000)# tradeReport.to_excel('BBandMa5MinStrategyReport.xlsx')
2018-11-15 17:09:14.809911 计算按日统计结果
2018-11-15 17:09:14.857881 ------------------------------
2018-11-15 17:09:14.857881 首个交易日: 2018-10-01 00:00:00
2018-11-15 17:09:14.857881 最后交易日: 2018-10-31 00:00:00
2018-11-15 17:09:14.857881 总交易日: 31
2018-11-15 17:09:14.857881 盈利交易日 18
2018-11-15 17:09:14.857881 亏损交易日: 13
2018-11-15 17:09:14.857881 起始资金: 100000
2018-11-15 17:09:14.857881 结束资金: 1,051,594.31
2018-11-15 17:09:14.857881 总收益率: 951.59%
2018-11-15 17:09:14.857881 年化收益: 7,367.18%
2018-11-15 17:09:14.857881 总盈亏: 951,594.31
2018-11-15 17:09:14.858881 最大回撤: -3,153,690.0
2018-11-15 17:09:14.858881 百分比最大回撤: -165.86%
2018-11-15 17:09:14.858881 总手续费: 204,385.69
2018-11-15 17:09:14.858881 总滑点: 0.0
2018-11-15 17:09:14.858881 总成交金额: 408,771,380.0
2018-11-15 17:09:14.858881 总成交笔数: 19
2018-11-15 17:09:14.858881 日均盈亏: 30,696.59
2018-11-15 17:09:14.858881 日均手续费: 6,593.09
2018-11-15 17:09:14.858881 日均滑点: 0.0
2018-11-15 17:09:14.858881 日均成交金额: 13,186,173.55
2018-11-15 17:09:14.858881 日均成交笔数: 0.61
2018-11-15 17:09:14.858881 日均收益率: 0.63%
2018-11-15 17:09:14.858881 收益标准差: 130.5%
2018-11-15 17:09:14.859880 Sharpe Ratio: 0.07
2018-11-15 17:09:15.731470 策略回测绩效图已保存

2018-11-15 17:09:16.499001 计算回测结果
2018-11-15 17:09:16.507002 交割单已生成
2018-11-15 17:09:16.507992 ------------------------------
2018-11-15 17:09:16.507992 第一笔交易: 2018-10-04 22:30:00
2018-11-15 17:09:16.507992 最后一笔交易: 2018-10-31 15:58:00
2018-11-15 17:09:16.507992 总交易次数: 14
2018-11-15 17:09:16.507992 总盈亏: 934,175.86
2018-11-15 17:09:16.507992 最大回撤: -570,710.25
2018-11-15 17:09:16.507992 平均每笔盈利: 66,726.85
2018-11-15 17:09:16.507992 平均每笔滑点: 0.0
2018-11-15 17:09:16.507992 平均每笔佣金: 15,843.15
2018-11-15 17:09:16.507992 胜率 50.0%
2018-11-15 17:09:16.507992 盈利交易平均值 320,543.11
2018-11-15 17:09:16.507992 亏损交易平均值 -187,089.42
2018-11-15 17:09:16.507992 盈亏比: 1.71
2018-11-15 17:09:17.148822 策略回测统计图已保存

2018-11-15 17:09:17.684494 计算按日统计结果
tradeReport
金字塔加仓法缺点是第一次入场仓位较重,而后加仓手数较轻,则可以适当提高第一次开仓的要求,同时降低后面加仓的要求
见 onBar 和0n30MinBar‘优化金字塔加仓模块’
用参数 n 控制加仓次数,参数 Ratio 控制加仓的进场位置,参数fixsize控制最大仓位手数,参数condition和tmp作为临时变量控制加仓逻辑。
if 金叉 and 多头排列:
开多单,仓位 = fixsize*0.3
elif 死叉 and 空头排列:
开空单,仓位 = fixsize*0.3
if 持多头仓位 and 股价与短均线死叉:
tmp = 1
elif 持空头仓位 and 股价与短均线金叉:
tmp = -1
if tmp == 1 and 股价与短均线金叉:
condition = 1
elif tmp == -1 and 股价与短均线死叉:
condition = -1
if 持多头仓位 and 当前加仓次数 nPos< 5:
if 当前处于盈利状态 and condition == 1:
nPos = nPos+1
加仓fixsize*(0.3-0.05*nPos)手数
tmp,condition = 0,0
elif 持空头仓位 and 当前加仓次数 nPos< 5:
if 当前处于盈利状态 and condition == -1:
nPos= nPos+1
加仓fixsize*(0.3-0.05*nPos)手数
tmp,condition = 0,0
if 持有多头仓位 and 死叉:
nPos = 0
elif 持有空头仓位 and 金叉:
nPos = 0
# 设置参数nPos = 0fixsize = 100transactionPrice = {}Ratio = 100tmp = 0condition = 0# 设置变量self.transactionPrice = {s: 0 for s in self.symbolList}#----------------------------------------------------------------------def onBar(self, bar):"""收到Bar推送(必须由用户继承实现)"""symbol = bar.vtSymbolam = self.getArrayManager(symbol, "1m")if not am.inited:return# 优化金字塔加仓模块________________________________________________if (self.posDict[symbol+'_LONG']!=0 and self.nPos < 5): # 持有多头仓位并且加仓次数不超过5次if self.transactionPrice[symbol]>bar.close and self.condition == 1: # 当前是盈利状况,并且满足上述加仓条件self.nPos += 1 # 加仓次数减少 1 次self.buy(symbol,bar.close*1.02,self.fixsize*(0.3-self.nPos*0.05)) # 目标加仓100手 分别为加仓 30手、25手、20手,15手,10手self.tmp = 0 # 置零两个临时的控制变量self.condition = 0elif (self.posDict[symbol + "_SHORT"] != 0 and self.nPos < 5): # 持有空头仓位并且加仓次数不超过5次if bar.close>self.transactionPrice[symbol] and self.condition == -1: # 当前是盈利状况,并且满足上述加仓条件self.nPos += 1 # 加仓次数减少 1 次self.short(symbol,bar.close*0.98,self.fixsize*(0.3-self.nPos*0.05)) # 目标加仓100手 分别为加仓 30手、25手、20手,15手,10手self.tmp = 0 # 置零两个临时的控制变量self.condition = 0# 发出状态更新事件self.putEvent()def on30MinBar(self, bar):"""30分钟K线推送"""symbol = bar.vtSymbolam30 = self.getArrayManager(symbol, "30m")if not am30.inited:return# 计算策略需要的信号-------------------------------------------------fastMa = ta.EMA(am30.close, self.fastWindow)slowMa = ta.EMA(am30.close, self.slowWindow)# 优化金字塔加仓模块________________________________________________price_crossOver = am30.close[-1]>fastMa[-1] and am30.close[-2]<fastMa[-2] # 估价金叉短均线price_crossBelow = am30.close[-1]<fastMa[-1] and am30.close[-2]>fastMa[-2] # 估价死叉短均线if self.posDict[symbol+'_LONG']!=0 and price_crossBelow: # 持有多头仓位,并且估价死叉短均线self.tmp = 1 # 临时变量,记录死叉现象elif self.posDict[symbol + "_SHORT"] != 0 and price_crossOver: # 持有多头仓位,并且估价金叉短均线self.tmp = -1 # 临时变量,记录金叉现象if self.tmp == 1 and price_crossOver: # 多头持仓中,发生死叉后金叉,即回调后再次上次,满足加仓条件self.condition = 1elif self.tmp == -1 and price_crossBelow: # 空头持仓中,发生金叉后死叉,即回调后再次下跌,满足加仓条件self.condition = -1
"""这里的Demo是一个最简单的双均线策略实现"""from __future__ import divisionfrom vnpy.trader.vtConstant import *from vnpy.trader.app.ctaStrategy.ctaBarManager import CtaTemplateimport numpy as npimport talib as tafrom datetime import timedelta######################################################################### 策略继承CtaTemplateclass DoubleMaStrategy(CtaTemplate):"""双指数均线策略Demo"""className = 'DoubleMaStrategy'author = 'ChannelCMT'# 策略参数barPeriod = 200fastWindow = 60 # 快速均线参数slowWindow = 120 # 慢速均线参数# 参数列表,保存了参数的名称paramList = ['name','className','author','fastWindow','slowWindow']# 变量列表,保存了变量的名称varList = ['barPeriod']nPos = 0fixsize = 100transactionPrice = {}Ratio = 100tmp = 0condition = 0# 同步列表,保存了需要保存到数据库的变量名称syncList = ['posDict', 'eveningDict']#----------------------------------------------------------------------def __init__(self, ctaEngine, setting):# 首先找到策略的父类(就是类CtaTemplate),然后把DoubleMaStrategy的对象转换为类CtaTemplate的对象super().__init__(ctaEngine, setting)#----------------------------------------------------------------------def onInit(self):"""初始化策略(必须由用户继承实现)"""self.writeCtaLog(u'双EMA演示策略初始化')# 生成Bar数组self.setArrayManagerSize(self.barPeriod)self.transactionPrice = {s: 0 for s in self.symbolList}self.mail("chushihuaaaaaaaaaaaaaaaaaaaaaaaaa")self.putEvent()#----------------------------------------------------------------------def onStart(self):"""启动策略(必须由用户继承实现)"""self.writeCtaLog(u'双EMA演示策略启动')self.putEvent()#----------------------------------------------------------------------def onStop(self):"""停止策略(必须由用户继承实现)"""self.writeCtaLog(u'策略停止')self.putEvent()#----------------------------------------------------------------------def onTick(self, tick):"""收到行情TICK推送(必须由用户继承实现)"""pass#----------------------------------------------------------------------def onBar(self, bar):"""收到Bar推送"""symbol = bar.vtSymbolam = self.getArrayManager(symbol, "1m")if not am.inited:return# 优化金字塔加仓模块________________________________________________if (self.posDict[symbol+'_LONG']!=0 and self.nPos < 5): # 持有多头仓位并且加仓次数不超过5次if self.transactionPrice[symbol]>bar.close and self.condition == 1: # 当前是盈利状况,并且满足上述加仓条件self.nPos += 1 # 加仓次数减少 1 次self.buy(symbol,bar.close*1.02,self.fixsize*(0.3-self.nPos*0.05)) # 目标加仓100手 分别为加仓 30手、25手、20手,15手,10手self.tmp = 0 # 置零两个临时的控制变量self.condition = 0elif (self.posDict[symbol + "_SHORT"] != 0 and self.nPos < 5): # 持有空头仓位并且加仓次数不超过5次if bar.close>self.transactionPrice[symbol] and self.condition == -1: # 当前是盈利状况,并且满足上述加仓条件self.nPos += 1 # 加仓次数减少 1 次self.short(symbol,bar.close*0.98,self.fixsize*(0.3-self.nPos*0.05)) # 目标加仓100手 分别为加仓 30手、25手、20手,15手,10手self.tmp = 0 # 置零两个临时的控制变量self.condition = 0# 发出状态更新事件self.putEvent()def on30MinBar(self, bar):"""30分钟K线推送"""symbol = bar.vtSymbolam30 = self.getArrayManager(symbol, "30m")if not am30.inited:return# 计算策略需要的信号-------------------------------------------------fastMa = ta.EMA(am30.close, self.fastWindow)slowMa = ta.EMA(am30.close, self.slowWindow)# 优化金字塔加仓模块________________________________________________price_crossOver = am30.close[-1]>fastMa[-1] and am30.close[-2]<fastMa[-2] # 估价金叉短均线price_crossBelow = am30.close[-1]<fastMa[-1] and am30.close[-2]>fastMa[-2] # 估价死叉短均线if self.posDict[symbol+'_LONG']!=0 and price_crossBelow: # 持有多头仓位,并且估价死叉短均线self.tmp = 1 # 临时变量,记录死叉现象elif self.posDict[symbol + "_SHORT"] != 0 and price_crossOver: # 持有多头仓位,并且估价金叉短均线self.tmp = -1 # 临时变量,记录金叉现象if self.tmp == 1 and price_crossOver: # 多头持仓中,发生死叉后金叉,即回调后再次上次,满足加仓条件self.condition = 1elif self.tmp == -1 and price_crossBelow: # 空头持仓中,发生金叉后死叉,即回调后再次下跌,满足加仓条件self.condition = -1crossOver = fastMa[-1]>slowMa[-1] and fastMa[-2]<=slowMa[-2] # 金叉上穿crossBelow = fastMa[-1]<slowMa[-1] and fastMa[-2]>=slowMa[-2] # 死叉下穿long = fastMa[-1]>fastMa[-2] and slowMa[-1]>slowMa[-2] # 多头排列short = fastMa[-1]<fastMa[-2] and slowMa[-1]<slowMa[-2] # 空头排列# 构建进出场逻辑-------------------------------------------------# 金叉和死叉的条件是互斥,多头和空头排列条件互斥if crossOver and long:# 如果金叉时手头没有持仓,则直接做多if (self.posDict[symbol+'_LONG']==0) and (self.posDict[symbol+'_SHORT']==0):self.buy(symbol, bar.close*1.02, self.fixsize*0.3)# 如果有空头持仓,则先平空,再做多elif self.posDict[symbol+'_SHORT'] >0:self.cancelAll()self.cover(symbol,bar.close*1.02, self.posDict[symbol+'_SHORT'])self.nPos = 0self.buy(symbol,bar.close*1.02, self.fixsize*0.3)# 死叉和金叉相反elif crossBelow and short:if (self.posDict[symbol+'_LONG']==0) and (self.posDict[symbol+'_SHORT']==0):self.short(symbol,bar.close*0.98, self.fixsize*0.3)elif self.posDict[symbol+'_LONG'] >0:self.cancelAll()self.sell(symbol,bar.close*0.98, self.posDict[symbol+'_LONG'])self.nPos = 0self.short(symbol,bar.close*0.98, self.fixsize*0.3)# 发出状态更新事件self.putEvent()#----------------------------------------------------------------------def onOrder(self, order):"""收到委托变化推送(必须由用户继承实现)"""# 对于无需做细粒度委托控制的策略,可以忽略onOrder# print(u'出现未知订单,需要策略师外部干预,ID:%s, symbol:%s,direction:%s,offset:%s'% (order.vtOrderID, order.vtSymbol, order.direction, order.offset))pass#----------------------------------------------------------------------def onTrade(self, trade):"""收到成交推送(必须由用户继承实现)"""symbol = trade.vtSymbolself.transactionPrice[symbol] = trade.pricepass#----------------------------------------------------------------------def onStopOrder(self, so):"""停止单推送"""pass
from vnpy.trader.app.ctaStrategy.ctaBarManager import BacktestingEngineimport pandas as pddef runBacktesting(strategyClass, settingDict,startDate, endDate, size, slippage, rate):engine = BacktestingEngine()engine.setBacktestingMode(engine.BAR_MODE)engine.setDatabase('VnTrader_1Min_Db')engine.setStartDate(startDate, initHours=200)engine.setEndDate(endDate)engine.setSize(size)engine.setSlippage(slippage)engine.setRate(rate)engine.initStrategy(strategyClass, settingDict)engine.setCapital(100000)engine.setLog(True, 'E://log//')engine.runBacktesting()#显示逐日回测结果engine.showDailyResult()#显示逐笔回测结果engine.showBacktestingResult()# 计算回测结果perfromance = engine.calculateDailyResult()perfromanceDf , result = engine.calculateDailyStatistics(perfromance)tradeReport = pd.DataFrame([obj.__dict__ for obj in engine.tradeDict.values()])tradeDf = tradeReport.set_index('dt')return perfromanceDf, tradeDfif __name__ == '__main__':# 同时传入信号与执行的数据performanceReport, tradeReport = \runBacktesting(DoubleMaStrategy, {'symbolList': ['BTCUSDT:binance']},'20181001 12:00', '20181031 16:00', 100, 0, 5/10000)# tradeReport.to_excel('BBandMa5MinStrategyReport.xlsx')
2018-11-15 17:27:50.932043 计算按日统计结果
2018-11-15 17:27:50.965024 ------------------------------
2018-11-15 17:27:50.965024 首个交易日: 2018-10-01 00:00:00
2018-11-15 17:27:50.965024 最后交易日: 2018-10-31 00:00:00
2018-11-15 17:27:50.965024 总交易日: 31
2018-11-15 17:27:50.965024 盈利交易日 18
2018-11-15 17:27:50.965024 亏损交易日: 13
2018-11-15 17:27:50.965024 起始资金: 100000
2018-11-15 17:27:50.965024 结束资金: 2,709,496.33
2018-11-15 17:27:50.965024 总收益率: 2,609.5%
2018-11-15 17:27:50.965024 年化收益: 20,202.55%
2018-11-15 17:27:50.965024 总盈亏: 2,609,496.33
2018-11-15 17:27:50.965024 最大回撤: -2,628,075.0
2018-11-15 17:27:50.965024 百分比最大回撤: -123.29%
2018-11-15 17:27:50.965024 总手续费: 316,833.66
2018-11-15 17:27:50.965024 总滑点: 0.0
2018-11-15 17:27:50.966023 总成交金额: 633,667,330.0
2018-11-15 17:27:50.966023 总成交笔数: 30
2018-11-15 17:27:50.966023 日均盈亏: 84,177.3
2018-11-15 17:27:50.966023 日均手续费: 10,220.44
2018-11-15 17:27:50.966023 日均滑点: 0.0
2018-11-15 17:27:50.966023 日均成交金额: 20,440,881.61
2018-11-15 17:27:50.966023 日均成交笔数: 0.97
2018-11-15 17:27:50.966023 日均收益率: 3.73%
2018-11-15 17:27:50.966023 收益标准差: 134.65%
2018-11-15 17:27:50.966023 Sharpe Ratio: 0.43
2018-11-15 17:27:51.800197 策略回测绩效图已保存

2018-11-15 17:27:52.577746 计算回测结果
2018-11-15 17:27:52.586740 交割单已生成
2018-11-15 17:27:52.586740 ------------------------------
2018-11-15 17:27:52.586740 第一笔交易: 2018-10-04 22:30:00
2018-11-15 17:27:52.586740 最后一笔交易: 2018-10-31 15:58:00
2018-11-15 17:27:52.586740 总交易次数: 26
2018-11-15 17:27:52.586740 总盈亏: 2,592,077.89
2018-11-15 17:27:52.586740 最大回撤: -807,531.68
2018-11-15 17:27:52.586740 平均每笔盈利: 99,695.3
2018-11-15 17:27:52.586740 平均每笔滑点: 0.0
2018-11-15 17:27:52.586740 平均每笔佣金: 12,855.85
2018-11-15 17:27:52.586740 胜率 42.31%
2018-11-15 17:27:52.586740 盈利交易平均值 314,165.61
2018-11-15 17:27:52.586740 亏损交易平均值 -57,582.92
2018-11-15 17:27:52.586740 盈亏比: 5.46
2018-11-15 17:27:53.246336 策略回测统计图已保存

2018-11-15 17:27:53.797042 计算按日统计结果
tradeReport