5_MultiSignal
多信号策略逻辑:
- CCI指标(30分钟信号)
- RSI指标(30分钟信号)
- MA指标(60分钟)
- 固定比率吊灯止损(分钟)
from __future__ import divisionfrom vnpy.trader.vtConstant import *from vnpy.trader.app.ctaStrategy import CtaTemplateimport talib as taclass MultiSignalStrategy(CtaTemplate): className = 'MultiSignalStrategy' author = 'ChannelCMT' amWindow = 20 # 策略参数 smaPeriod = 20; lmaPeriod = 55 cciPeriod = 10; cciThrehold = 10 rsiPeriod = 10; rsiEntry = 12 trailingPct = 0.04 lot = 1 # 策略变量 transactionPrice = {} # 记录成交价格 intraTradeHighDict = {}; intraTradeLowDict = {} RSI = {}; CCI = {}; MA = {} # 参数列表,保存了参数的名称 paramList = [ 'amWindow', 'rsiPeriod', 'rsiEntry', 'cciPeriod', 'cciThreshold', 'smaPeriod', 'lmaPeriod', 'trailingPct'] # 变量列表,保存了变量的名称 varList = ['transactionPrice' 'intraTradeHighDict', 'intraTradeLowDict' 'RSI', 'CCI', 'MA'] # 同步列表,保存了需要保存到数据库的变量名称 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.intraTradeHighDict = {s:0 for s in self.symbolList} self.intraTradeLowDict = {s:999999 for s in self.symbolList} self.RSI = {s:0 for s in self.symbolList} self.CCI = {s:0 for s in self.symbolList} self.MA = {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推送""" symbol = bar.vtSymbol # 洗价器(止盈止损) if self.posDict[symbol+'_LONG'] == 0 and self.posDict[symbol+'_SHORT'] == 0: self.intraTradeHighDict[symbol] = 0 self.intraTradeLowDict[symbol] = 999999 # 持有多头仓位 elif self.posDict[symbol+'_LONG'] >0: self.intraTradeHighDict[symbol] = max(self.intraTradeHighDict[symbol], bar.high) self.longStop = self.intraTradeHighDict[symbol]*(1-self.trailingPct) if bar.close<=self.longStop: self.cancelAll() self.sell(symbol, bar.close*0.9, self.posDict[symbol+'_LONG'])# # 持有空头仓位 elif self.posDict[symbol+'_SHORT'] >0: self.intraTradeLowDict[symbol] = min(self.intraTradeLowDict[symbol], bar.low) self.shortStop = self.intraTradeLowDict[symbol]*(1+self.trailingPct) if bar.close>=self.shortStop: self.cancelAll() self.cover(symbol, bar.close*1.1, self.posDict[symbol+'_SHORT']) self.putEvent() def on30MinBar(self, bar): symbol = bar.vtSymbol am30 = self.getArrayManager(symbol, "30m") if not am30.inited: return cci = ta.CCI(am30.high, am30.low, am30.close, self.cciPeriod) rsi = ta.RSI(am30.close, self.rsiPeriod) rsiLong = 50 + self.rsiEntry rsiShort = 50 - self.rsiEntry if cci[-1]>self.cciThrehold: self.CCI[symbol] = 1 elif cci[-1]<-self.cciThrehold: self.CCI[symbol] = -1 else: self.CCI[symbol] = 0 if rsi[-1]>=rsiLong: self.RSI[symbol] = 1 elif rsi[-1]<=rsiShort: self.RSI[symbol] = -1 else: self.RSI[symbol] = 0 # 发出状态更新事件 self.putEvent() def on60MinBar(self, bar): symbol = bar.vtSymbol am60 = self.getArrayManager(symbol, "60m") if not am60.inited: return SMA = ta.MA(am60.close, self.smaPeriod) LMA = ta.MA(am60.close, self.lmaPeriod) if SMA[-1]>LMA[-1]: self.MA[symbol] = 1 elif SMA[-1]<LMA[-1]: self.MA[symbol] = -1 else: self.MA[symbol] = 0 Signal = self.MA[symbol]+self.CCI[symbol]+self.RSI[symbol] if (Signal>=2) and (self.posDict[symbol+'_LONG']==0): if self.posDict[symbol+'_SHORT']==0: self.buy(symbol,bar.close*1.02, self.lot) elif self.posDict[symbol+'_SHORT'] > 0: self.cancelAll() self.cover(symbol,bar.close*1.1, self.posDict[symbol+'_SHORT']) self.buy(symbol,bar.close*1.1, self.lot) elif (Signal<=-2) and (self.posDict[symbol+'_SHORT']==0): if (self.posDict[symbol+'_LONG']==0): self.short(symbol,bar.close*0.9, self.lot) elif self.posDict[symbol+'_LONG']>0: self.cancelAll() self.sell(symbol,bar.close*0.98, self.posDict[symbol+'_LONG']) self.short(symbol,bar.close*0.98, 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 # 记录成交价格# 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.3 engine.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(MultiSignalStrategy, parameterDict, '20180901 12:00', '20181125 12:00', 0.002, 5/10000)
2018-11-27 17:43:32.023331 计算按日统计结果
2018-11-27 17:43:32.040316 ------------------------------
2018-11-27 17:43:32.040316 首个交易日: 2018-09-01 00:00:00
2018-11-27 17:43:32.040316 最后交易日: 2018-11-25 00:00:00
2018-11-27 17:43:32.040316 总交易日: 86
2018-11-27 17:43:32.040316 盈利交易日 52
2018-11-27 17:43:32.040316 亏损交易日: 33
2018-11-27 17:43:32.040316 起始资金: 100000
2018-11-27 17:43:32.040316 结束资金: 103,607.16
2018-11-27 17:43:32.040316 总收益率: 3.61%
2018-11-27 17:43:32.040316 年化收益: 10.07%
2018-11-27 17:43:32.040316 总盈亏: 3,607.16
2018-11-27 17:43:32.041316 最大回撤: -308.75
2018-11-27 17:43:32.041316 百分比最大回撤: -0.31%
2018-11-27 17:43:32.041316 总手续费: 356.74
2018-11-27 17:43:32.041316 总滑点: 0.23
2018-11-27 17:43:32.041316 总成交金额: 713,478.68
2018-11-27 17:43:32.041316 总成交笔数: 117
2018-11-27 17:43:32.041316 日均盈亏: 41.94
2018-11-27 17:43:32.041316 日均手续费: 4.15
2018-11-27 17:43:32.041316 日均滑点: 0.0
2018-11-27 17:43:32.041316 日均成交金额: 8,296.26
2018-11-27 17:43:32.041316 日均成交笔数: 1.36
2018-11-27 17:43:32.041316 日均收益率: 0.04%
2018-11-27 17:43:32.041316 收益标准差: 0.16%
2018-11-27 17:43:32.041316 Sharpe Ratio: 3.77

2018-11-27 17:43:33.486833 计算回测结果
2018-11-27 17:43:33.496824 ------------------------------
2018-11-27 17:43:33.496824 第一笔交易: 2018-09-05 17:59:00
2018-11-27 17:43:33.496824 最后一笔交易: 2018-11-25 11:58:00
2018-11-27 17:43:33.496824 总交易次数: 59
2018-11-27 17:43:33.496824 总盈亏: 3,605.27
2018-11-27 17:43:33.496824 最大回撤: -361.43
2018-11-27 17:43:33.496824 平均每笔盈利: 61.11
2018-11-27 17:43:33.497822 平均每笔滑点: 0.0
2018-11-27 17:43:33.497822 平均每笔佣金: 6.08
2018-11-27 17:43:33.497822 胜率 45.76%
2018-11-27 17:43:33.497822 盈利交易平均值 198.05
2018-11-27 17:43:33.497822 亏损交易平均值 -54.44
2018-11-27 17:43:33.497822 盈亏比: 3.64

2018-11-27 17:43:34.450847 计算按日统计结果