@Channelchan
2018-11-28T09:56:17.000000Z
字数 6890
阅读 61351
止损需要写在onBar,以最快的速度成交
from vnpy.trader.vtConstant import *from vnpy.trader.app.ctaStrategy import CtaTemplateimport talib as ta######################################################################### 策略继承CtaTemplateclass MultiFrameMaStrategy(CtaTemplate):className = 'MultiFrameMaStrategy'author = 'ChannelCMT'# 策略参数fastPeriod = 20; slowPeriod = 40signalMaPeriod = 20stopRatio = 0.04lot = 1# 策略变量maTrend = {} # 记录趋势状态,多头1,空头-1transactionPrice = {} # 记录成交价格# 参数列表,保存了参数的名称paramList = ['fastPeriod','slowPeriod','signalMaPeriod','stopRatio']# 变量列表,保存了变量的名称varList = ['maTrend','transactionPrice']# 同步列表,保存了需要保存到数据库的变量名称syncList = ['posDict', 'eveningDict']#----------------------------------------------------------------------def __init__(self, ctaEngine, setting):super().__init__(ctaEngine, setting)#----------------------------------------------------------------------def onInit(self):"""初始化策略"""self.writeCtaLog(u'策略初始化')self.transactionPrice = {s:0 for s in self.symbolList} # 生成成交价格的字典self.maTrend = {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 onBar(self, bar):"""收到Bar推送"""self.onBarStopLoss(bar)def onBarStopLoss(self, bar):symbol = bar.vtSymbol# 计算止损止盈价位longStop = self.transactionPrice[symbol]*(1-self.stopRatio)longProfit = self.transactionPrice[symbol]*(1+3*self.stopRatio)shortStop = self.transactionPrice[symbol]*(1+self.stopRatio)shortProfit = self.transactionPrice[symbol]*(1-3*self.stopRatio)# 洗价器if (self.posDict[symbol+'_LONG'] > 0):if (bar.close < longStop):print('LONG stopLoss')self.cancelAll()self.sell(symbol,bar.close*0.99, self.posDict[symbol+'_LONG'])elif (bar.close > longProfit):print('LONG takeProfit')self.cancelAll()self.sell(symbol,bar.close*0.99, self.posDict[symbol+'_LONG'])elif (self.posDict[symbol+'_SHORT'] > 0):if (bar.close > shortStop):print('SHORT stopLoss')self.cancelAll()self.cover(symbol,bar.close*1.01, self.posDict[symbol+'_SHORT'])elif (bar.close < shortProfit):print('SHORT takeProfit')self.cancelAll()self.cover(symbol,bar.close*1.01, self.posDict[symbol+'_SHORT'])#----------------------------------------------------------------------def on60MinBar(self, bar):"""收到60MinBar推送"""symbol = bar.vtSymbolam60 = self.getArrayManager(symbol, "60m")if not am60.inited:return# 计算均线并判断趋势fastMa = ta.MA(am60.close, self.fastPeriod)slowMa = ta.MA(am60.close, self.slowPeriod)#定义事件信号if fastMa[-1] > slowMa[-1]:self.maTrend[symbol] = 1else:self.maTrend[symbol] = -1#----------------------------------------------------------------------def on15MinBar(self, bar):"""收到15MinBar推送"""symbol = bar.vtSymbolam15 = self.getArrayManager(symbol, "15m")if not am15.inited:returnsignalMa = ta.EMA(am15.close, self.signalMaPeriod)maUp = signalMa[-1]>signalMa[-3] # 均线上涨maDn = signalMa[-1]<signalMa[-3] # 均线下跌# 均线上涨, 趋势为多头, 多头没有持仓if maUp and (self.maTrend[symbol]==1) 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)# 均线下跌, 趋势为空头, 空头没有持仓if maDn and (self.maTrend[symbol]==-1) 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):"""收到委托变化推送(必须由用户继承实现)"""# 对于无需做细粒度委托控制的策略,可以忽略onOrderpass#----------------------------------------------------------------------def onTrade(self, trade):"""收到成交推送(必须由用户继承实现)"""symbol = trade.vtSymbolif trade.offset == OFFSET_OPEN: # 判断成交订单类型self.transactionPrice[symbol] = trade.price # 记录成交价格print(trade.tradeTime, self.posDict)#----------------------------------------------------------------------def onStopOrder(self, so):"""停止单推送"""pass
from vnpy.trader.app.ctaStrategy import BacktestingEngineimport pandas as pddef runBacktesting(strategyClass, settingDict,startDate, endDate, slippage, rate):engine = BacktestingEngine()engine.setBacktestingMode(engine.BAR_MODE) # 设置引擎的回测模式为K线engine.setDatabase('VnTrader_1Min_Db') # 设置使用的历史数据库engine.setStartDate(startDate, initHours=200) # 设置回测用的数据起始日期engine.setEndDate(endDate) # 设置回测用的数据结束日期engine.setSlippage(slippage) # 设置滑点engine.setRate(rate) # 设置手续费万0.3engine.initStrategy(strategyClass, settingDict)engine.setCapital(100000) # 设置回测本金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, tradeDf
parameterDict = {'symbolList':['BTCUSDT:binance']}runBacktesting(MultiFrameMaStrategy, parameterDict, '20180901 12:00', '20181121 12:00', 0.002, 5/10000)
2018-11-27 17:29:37.762428 计算按日统计结果
2018-11-27 17:29:37.780410 ------------------------------
2018-11-27 17:29:37.780410 首个交易日: 2018-09-01 00:00:00
2018-11-27 17:29:37.780410 最后交易日: 2018-11-21 00:00:00
2018-11-27 17:29:37.780410 总交易日: 82
2018-11-27 17:29:37.780410 盈利交易日 43
2018-11-27 17:29:37.780410 亏损交易日: 38
2018-11-27 17:29:37.780410 起始资金: 100000
2018-11-27 17:29:37.780410 结束资金: 102,226.39
2018-11-27 17:29:37.780410 总收益率: 2.23%
2018-11-27 17:29:37.780410 年化收益: 6.52%
2018-11-27 17:29:37.780410 总盈亏: 2,226.39
2018-11-27 17:29:37.780410 最大回撤: -408.37
2018-11-27 17:29:37.780410 百分比最大回撤: -0.41%
2018-11-27 17:29:37.780410 总手续费: 388.41
2018-11-27 17:29:37.780410 总滑点: 0.24
2018-11-27 17:29:37.780410 总成交金额: 776,821.7
2018-11-27 17:29:37.780410 总成交笔数: 121
2018-11-27 17:29:37.780410 日均盈亏: 27.15
2018-11-27 17:29:37.780410 日均手续费: 4.74
2018-11-27 17:29:37.780410 日均滑点: 0.0
2018-11-27 17:29:37.780410 日均成交金额: 9,473.44
2018-11-27 17:29:37.780410 日均成交笔数: 1.48
2018-11-27 17:29:37.780410 日均收益率: 0.03%
2018-11-27 17:29:37.780410 收益标准差: 0.14%
2018-11-27 17:29:37.780410 Sharpe Ratio: 2.84

2018-11-27 17:29:39.153005 计算回测结果
2018-11-27 17:29:39.157999 ------------------------------
2018-11-27 17:29:39.157999 第一笔交易: 2018-09-04 06:45:00
2018-11-27 17:29:39.157999 最后一笔交易: 2018-11-21 11:58:00
2018-11-27 17:29:39.157999 总交易次数: 61
2018-11-27 17:29:39.157999 总盈亏: 2,224.06
2018-11-27 17:29:39.157999 最大回撤: -964.09
2018-11-27 17:29:39.157999 平均每笔盈利: 36.46
2018-11-27 17:29:39.157999 平均每笔滑点: 0.0
2018-11-27 17:29:39.157999 平均每笔佣金: 6.41
2018-11-27 17:29:39.157999 胜率 26.23%
2018-11-27 17:29:39.157999 盈利交易平均值 319.33
2018-11-27 17:29:39.157999 亏损交易平均值 -64.11
2018-11-27 17:29:39.157999 盈亏比: 4.98
