[关闭]
@Channelchan 2018-11-28T17:50:16.000000Z 字数 11191 阅读 64205

止盈止损-TrailingStopLoss

1、 最高价吊灯(highPrice)
2、波幅吊灯(atrMultiple)
3、 价格百分比跟踪(stairPct)
4、 指标追踪(Indicator)

1. 最高价吊灯(highPrice)

适用于日内交易:
1、 设置追踪止损的百分比
2、 创建记录最高最低价的字典并把初始值设置成0与一个极大数值
3、 记录不断创新高或新低的价格
4、当现价超过最(高/低)价加减追踪止损的百分比的比例即出场

  1. # 设置参数
  2. trailingPct = 0.02 #百分之二
  3. # 设置变量
  4. self.intraTradeHighDict = {s: 0 for s in self.symbolList}
  5. self.intraTradeLowDict = {s: 999999 for s in self.symbolList}
  6. # 变量初始化
  7. if self.posDict[symbol + "_LONG"] == 0 and self.posDict[symbol + "_SHORT"] == 0:
  8. self.intraTradeHighDict[symbol] = 0
  9. self.intraTradeLowDict[symbol] = 999999
  10. # 持有多头仓位
  11. elif self.posDict[symbol + "_LONG"] > 0:
  12. self.intraTradeHighDict[symbol] = max(self.intraTradeHighDict[symbol], bar.high)
  13. longStop = self.intraTradeHighDict[symbol] * (1-self.trailingPct)
  14. if bar.low <= longStop:
  15. self.sell(symbol, bar.close * 0.985, self.posDict[symbol + "_LONG"])
  16. # 持有空头仓位
  17. elif self.posDict[symbol + "_SHORT"] > 0:
  18. self.intraTradeLowDict[symbol] = min(self.intraTradeLowDict[symbol], bar.low)
  19. shortStop = self.intraTradeLowDict[symbol] * (1 + self.trailingPct)
  20. if bar.high >= shortStop:
  21. self.cover(symbol, bar.close * 1.015, self.posDict[symbol + "_SHORT"])

2. 波幅吊灯(atrMultiple)

适用于日内交易:
1. 设置ATR的倍数,并计算ATR的值。
2. 创建记录最高最低价的字典并把初始值设置成0与一个极大数值
3. 记录不断创新高或新低的价格
4. 当现价超过最(高/低)价加减ATR的倍数即出场,记录止损价,只能提升浮盈。

  1. # 设置参数
  2. atrMultipler = 3 #3倍的ATR
  3. # 设置变量
  4. self.intraTradeHighDict = {s: 0 for s in self.symbolList}
  5. self.intraTradeLowDict = {s: 999999 for s in self.symbolList}
  6. # 计算ATR的值
  7. atr = ta.ATR(am.close, 10)
  8. # 变量初始化
  9. if self.posDict[symbol + "_LONG"] == 0 and self.posDict[symbol + "_SHORT"] == 0:
  10. self.intraTradeHighDict[symbol] = 0
  11. self.intraTradeLowDict[symbol] = 999999
  12. self.longStop[symbol] = 0
  13. self.shortStop[symbol] = 999999
  14. # 持有多头仓位
  15. elif self.posDict[symbol + "_LONG"] > 0:
  16. self.intraTradeHighDict[symbol] = max(self.intraTradeHighDict[symbol], bar.high)
  17. self.longStop[symbol] = max(self.longStop[symbol], self.intraTradeHighDict[symbol]-self.atrMultipler*self.atr)
  18. if bar.low <= self.longStop[symbol]:
  19. self.sell(symbol, bar.close * 0.985, self.posDict[symbol + "_LONG"])
  20. # 持有空头仓位
  21. elif self.posDict[symbol + "_SHORT"] > 0:
  22. self.intraTradeLowDict[symbol] = min(self.intraTradeLowDict[symbol], bar.low)
  23. self.shortStop[symbol] = min(self.shortStop[symbol], self.intraTradeLowDict[symbol]+self.atrMultipler*self.atr)
  24. if bar.high >= self.shortStop[symbol]:
  25. self.cover(symbol, bar.close * 1.015, self.posDict[symbol + "_SHORT"])

3. 价格百分比跟踪(stairPct)

适用于隔夜交易:
1. 设置追踪止损的百分比
2. 创建记录最高最低价的字典并把初始值设置成0与一个极大数值
3. 记录不断创新高或新低的价格
4. 当最(高/低)价加减追踪止损百分比超过一定比例,止损才会移动
5. 当现价超过止损即出场

  1. # 设置参数
  2. trailingPct = 0.02 #百分之二
  3. # 设置变量
  4. self.intraTradeHighDict = {s: 0 for s in self.symbolList}
  5. self.intraTradeLowDict = {s: 999999 for s in self.symbolList}
  6. # 变量初始化
  7. if self.posDict[symbol + "_LONG"] == 0 and self.posDict[symbol + "_SHORT"] == 0:
  8. self.intraTradeHighDict[symbol] = 0
  9. self.intraTradeLowDict[symbol] = 999999
  10. self.nChange = 0
  11. # 持有多头仓位
  12. elif self.posDict[symbol + "_LONG"] > 0:
  13. self.intraTradeHighDict[symbol] = max(self.intraTradeHighDict[symbol], bar.high)
  14. self.nChange = (self.intraTradeHighDict[symbol]/transactionPrice[symbol]-1)//self.trailingPct
  15. changePrice = transactionPrice[symbol]*self.nChange*self.trailingPct
  16. self.longStop[symbol] = max(self.longStop[symbol], transactionPrice[symbol]*(1-self.trailingPct)+changePrice)
  17. if bar.low <= self.longStop[symbol]:
  18. self.sell(symbol, bar.close * 0.985, self.posDict[symbol + "_LONG"])
  19. # 持有空头仓位
  20. elif self.posDict[symbol + "_SHORT"] > 0:
  21. self.intraTradeLowDict[symbol] = min(self.intraTradeLowDict[symbol], bar.low)
  22. self.nChange[symbol] = -1* (self.intraTradeLowDict[symbol]/self.transactionPrice[symbol]-1)//self.trailingPct
  23. changePrice = self.transactionPrice[symbol]*self.nChange[symbol]*self.trailingPct
  24. self.shortStop[symbol] = min(self.shortStop[symbol], self.transactionPrice[symbol]*(1+self.trailingPct)-changePrice)
  25. if bar.high >= self.shortStop[symbol]:
  26. self.cover(symbol, bar.close * 1.015, self.posDict[symbol + "_SHORT"])
  27. self.stopLossControl[symbol] = -1

4. 指标追踪止损(Indicator)

适合信号出场:
1. 设定指标参数
2. 多空出场信号

  1. # 设置参数
  2. kamaPeriod = 20
  3. # 计算指标
  4. kama = ta.KAMA(am.close, self.kamaPeriod)
  5. # 持有多头仓位
  6. if self.posDict[symbol + "_LONG"] > 0:
  7. if bar.close<=kama[-1]:
  8. self.sell(symbol, bar.close * 0.985, self.posDict[symbol + "_LONG"])
  9. # 持有空头仓位
  10. if self.posDict[symbol + "_SHORT"] > 0:
  11. if bar.close>=kama[-1]:
  12. self.cover(symbol, bar.close * 1.015, self.posDict[symbol + "_SHORT"])
  1. # 设置参数
  2. sarPeriod = 20
  3. # 计算指标
  4. sar = ta.SAR(am.close, self.kamaPeriod)
  5. # 持有多头仓位
  6. if self.posDict[symbol + "_LONG"] > 0:
  7. if bar.close<=sar[-1] and bar.close>=sar[-2]:
  8. self.sell(symbol, bar.close * 0.985, self.posDict[symbol + "_LONG"])
  9. # 持有空头仓位
  10. if self.posDict[symbol + "_SHORT"] > 0:
  11. if bar.close<=sar[-1] and bar.close>=sar[-2]:
  12. self.cover(symbol, bar.close * 1.015, self.posDict[symbol + "_SHORT"])

Example: stairPctCase

  1. 设置参数
  2. 添加stairPct模块到onBar
  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. trailingPct = 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.intraTradeHighDict = {s: 0 for s in self.symbolList}
  41. self.intraTradeLowDict = {s: 999999 for s in self.symbolList}
  42. self.putEvent()
  43. #----------------------------------------------------------------------
  44. def onStart(self):
  45. """启动策略"""
  46. self.writeCtaLog(u'策略启动')
  47. self.putEvent()
  48. #----------------------------------------------------------------------
  49. def onStop(self):
  50. """停止策略"""
  51. self.writeCtaLog(u'策略停止')
  52. self.putEvent()
  53. #----------------------------------------------------------------------
  54. def onTick(self, tick):
  55. """收到行情TICK推送"""
  56. pass
  57. #----------------------------------------------------------------------
  58. def onBar(self, bar):
  59. """收到Bar推送"""
  60. self.onBarStopLoss(bar)
  61. def onBarStopLoss(self, bar):
  62. symbol = bar.vtSymbol
  63. # 变量初始化
  64. if self.posDict[symbol + "_LONG"] == 0 and self.posDict[symbol + "_SHORT"] == 0:
  65. self.intraTradeHighDict[symbol] = 0
  66. self.intraTradeLowDict[symbol] = 999999
  67. # 持有多头仓位
  68. elif self.posDict[symbol + "_LONG"] > 0:
  69. self.intraTradeHighDict[symbol] = max(self.intraTradeHighDict[symbol], bar.high)
  70. longStop = self.intraTradeHighDict[symbol] * (1-self.trailingPct)
  71. if bar.low <= longStop:
  72. # print('longStop')
  73. self.cancelAll()
  74. self.sell(symbol, bar.close * 0.99, self.posDict[symbol + "_LONG"])
  75. # 持有空头仓位
  76. elif self.posDict[symbol + "_SHORT"] > 0:
  77. self.intraTradeLowDict[symbol] = min(self.intraTradeLowDict[symbol], bar.low)
  78. shortStop = self.intraTradeLowDict[symbol] * (1 + self.trailingPct)
  79. if bar.high >= shortStop:
  80. # print('shortStop')
  81. self.cancelAll()
  82. self.cover(symbol, bar.close * 1.01, self.posDict[symbol + "_SHORT"])
  83. #----------------------------------------------------------------------
  84. def on60MinBar(self, bar):
  85. """收到60MinBar推送"""
  86. symbol = bar.vtSymbol
  87. am60 = self.getArrayManager(symbol, "60m")
  88. if not am60.inited:
  89. return
  90. # 计算均线并判断趋势
  91. fastMa = ta.MA(am60.close, self.fastPeriod)
  92. slowMa = ta.MA(am60.close, self.slowPeriod)
  93. if fastMa[-1] > slowMa[-1]:
  94. self.maTrend[symbol] = 1
  95. else:
  96. self.maTrend[symbol] = -1
  97. #----------------------------------------------------------------------
  98. def on15MinBar(self, bar):
  99. """收到15MinBar推送"""
  100. symbol = bar.vtSymbol
  101. am15 = self.getArrayManager(symbol, "15m")
  102. if not am15.inited:
  103. return
  104. signalMa = ta.EMA(am15.close, self.signalMaPeriod)
  105. maUp = signalMa[-1]>signalMa[-3] # 均线上涨
  106. maDn = signalMa[-1]<signalMa[-3] # 均线下跌
  107. # 均线上涨, 趋势为多头, 多头没有持仓
  108. if maUp and (self.maTrend[symbol]==1) and (self.posDict[symbol+'_LONG']==0):
  109. if (self.posDict[symbol+'_SHORT']==0):
  110. self.buy(symbol, bar.close*1.01, self.lot) # 成交价*1.01发送高价位的限价单,以最优市价买入进场
  111. elif (self.posDict[symbol+'_SHORT'] > 0):
  112. self.cancelAll() # 撤销挂单
  113. self.cover(symbol, bar.close*1.01, self.posDict[symbol+'_SHORT'])
  114. self.buy(symbol, bar.close*1.01, self.lot)
  115. # 均线下跌, 趋势为空头, 空头没有持仓
  116. if maDn and (self.maTrend[symbol]==-1) and (self.posDict[symbol+'_SHORT']==0):
  117. if (self.posDict[symbol+'_LONG']==0):
  118. self.short(symbol, bar.close*0.99, self.lot) # 成交价*0.99发送低价位的限价单,以最优市价卖出进场
  119. elif (self.posDict[symbol+'_LONG'] > 0):
  120. self.cancelAll() # 撤销挂单
  121. self.sell(symbol, bar.close*0.99, self.posDict[symbol+'_LONG'])
  122. self.short(symbol, bar.close*0.99, self.lot)
  123. self.putEvent()
  124. #----------------------------------------------------------------------
  125. def onOrder(self, order):
  126. """收到委托变化推送(必须由用户继承实现)"""
  127. # 对于无需做细粒度委托控制的策略,可以忽略onOrder
  128. pass
  129. #----------------------------------------------------------------------
  130. def onTrade(self, trade):
  131. """收到成交推送(必须由用户继承实现)"""
  132. symbol = trade.vtSymbol
  133. if trade.offset == OFFSET_OPEN: # 判断成交订单类型
  134. self.transactionPrice[symbol] = trade.price # 记录成交价格
  135. # print(trade.tradeTime, self.posDict)
  136. #----------------------------------------------------------------------
  137. def onStopOrder(self, so):
  138. """停止单推送"""
  139. pass# 策略变量
  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. perfromance = engine.calculateDailyResult()
  21. perfromanceDf , result = engine.calculateDailyStatistics(perfromance)
  22. tradeReport = pd.DataFrame([obj.__dict__ for obj in engine.tradeDict.values()])
  23. tradeDf = tradeReport.set_index('dt')
  24. return perfromanceDf, tradeDf
  1. parameterDict = {'symbolList':['BTCUSDT:binance']}
  2. runBacktesting(MultiFrameMaStrategy, parameterDict, '20180901 12:00', '20181121 12:00', 0.002, 5/10000)
2018-11-27 19:01:27.942563  计算按日统计结果
2018-11-27 19:01:27.973531  ------------------------------
2018-11-27 19:01:27.973531  首个交易日:  2018-09-01 00:00:00
2018-11-27 19:01:27.973531  最后交易日:  2018-11-21 00:00:00
2018-11-27 19:01:27.973531  总交易日:   82
2018-11-27 19:01:27.973531  盈利交易日   43
2018-11-27 19:01:27.973531  亏损交易日:  38
2018-11-27 19:01:27.973531  起始资金:   100000
2018-11-27 19:01:27.973531  结束资金:   101,956.69
2018-11-27 19:01:27.973531  总收益率:   1.96%
2018-11-27 19:01:27.973531  年化收益:   5.73%
2018-11-27 19:01:27.973531  总盈亏:    1,956.69
2018-11-27 19:01:27.973531  最大回撤:   -462.06
2018-11-27 19:01:27.974531  百分比最大回撤: -0.46%
2018-11-27 19:01:27.974531  总手续费:   483.71
2018-11-27 19:01:27.974531  总滑点:    0.3
2018-11-27 19:01:27.974531  总成交金额:  967,425.45
2018-11-27 19:01:27.974531  总成交笔数:  152
2018-11-27 19:01:27.974531  日均盈亏:   23.86
2018-11-27 19:01:27.974531  日均手续费:  5.9
2018-11-27 19:01:27.974531  日均滑点:   0.0
2018-11-27 19:01:27.974531  日均成交金额: 11,797.87
2018-11-27 19:01:27.974531  日均成交笔数: 1.85
2018-11-27 19:01:27.974531  日均收益率:  0.02%
2018-11-27 19:01:27.974531  收益标准差:  0.13%
2018-11-27 19:01:27.974531  Sharpe Ratio:   2.61

output_13_1.png-55.1kB

2018-11-27 19:01:29.331143  计算回测结果
2018-11-27 19:01:29.338136  ------------------------------
2018-11-27 19:01:29.338136  第一笔交易:  2018-09-04 06:45:00
2018-11-27 19:01:29.338136  最后一笔交易: 2018-11-21 10:18:00
2018-11-27 19:01:29.338136  总交易次数:  76
2018-11-27 19:01:29.338136  总盈亏:    1,956.69
2018-11-27 19:01:29.338136  最大回撤:   -1,028.45
2018-11-27 19:01:29.338136  平均每笔盈利: 25.75
2018-11-27 19:01:29.338136  平均每笔滑点: 0.0
2018-11-27 19:01:29.338136  平均每笔佣金: 6.36
2018-11-27 19:01:29.338136  胜率      27.63%
2018-11-27 19:01:29.338136  盈利交易平均值 237.95
2018-11-27 19:01:29.338136  亏损交易平均值 -55.28
2018-11-27 19:01:29.338136  盈亏比:    4.3

output_13_3.png-40.3kB

2018-11-27 19:01:30.086370  计算按日统计结果
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注