[关闭]
@Channelchan 2018-11-28T17:56:43.000000Z 字数 13691 阅读 61310

4_MA+RSI_Portfolio


回测引擎设置

  1. from vnpy.trader.app.ctaStrategy import BacktestingEngine
  2. import pandas as pd
  3. def runBacktesting(strategyClass, settingDict,
  4. startDate, endDate, slippage, rate):
  5. engine = BacktestingEngine()
  6. engine.setBacktestingMode(engine.BAR_MODE) # 设置引擎的回测模式为K线
  7. engine.setDatabase('VnTrader_1Min_Db') # 设置使用的历史数据库
  8. engine.setStartDate(startDate, initHours=200) # 设置回测用的数据起始日期
  9. engine.setEndDate(endDate) # 设置回测用的数据结束日期
  10. engine.setSlippage(slippage) # 设置滑点
  11. engine.setRate(rate) # 设置手续费万0.3
  12. engine.initStrategy(strategyClass, settingDict)
  13. engine.setCapital(100000) # 设置回测本金
  14. engine.runBacktesting()
  15. #显示逐日回测结果
  16. engine.showDailyResult()
  17. #显示逐笔回测结果
  18. engine.showBacktestingResult()
  19. # 计算回测结果
  20. df = engine.calculateDailyResult()
  21. return df

均线止损策略

  1. from vnpy.trader.vtConstant import *
  2. from vnpy.trader.app.ctaStrategy import CtaTemplate
  3. import talib as ta
  4. ########################################################################
  5. # 策略继承CtaTemplate
  6. class MultiFrameMaStrategy(CtaTemplate):
  7. className = 'MultiFrameMaStrategy'
  8. author = 'ChannelCMT'
  9. # 策略参数
  10. fastPeriod = 20; slowPeriod = 40
  11. signalMaPeriod = 20
  12. stopRatio = 0.04
  13. lot = 1
  14. # 策略变量
  15. maTrend = {} # 记录趋势状态,多头1,空头-1
  16. transactionPrice = {} # 记录成交价格
  17. # 参数列表,保存了参数的名称
  18. paramList = [
  19. 'fastPeriod',
  20. 'slowPeriod',
  21. 'signalMaPeriod',
  22. 'stopRatio'
  23. ]
  24. # 变量列表,保存了变量的名称
  25. varList = [
  26. 'maTrend',
  27. 'transactionPrice'
  28. ]
  29. # 同步列表,保存了需要保存到数据库的变量名称
  30. syncList = ['posDict', 'eveningDict']
  31. #----------------------------------------------------------------------
  32. def __init__(self, ctaEngine, setting):
  33. super().__init__(ctaEngine, setting)
  34. #----------------------------------------------------------------------
  35. def onInit(self):
  36. """初始化策略"""
  37. self.writeCtaLog(u'策略初始化')
  38. self.transactionPrice = {s:0 for s in self.symbolList} # 生成成交价格的字典
  39. self.maTrend = {s:0 for s in self.symbolList}
  40. self.putEvent()
  41. #----------------------------------------------------------------------
  42. def onStart(self):
  43. """启动策略"""
  44. self.writeCtaLog(u'策略启动')
  45. self.putEvent()
  46. #----------------------------------------------------------------------
  47. def onStop(self):
  48. """停止策略"""
  49. self.writeCtaLog(u'策略停止')
  50. self.putEvent()
  51. #----------------------------------------------------------------------
  52. def onTick(self, tick):
  53. """收到行情TICK推送"""
  54. pass
  55. #----------------------------------------------------------------------
  56. def onBar(self, bar):
  57. """收到Bar推送"""
  58. self.onBarStopLoss(bar)
  59. def onBarStopLoss(self, bar):
  60. symbol = bar.vtSymbol
  61. # 计算止损止盈价位
  62. longStop = self.transactionPrice[symbol]*(1-self.stopRatio)
  63. longProfit = self.transactionPrice[symbol]*(1+3*self.stopRatio)
  64. shortStop = self.transactionPrice[symbol]*(1+self.stopRatio)
  65. shortProfit = self.transactionPrice[symbol]*(1-3*self.stopRatio)
  66. # 洗价器
  67. if (self.posDict[symbol+'_LONG'] > 0):
  68. if (bar.close < longStop):
  69. print('LONG stopLoss')
  70. self.cancelAll()
  71. self.sell(symbol,bar.close*0.99, self.posDict[symbol+'_LONG'])
  72. elif (bar.close > longProfit):
  73. print('LONG takeProfit')
  74. self.cancelAll()
  75. self.sell(symbol,bar.close*0.99, self.posDict[symbol+'_LONG'])
  76. elif (self.posDict[symbol+'_SHORT'] > 0):
  77. if (bar.close > shortStop):
  78. print('SHORT stopLoss')
  79. self.cancelAll()
  80. self.cover(symbol,bar.close*1.01, self.posDict[symbol+'_SHORT'])
  81. elif (bar.close < shortProfit):
  82. print('SHORT takeProfit')
  83. self.cancelAll()
  84. self.cover(symbol,bar.close*1.01, self.posDict[symbol+'_SHORT'])
  85. #----------------------------------------------------------------------
  86. def on60MinBar(self, bar):
  87. """收到60MinBar推送"""
  88. symbol = bar.vtSymbol
  89. am60 = self.getArrayManager(symbol, "60m")
  90. if not am60.inited:
  91. return
  92. # 计算均线并判断趋势
  93. fastMa = ta.MA(am60.close, self.fastPeriod)
  94. slowMa = ta.MA(am60.close, self.slowPeriod)
  95. if fastMa[-1] > slowMa[-1]:
  96. self.maTrend[symbol] = 1
  97. else:
  98. self.maTrend[symbol] = -1
  99. #----------------------------------------------------------------------
  100. def on15MinBar(self, bar):
  101. """收到15MinBar推送"""
  102. symbol = bar.vtSymbol
  103. am15 = self.getArrayManager(symbol, "15m")
  104. if not am15.inited:
  105. return
  106. signalMa = ta.EMA(am15.close, self.signalMaPeriod)
  107. maUp = signalMa[-1]>signalMa[-3] # 均线上涨
  108. maDn = signalMa[-1]<signalMa[-3] # 均线下跌
  109. # 均线上涨, 趋势为多头, 多头没有持仓
  110. if maUp and (self.maTrend[symbol]==1) and (self.posDict[symbol+'_LONG']==0):
  111. if (self.posDict[symbol+'_SHORT']==0):
  112. self.buy(symbol, bar.close*1.01, self.lot) # 成交价*1.01发送高价位的限价单,以最优市价买入进场
  113. elif (self.posDict[symbol+'_SHORT'] > 0):
  114. self.cancelAll() # 撤销挂单
  115. self.cover(symbol, bar.close*1.01, self.posDict[symbol+'_SHORT'])
  116. self.buy(symbol, bar.close*1.01, self.lot)
  117. # 均线下跌, 趋势为空头, 空头没有持仓
  118. if maDn and (self.maTrend[symbol]==-1) and (self.posDict[symbol+'_SHORT']==0):
  119. if (self.posDict[symbol+'_LONG']==0):
  120. self.short(symbol, bar.close*0.99, self.lot) # 成交价*0.99发送低价位的限价单,以最优市价卖出进场
  121. elif (self.posDict[symbol+'_LONG'] > 0):
  122. self.cancelAll() # 撤销挂单
  123. self.sell(symbol, bar.close*0.99, self.posDict[symbol+'_LONG'])
  124. self.short(symbol, bar.close*0.99, self.lot)
  125. self.putEvent()
  126. #----------------------------------------------------------------------
  127. def onOrder(self, order):
  128. """收到委托变化推送(必须由用户继承实现)"""
  129. # 对于无需做细粒度委托控制的策略,可以忽略onOrder
  130. pass
  131. #----------------------------------------------------------------------
  132. def onTrade(self, trade):
  133. """收到成交推送(必须由用户继承实现)"""
  134. symbol = trade.vtSymbol
  135. if trade.offset == OFFSET_OPEN: # 判断成交订单类型
  136. self.transactionPrice[symbol] = trade.price # 记录成交价格
  137. print(trade.tradeTime, self.posDict)
  138. #----------------------------------------------------------------------
  139. def onStopOrder(self, so):
  140. """停止单推送"""
  141. pass
  1. MultiFrameMaDf = runBacktesting(MultiFrameMaStrategy, {'symbolList':['BTCUSDT:binance']} , '20180901 12:00', \
  2. '20181126 12:00', 0.002, 5/10000)
2018-11-27 17:37:04.057980  计算按日统计结果
2018-11-27 17:37:04.080956  ------------------------------
2018-11-27 17:37:04.081955  首个交易日:  2018-09-01 00:00:00
2018-11-27 17:37:04.081955  最后交易日:  2018-11-26 00:00:00
2018-11-27 17:37:04.081955  总交易日:   87
2018-11-27 17:37:04.081955  盈利交易日   45
2018-11-27 17:37:04.081955  亏损交易日:  41
2018-11-27 17:37:04.081955  起始资金:   100000
2018-11-27 17:37:04.081955  结束资金:   101,987.91
2018-11-27 17:37:04.082954  总收益率:   1.99%
2018-11-27 17:37:04.082954  年化收益:   5.48%
2018-11-27 17:37:04.082954  总盈亏:    1,987.91
2018-11-27 17:37:04.082954  最大回撤:   -408.37
2018-11-27 17:37:04.082954  百分比最大回撤: -0.41%
2018-11-27 17:37:04.082954  总手续费:   427.34
2018-11-27 17:37:04.082954  总滑点:    0.28
2018-11-27 17:37:04.082954  总成交金额:  854,686.82
2018-11-27 17:37:04.082954  总成交笔数:  139
2018-11-27 17:37:04.082954  日均盈亏:   22.85
2018-11-27 17:37:04.082954  日均手续费:  4.91
2018-11-27 17:37:04.082954  日均滑点:   0.0
2018-11-27 17:37:04.082954  日均成交金额: 9,823.99
2018-11-27 17:37:04.082954  日均成交笔数: 1.6
2018-11-27 17:37:04.082954  日均收益率:  0.02%
2018-11-27 17:37:04.082954  收益标准差:  0.14%
2018-11-27 17:37:04.082954  Sharpe Ratio:   2.3

output_5_1.png-54.7kB

2018-11-27 17:37:05.468537  计算回测结果
2018-11-27 17:37:05.474531  ------------------------------
2018-11-27 17:37:05.475529  第一笔交易:  2018-09-04 06:45:00
2018-11-27 17:37:05.475529  最后一笔交易: 2018-11-26 11:58:00
2018-11-27 17:37:05.475529  总交易次数:  70
2018-11-27 17:37:05.475529  总盈亏:    1,985.85
2018-11-27 17:37:05.475529  最大回撤:   -964.09
2018-11-27 17:37:05.475529  平均每笔盈利: 28.37
2018-11-27 17:37:05.475529  平均每笔滑点: 0.0
2018-11-27 17:37:05.475529  平均每笔佣金: 6.13
2018-11-27 17:37:05.475529  胜率      25.71%
2018-11-27 17:37:05.475529  盈利交易平均值 317.25
2018-11-27 17:37:05.475529  亏损交易平均值 -71.63
2018-11-27 17:37:05.475529  盈亏比:    4.43

output_5_3.png-43kB

2018-11-27 17:37:06.443538  计算按日统计结果

RSI顺势超买超卖策略

Buy: RSI<30

Sell: RSI>70

  1. from __future__ import division
  2. from vnpy.trader.vtConstant import *
  3. from vnpy.trader.app.ctaStrategy import CtaTemplate
  4. import talib as ta
  5. ########################################################################
  6. # 策略继承CtaTemplate
  7. class RsiTrendStrategy(CtaTemplate):
  8. className = 'RsiTrendStrategy'
  9. author = 'ChannelCMT'
  10. # 策略参数
  11. fastPeriod = 30; slowPeriod = 60
  12. signalMaPeriod = 20
  13. stopRatio = 0.03
  14. lot = 1
  15. # 策略变量
  16. maTrend = {} # 记录趋势状态,多头1,空头-1
  17. transactionPrice = {} # 记录成交价格
  18. # 参数列表,保存了参数的名称
  19. paramList = [
  20. 'fastPeriod', 'slowPeriod',
  21. 'signalMaPeriod',
  22. 'stopRatio'
  23. ]
  24. # 变量列表,保存了变量的名称
  25. varList = [
  26. 'maTrend',
  27. 'transactionPrice'
  28. ]
  29. # 同步列表,保存了需要保存到数据库的变量名称
  30. syncList = ['posDict', 'eveningDict']
  31. #----------------------------------------------------------------------
  32. def __init__(self, ctaEngine, setting):
  33. super().__init__(ctaEngine, setting)
  34. #----------------------------------------------------------------------
  35. def onInit(self):
  36. """初始化策略"""
  37. self.writeCtaLog(u'策略初始化')
  38. self.transactionPrice = {s:0 for s in self.symbolList} # 生成成交价格的字典
  39. self.maTrend = {s:0 for s in self.symbolList}
  40. self.putEvent()
  41. #----------------------------------------------------------------------
  42. def onStart(self):
  43. """启动策略"""
  44. self.writeCtaLog(u'策略启动')
  45. self.putEvent()
  46. #----------------------------------------------------------------------
  47. def onStop(self):
  48. """停止策略"""
  49. self.writeCtaLog(u'策略停止')
  50. self.putEvent()
  51. #----------------------------------------------------------------------
  52. def onTick(self, tick):
  53. """收到行情TICK推送"""
  54. pass
  55. #----------------------------------------------------------------------
  56. def onBar(self, bar):
  57. """收到Bar推送"""
  58. self.onBarStopLoss(bar)
  59. def onBarStopLoss(self, bar):
  60. symbol = bar.vtSymbol
  61. # 计算止损止盈价位
  62. longStop = self.transactionPrice[symbol]*(1-self.stopRatio)
  63. longProfit = self.transactionPrice[symbol]*(1+3*self.stopRatio)
  64. shortStop = self.transactionPrice[symbol]*(1+self.stopRatio)
  65. shortProfit = self.transactionPrice[symbol]*(1-3*self.stopRatio)
  66. # 洗价器
  67. if (self.posDict[symbol+'_LONG'] > 0):
  68. if (bar.close < longStop):
  69. self.cancelAll()
  70. self.sell(symbol,bar.close*0.99, self.posDict[symbol+'_LONG'])
  71. elif (bar.close > longProfit):
  72. self.cancelAll()
  73. self.sell(symbol,bar.close*0.99, self.posDict[symbol+'_LONG'])
  74. elif (self.posDict[symbol+'_SHORT'] > 0):
  75. if (bar.close > shortStop):
  76. self.cancelAll()
  77. self.cover(symbol,bar.close*1.01, self.posDict[symbol+'_SHORT'])
  78. elif (bar.close < shortProfit):
  79. self.cancelAll()
  80. self.cover(symbol,bar.close*1.01, self.posDict[symbol+'_SHORT'])
  81. #----------------------------------------------------------------------
  82. def on60MinBar(self, bar):
  83. """收到60MinBar推送"""
  84. symbol = bar.vtSymbol
  85. am60 = self.getArrayManager(symbol, "60m")
  86. if not am60.inited:
  87. return
  88. # 计算均线并判断趋势
  89. fastMa = ta.MA(am60.close, self.fastPeriod)
  90. slowMa = ta.MA(am60.close, self.slowPeriod)
  91. if fastMa[-1] > slowMa[-1]:
  92. self.maTrend[symbol] = 1
  93. else:
  94. self.maTrend[symbol] = -1
  95. #----------------------------------------------------------------------
  96. def on15MinBar(self, bar):
  97. """收到15MinBar推送"""
  98. symbol = bar.vtSymbol
  99. am15 = self.getArrayManager(symbol, "15m")
  100. if not am15.inited:
  101. return
  102. rsi = ta.RSI(am15.close, self.signalMaPeriod)
  103. rsiOverbought = (rsi[-1]>70) and (rsi[-2]<=70) # 超买
  104. rsiOversold = (rsi[-1]<30) and (rsi[-2]>=30) # 超卖
  105. # 均线上涨, 趋势为多头, 多头没有持仓
  106. if rsiOversold and (self.maTrend[symbol]==1) and (self.posDict[symbol+'_LONG']==0):
  107. if (self.posDict[symbol+'_SHORT']==0):
  108. self.buy(symbol, bar.close*1.01, self.lot) # 成交价*1.01发送高价位的限价单,以最优市价买入进场
  109. elif (self.posDict[symbol+'_SHORT'] > 0):
  110. self.cancelAll() # 撤销挂单
  111. self.cover(symbol, bar.close*1.01, self.posDict[symbol+'_SHORT'])
  112. self.buy(symbol, bar.close*1.01, self.lot)
  113. # 均线下跌, 趋势为空头, 空头没有持仓
  114. if rsiOverbought and (self.maTrend[symbol]==-1) and (self.posDict[symbol+'_SHORT']==0):
  115. if (self.posDict[symbol+'_LONG']==0):
  116. # self.cancelAll() # 撤销挂单
  117. self.short(symbol, bar.close*0.99, self.lot) # 成交价*0.99发送低价位的限价单,以最优市价卖出进场
  118. elif (self.posDict[symbol+'_LONG'] > 0):
  119. self.cancelAll() # 撤销挂单
  120. self.sell(symbol, bar.close*0.99, self.posDict[symbol+'_LONG'])
  121. self.short(symbol, bar.close*0.99, self.lot)
  122. self.putEvent()
  123. #----------------------------------------------------------------------
  124. def onOrder(self, order):
  125. """收到委托变化推送(必须由用户继承实现)"""
  126. # 对于无需做细粒度委托控制的策略,可以忽略onOrder
  127. pass
  128. #----------------------------------------------------------------------
  129. def onTrade(self, trade):
  130. """收到成交推送(必须由用户继承实现)"""
  131. symbol = trade.vtSymbol
  132. if trade.offset == OFFSET_OPEN: # 判断成交订单类型
  133. self.transactionPrice[symbol] = trade.price # 记录成交价格
  134. # print(trade.tradeTime, self.posDict)
  135. #----------------------------------------------------------------------
  136. def onStopOrder(self, so):
  137. """停止单推送"""
  138. pass
  1. rsiTrendDf = runBacktesting(RsiTrendStrategy, {'symbolList':['BTCUSDT:binance']} , '20180901 12:00', \
  2. '20181126 12:00', 0.002, 5/10000)
2018-11-27 17:37:24.700101  计算按日统计结果
2018-11-27 17:37:24.717082  ------------------------------
2018-11-27 17:37:24.717082  首个交易日:  2018-09-01 00:00:00
2018-11-27 17:37:24.717082  最后交易日:  2018-11-26 00:00:00
2018-11-27 17:37:24.717082  总交易日:   87
2018-11-27 17:37:24.717082  盈利交易日   33
2018-11-27 17:37:24.717082  亏损交易日:  24
2018-11-27 17:37:24.717082  起始资金:   100000
2018-11-27 17:37:24.717082  结束资金:   100,411.64
2018-11-27 17:37:24.717082  总收益率:   0.41%
2018-11-27 17:37:24.717082  年化收益:   1.14%
2018-11-27 17:37:24.717082  总盈亏:    411.64
2018-11-27 17:37:24.717082  最大回撤:   -602.46
2018-11-27 17:37:24.717082  百分比最大回撤: -0.6%
2018-11-27 17:37:24.717082  总手续费:   117.45
2018-11-27 17:37:24.717082  总滑点:    0.07
2018-11-27 17:37:24.717082  总成交金额:  234,902.46
2018-11-27 17:37:24.718082  总成交笔数:  37
2018-11-27 17:37:24.718082  日均盈亏:   4.73
2018-11-27 17:37:24.718082  日均手续费:  1.35
2018-11-27 17:37:24.718082  日均滑点:   0.0
2018-11-27 17:37:24.718082  日均成交金额: 2,700.03
2018-11-27 17:37:24.718082  日均成交笔数: 0.43
2018-11-27 17:37:24.718082  日均收益率:  0.0%
2018-11-27 17:37:24.718082  收益标准差:  0.09%
2018-11-27 17:37:24.718082  Sharpe Ratio:   0.8

output_8_1.png-49.4kB

2018-11-27 17:37:26.076690  计算回测结果
2018-11-27 17:37:26.078689  ------------------------------
2018-11-27 17:37:26.078689  第一笔交易:  2018-09-06 00:51:00
2018-11-27 17:37:26.078689  最后一笔交易: 2018-11-26 11:58:00
2018-11-27 17:37:26.078689  总交易次数:  19
2018-11-27 17:37:26.078689  总盈亏:    409.58
2018-11-27 17:37:26.078689  最大回撤:   -597.16
2018-11-27 17:37:26.078689  平均每笔盈利: 21.56
2018-11-27 17:37:26.078689  平均每笔滑点: 0.0
2018-11-27 17:37:26.078689  平均每笔佣金: 6.29
2018-11-27 17:37:26.078689  胜率      63.16%
2018-11-27 17:37:26.078689  盈利交易平均值 138.08
2018-11-27 17:37:26.078689  亏损交易平均值 -178.19
2018-11-27 17:37:26.078689  盈亏比:    0.77

output_8_3.png-41.9kB

2018-11-27 17:37:26.712041  计算按日统计结果

Strategy_Portfolio

  1. MultiFrameMaDf.tail()
  1. rsiTrendDf.tail()
  1. PortfolioDf = MultiFrameMaDf+rsiTrendDf
  1. PortfolioDf = PortfolioDf.dropna()
  2. # 创建回测引擎,并设置组合回测初始资金后,显示结果
  3. engine = BacktestingEngine()
  4. engine.setCapital(1000000)
  5. dfp, result = engine.calculateDailyStatistics(PortfolioDf)
  1. result
{'annualizedReturn': 0.6619457544827818,
 'dailyCommission': 6.262007356321838,
 'dailyNetPnl': 27.581073103448254,
 'dailyReturn': 0.0026295448011353366,
 'dailySlippage': 0.004045977011494256,
 'dailyTradeCount': 2.0229885057471266,
 'dailyTurnover': 12524.014712643675,
 'endBalance': 1002399.55336,
 'endDate': Timestamp('2018-11-26 00:00:00'),
 'lossDays': 30,
 'maxDdPercent': -0.05138439214392886,
 'maxDrawdown': -514.0053199999966,
 'profitDays': 46,
 'returnStd': 0.015721744941956703,
 'sharpeRatio': 2.5911076055495266,
 'startDate': Timestamp('2018-09-01 00:00:00'),
 'totalCommission': 544.79464,
 'totalDays': 87,
 'totalNetPnl': 2399.553359999998,
 'totalReturn': 0.2399553360000084,
 'totalSlippage': 0.35200000000000026,
 'totalTradeCount': 176,
 'totalTurnover': 1089589.2799999998}
  1. import matplotlib.pyplot as plt
  2. plt.figure(figsize=(15, 7))
  3. plt.plot(PortfolioDf['netPnl'].cumsum())
  4. plt.show()

output_15_0.png-25.1kB

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注