[关闭]
@Channelchan 2018-11-28T18:02:23.000000Z 字数 9391 阅读 64306

仓位管理-Martingale and Anti-Martingale

1、马丁格尔加仓法

2、反马丁格尔加仓法


1.马丁格尔加仓策略

Martingale是一种亏损加仓模式 适合胜率高的策略

见 onBar ‘马丁格尔加仓模块’

用参数 nPos 控制加仓次数,参数 Ratio 控制加仓的进场位置。


算法如下:

if 持多头仓位 and 当前加仓次数 nPos < 3:

if 亏损达到Ratio/100:

    加仓fixsize*(2**nPos)手数

    nPos = nPos+1

elif 持空头仓位 and 当前加仓次数 < 3:

if 亏损达到Ratio:

    加仓fixsize*(2**nPos)手数

    nPos = nPos+1

当执行平仓信号,将 nPos 重置为 0

if 持有多头仓位 and 死叉:

nPos = 0

elif 持有空头仓位 and 金叉:

nPos = 0
  1. ## 大的价格除以小的价格减1
  2. lastOrder=self.transactionPrice[symbol]
  3. ## 多头亏损大于一个百分比
  4. (self.transactionPrice[symbol] - bar.close)/bar.close
  5. = lastOrder/bar.close-1
  6. ## 多头盈利大于一个百分比
  7. (bar.close-self.transactionPrice[symbol])/self.transactionPrice[symbol]
  8. = bar.close/lastOrder-1
  9. ## 空头亏损大于一个百分比
  10. (bar.close - self.transactionPrice[symbol])/self.transactionPrice[symbol]
  11. = bar.close/lastOrder-1
  12. ## 空头盈利大于一个百分比
  13. (self.transactionPrice[symbol] - bar.close)/bar.close
  14. = lastOrder/bar.close-1
  1. # 设置参数
  2. nPos = 0
  3. fixsize = 2
  4. transactionPrice = {}
  5. Ratio = 2
  6. # 设置变量
  7. self.transactionPrice = {s: 0 for s in self.symbolList}
  8. #----------------------------------------------------------------------
  9. def onBar(self, bar):
  10. """收到Bar推送(必须由用户继承实现)"""
  11. symbol = bar.vtSymbol
  12. lastOrder=self.transactionPrice[symbol]
  13. # 马丁格尔加仓模块________________________________________________
  14. if (self.posDict[symbol+'_LONG']!=0 and self.nPos < 3): # 持有多头仓位并且加仓次数不超过3次
  15. if lastOrder/bar.close-1 >= self.Ratio/100: # 计算亏损比例,达到2%
  16. self.buy(symbol,bar.close*1.02,self.fixsize*(2**self.nPos)) # 加仓 2手、4手、8手
  17. self.nPos += 1 # 加仓次数减少 1 次
  18. elif (self.posDict[symbol + "_SHORT"] != 0 and self.nPos < 3): # 持有空头仓位并且加仓次数不超过3次
  19. if bar.close/lastOrder-1 >= self.Ratio/100: # 计算亏损比例,达到2%
  20. self.short(symbol,bar.close*0.98,self.fixsize*(2**self.nPos)) # 加仓 2手、4手、8手
  21. self.nPos += 1 # 加仓次数减少 1 次
  22. # 发出状态更新事件
  23. self.putEvent()

2.反马丁格尔加仓策略

Anti-Martingale是一种亏损加仓模式 适合胜率较低而盈亏比高的策略
见 onBar ‘反马丁格尔加仓模块’
用参数 n 控制加仓次数,参数 Ratio 控制加仓的进场位置。


算法如下:

if 持多头仓位 and 当前加仓次数 nPos < 3:

if 盈利达到Ratio/100:

    加仓fixsize*(2**n)手数

    nPos = nPos+1

elif 持空头仓位 and 当前加仓次数 < 3:

if 盈利达到Ratio:

    加仓fixsize*(2**nPos)手数

    nPos = nPos+1

当执行平仓信号,将 nPos 重置为 0

if 持有多头仓位 and 死叉:

nPos = 0

elif 持有空头仓位 and 金叉:

nPos = 0
  1. # 设置参数
  2. nPos = 0
  3. fixsize = 2
  4. transactionPrice = {}
  5. Ratio = 0.02
  6. # 设置变量
  7. self.transactionPrice = {s: 0 for s in self.symbolList}
  8. #----------------------------------------------------------------------
  9. def onBar(self, bar):
  10. """收到Bar推送(必须由用户继承实现)"""
  11. symbol = bar.vtSymbol
  12. lastOrder=self.transactionPrice[symbol]
  13. # 反马丁格尔加仓模块______________________________________
  14. if (self.posDict[symbol+'_LONG']!=0 and self.nPos < 3): # 持有多头仓位并且加仓次数不超过3次
  15. if bar.close/lastOrder-1>= self.Ratio: # 计算盈利比例,达到2%
  16. self.buy(symbol,bar.close*1.02,self.fixsize*(2**self.nPos)) # 加仓 2手、4手、8手
  17. self.nPos += 1 # 加仓次数减少 1 次
  18. elif (self.posDict[symbol + "_SHORT"] != 0 and self.nPos < 3): # 持有空头仓位并且加仓次数不超过3次
  19. if lastOrder/bar.close-1 >= self.Ratio: # 计算盈利比例,达到2%
  20. self.short(symbol,bar.close*0.98,self.fixsize*(2**self.nPos)) # 加仓 2手、4手、8手
  21. self.nPos += 1 # 加仓次数减少 1 次
  22. # 发出状态更新事件
  23. self.putEvent()

马丁格尔加仓法策略使用案例

  1. """
  2. 这里的Demo是一个最简单的双均线策略实现
  3. """
  4. from __future__ import division
  5. from vnpy.trader.vtConstant import *
  6. from vnpy.trader.app.ctaStrategy.ctaBarManager import CtaTemplate
  7. import numpy as np
  8. import talib as ta
  9. from datetime import timedelta
  10. ########################################################################
  11. # 策略继承CtaTemplate
  12. class DoubleMaStrategy(CtaTemplate):
  13. """双指数均线策略Demo"""
  14. className = 'DoubleMaStrategy'
  15. author = 'ChannelCMT'
  16. # 策略参数
  17. barPeriod = 200
  18. fastWindow = 60 # 快速均线参数
  19. slowWindow = 120 # 慢速均线参数
  20. # 参数列表,保存了参数的名称
  21. paramList = ['name',
  22. 'className',
  23. 'author',
  24. 'fastWindow',
  25. 'slowWindow']
  26. # 变量列表,保存了变量的名称
  27. varList = ['barPeriod']
  28. nPos = 0
  29. fixsize = 2
  30. transactionPrice = {}
  31. Ratio = 2
  32. # 同步列表,保存了需要保存到数据库的变量名称
  33. syncList = ['posDict', 'eveningDict']
  34. #----------------------------------------------------------------------
  35. def __init__(self, ctaEngine, setting):
  36. # 首先找到策略的父类(就是类CtaTemplate),然后把DoubleMaStrategy的对象转换为类CtaTemplate的对象
  37. super().__init__(ctaEngine, setting)
  38. #----------------------------------------------------------------------
  39. def onInit(self):
  40. """初始化策略(必须由用户继承实现)"""
  41. self.writeCtaLog(u'双EMA演示策略初始化')
  42. # 生成Bar数组
  43. self.setArrayManagerSize(self.barPeriod)
  44. self.transactionPrice = {s: 0 for s in self.symbolList}
  45. self.mail("chushihuaaaaaaaaaaaaaaaaaaaaaaaaa")
  46. self.putEvent()
  47. #----------------------------------------------------------------------
  48. def onStart(self):
  49. """启动策略(必须由用户继承实现)"""
  50. self.writeCtaLog(u'双EMA演示策略启动')
  51. self.putEvent()
  52. #----------------------------------------------------------------------
  53. def onStop(self):
  54. """停止策略(必须由用户继承实现)"""
  55. self.writeCtaLog(u'策略停止')
  56. self.putEvent()
  57. #----------------------------------------------------------------------
  58. def onTick(self, tick):
  59. """收到行情TICK推送(必须由用户继承实现)"""
  60. pass
  61. #----------------------------------------------------------------------
  62. def onBar(self, bar):
  63. """收到Bar推送(必须由用户继承实现)"""
  64. symbol = bar.vtSymbol
  65. lastOrder=self.transactionPrice[symbol]
  66. # 马丁格尔加仓模块________________________________________________
  67. if (self.posDict[symbol+'_LONG']!=0 and self.nPos < 3): # 持有多头仓位并且加仓次数不超过3次
  68. if lastOrder/bar.close-1 >= self.Ratio/100: # 计算亏损比例,达到2%
  69. self.buy(symbol,bar.close*1.02,self.fixsize*(2**self.nPos)) # 加仓 2手、4手、8手
  70. self.nPos += 1 # 加仓次数减少 1 次
  71. elif (self.posDict[symbol + "_SHORT"] != 0 and self.nPos < 3): # 持有空头仓位并且加仓次数不超过3次
  72. if bar.close/lastOrder-1 >= self.Ratio/100: # 计算亏损比例,达到2%
  73. self.short(symbol,bar.close*0.98,self.fixsize*(2**self.nPos)) # 加仓 2手、4手、8手
  74. self.nPos += 1 # 加仓次数减少 1 次
  75. # 发出状态更新事件
  76. self.putEvent()
  77. def on30MinBar(self, bar):
  78. """30分钟K线推送"""
  79. symbol = bar.vtSymbol
  80. am30 = self.getArrayManager(symbol, "30m")
  81. if not am30.inited:
  82. return
  83. # 计算策略需要的信号-------------------------------------------------
  84. fastMa = ta.EMA(am30.close, self.fastWindow)
  85. slowMa = ta.EMA(am30.close, self.slowWindow)
  86. crossOver = fastMa[-1]>slowMa[-1] and fastMa[-2]<=slowMa[-2] # 金叉上穿
  87. crossBelow = fastMa[-1]<slowMa[-1] and fastMa[-2]>=slowMa[-2] # 死叉下穿
  88. # 构建进出场逻辑-------------------------------------------------
  89. # 金叉和死叉的条件是互斥
  90. if crossOver:
  91. # 如果金叉时手头没有持仓,则直接做多
  92. if (self.posDict[symbol+'_LONG']==0) and (self.posDict[symbol+'_SHORT']==0):
  93. self.buy(symbol, bar.close*1.02, self.fixsize)
  94. # 如果有空头持仓,则先平空,再做多
  95. elif self.posDict[symbol+'_SHORT'] >0:
  96. self.cancelAll()
  97. self.cover(symbol,bar.close*1.02, self.posDict[symbol+'_SHORT'])
  98. self.nPos = 0
  99. self.buy(symbol,bar.close*1.02, self.fixsize)
  100. # 死叉和金叉相反
  101. elif crossBelow :
  102. if (self.posDict[symbol+'_LONG']==0) and (self.posDict[symbol+'_SHORT']==0):
  103. self.short(symbol,bar.close*0.98, self.fixsize)
  104. elif self.posDict[symbol+'_LONG'] >0:
  105. self.cancelAll()
  106. self.sell(symbol,bar.close*0.98, self.posDict[symbol+'_LONG'])
  107. self.nPos = 0
  108. self.short(symbol,bar.close*0.98, self.fixsize)
  109. # 发出状态更新事件
  110. self.putEvent()
  111. #----------------------------------------------------------------------
  112. def onOrder(self, order):
  113. """收到委托变化推送(必须由用户继承实现)"""
  114. # 对于无需做细粒度委托控制的策略,可以忽略onOrder
  115. # print(u'出现未知订单,需要策略师外部干预,ID:%s, symbol:%s,direction:%s,offset:%s'% (order.vtOrderID, order.vtSymbol, order.direction, order.offset))
  116. pass
  117. #----------------------------------------------------------------------
  118. def onTrade(self, trade):
  119. """收到成交推送(必须由用户继承实现)"""
  120. symbol = trade.vtSymbol
  121. self.transactionPrice[symbol] = trade.price
  122. pass
  123. #----------------------------------------------------------------------
  124. def onStopOrder(self, so):
  125. """停止单推送"""
  126. pass

马丁格尔加仓模型绩效测试

  1. from vnpy.trader.app.ctaStrategy.ctaBarManager import BacktestingEngine
  2. import pandas as pd
  3. def runBacktesting(strategyClass, settingDict,
  4. startDate, endDate, size, slippage, rate):
  5. engine = BacktestingEngine()
  6. engine.setBacktestingMode(engine.BAR_MODE)
  7. engine.setDatabase('VnTrader_1Min_Db')
  8. engine.setStartDate(startDate, initHours=200)
  9. engine.setEndDate(endDate)
  10. engine.setSize(size)
  11. engine.setSlippage(slippage)
  12. engine.setRate(rate)
  13. engine.initStrategy(strategyClass, settingDict)
  14. engine.setCapital(100000)
  15. engine.setLog(True, 'E://log//')
  16. engine.runBacktesting()
  17. #显示逐日回测结果
  18. engine.showDailyResult()
  19. #显示逐笔回测结果
  20. engine.showBacktestingResult()
  21. # 计算回测结果
  22. perfromance = engine.calculateDailyResult()
  23. perfromanceDf , result = engine.calculateDailyStatistics(perfromance)
  24. tradeReport = pd.DataFrame([obj.__dict__ for obj in engine.tradeDict.values()])
  25. tradeDf = tradeReport.set_index('dt')
  26. return perfromanceDf, tradeDf
  27. if __name__ == '__main__':
  28. # 同时传入信号与执行的数据
  29. performanceReport, tradeReport = \
  30. runBacktesting(DoubleMaStrategy, {'symbolList': ['BTCUSDT:binance']},
  31. '20181001 12:00', '20181031 16:00', 100, 0, 5/10000)
  32. # tradeReport.to_excel('BBandMa5MinStrategyReport.xlsx')
2018-11-12 22:20:07.424068  计算按日统计结果
2018-11-12 22:20:07.457049  ------------------------------
2018-11-12 22:20:07.458047  首个交易日:  2018-10-01 00:00:00
2018-11-12 22:20:07.458047  最后交易日:  2018-10-31 00:00:00
2018-11-12 22:20:07.458047  总交易日:   31
2018-11-12 22:20:07.458047  盈利交易日   18
2018-11-12 22:20:07.458047  亏损交易日:  13
2018-11-12 22:20:07.458047  起始资金:   100000
2018-11-12 22:20:07.458047  结束资金:   185,214.85
2018-11-12 22:20:07.458047  总收益率:   85.21%
2018-11-12 22:20:07.458047  年化收益:   659.73%
2018-11-12 22:20:07.458047  总盈亏:    85,214.85
2018-11-12 22:20:07.458047  最大回撤:   -70,082.0
2018-11-12 22:20:07.458047  百分比最大回撤: -34.7%
2018-11-12 22:20:07.458047  总手续费:   8,525.15
2018-11-12 22:20:07.458047  总滑点:    0
2018-11-12 22:20:07.459047  总成交金额:  17,050,304.0
2018-11-12 22:20:07.459047  总成交笔数:  13
2018-11-12 22:20:07.459047  日均盈亏:   2,748.87
2018-11-12 22:20:07.459047  日均手续费:  275.0
2018-11-12 22:20:07.459047  日均滑点:   0.0
2018-11-12 22:20:07.459047  日均成交金额: 550,009.81
2018-11-12 22:20:07.459047  日均成交笔数: 0.42
2018-11-12 22:20:07.459047  日均收益率:  2.1%
2018-11-12 22:20:07.459047  收益标准差:  16.66%
2018-11-12 22:20:07.459047  Sharpe Ratio:   1.95
2018-11-12 22:20:08.307526  策略回测绩效图已保存

output_10_1.png-42.5kB

2018-11-12 22:20:09.105040  计算回测结果
2018-11-12 22:20:09.114033  交割单已生成
2018-11-12 22:20:09.114033  ------------------------------
2018-11-12 22:20:09.114033  第一笔交易:  2018-10-04 22:30:00
2018-11-12 22:20:09.114033  最后一笔交易: 2018-10-31 15:58:00
2018-11-12 22:20:09.114033  总交易次数:  7
2018-11-12 22:20:09.114033  总盈亏:    84,581.45
2018-11-12 22:20:09.114033  最大回撤:   -36,412.91
2018-11-12 22:20:09.114033  平均每笔盈利: 12,083.06
2018-11-12 22:20:09.115032  平均每笔滑点: 0.0
2018-11-12 22:20:09.115032  平均每笔佣金: 1,308.36
2018-11-12 22:20:09.115032  胜率      42.86%
2018-11-12 22:20:09.115032  盈利交易平均值 40,331.45
2018-11-12 22:20:09.115032  亏损交易平均值 -9,103.23
2018-11-12 22:20:09.115032  盈亏比:    4.43
2018-11-12 22:20:09.781694  策略回测统计图已保存

output_10_3.png-30.6kB

2018-11-12 22:20:10.410309  计算按日统计结果

交易信息

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