5_MultiSignal
多信号策略逻辑:
- CCI指标(30分钟信号)
- RSI指标(30分钟信号)
- MA指标(60分钟)
- 固定比率吊灯止损(分钟)
from __future__ import division
from vnpy.trader.vtConstant import *
from vnpy.trader.app.ctaStrategy import CtaTemplate
import talib as ta
class 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 BacktestingEngine
import pandas as pd
def 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 计算按日统计结果