@Channelchan
2018-11-28T18:02:23.000000Z
字数 9391
阅读 64306
1、马丁格尔加仓法
2、反马丁格尔加仓法
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
if 持有多头仓位 and 死叉:
nPos = 0
elif 持有空头仓位 and 金叉:
nPos = 0
## 大的价格除以小的价格减1
lastOrder=self.transactionPrice[symbol]
## 多头亏损大于一个百分比
(self.transactionPrice[symbol] - bar.close)/bar.close
= lastOrder/bar.close-1
## 多头盈利大于一个百分比
(bar.close-self.transactionPrice[symbol])/self.transactionPrice[symbol]
= bar.close/lastOrder-1
## 空头亏损大于一个百分比
(bar.close - self.transactionPrice[symbol])/self.transactionPrice[symbol]
= bar.close/lastOrder-1
## 空头盈利大于一个百分比
(self.transactionPrice[symbol] - bar.close)/bar.close
= lastOrder/bar.close-1
# 设置参数
nPos = 0
fixsize = 2
transactionPrice = {}
Ratio = 2
# 设置变量
self.transactionPrice = {s: 0 for s in self.symbolList}
#----------------------------------------------------------------------
def onBar(self, bar):
"""收到Bar推送(必须由用户继承实现)"""
symbol = bar.vtSymbol
lastOrder=self.transactionPrice[symbol]
# 马丁格尔加仓模块________________________________________________
if (self.posDict[symbol+'_LONG']!=0 and self.nPos < 3): # 持有多头仓位并且加仓次数不超过3次
if lastOrder/bar.close-1 >= self.Ratio/100: # 计算亏损比例,达到2%
self.buy(symbol,bar.close*1.02,self.fixsize*(2**self.nPos)) # 加仓 2手、4手、8手
self.nPos += 1 # 加仓次数减少 1 次
elif (self.posDict[symbol + "_SHORT"] != 0 and self.nPos < 3): # 持有空头仓位并且加仓次数不超过3次
if bar.close/lastOrder-1 >= self.Ratio/100: # 计算亏损比例,达到2%
self.short(symbol,bar.close*0.98,self.fixsize*(2**self.nPos)) # 加仓 2手、4手、8手
self.nPos += 1 # 加仓次数减少 1 次
# 发出状态更新事件
self.putEvent()
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
if 持有多头仓位 and 死叉:
nPos = 0
elif 持有空头仓位 and 金叉:
nPos = 0
# 设置参数
nPos = 0
fixsize = 2
transactionPrice = {}
Ratio = 0.02
# 设置变量
self.transactionPrice = {s: 0 for s in self.symbolList}
#----------------------------------------------------------------------
def onBar(self, bar):
"""收到Bar推送(必须由用户继承实现)"""
symbol = bar.vtSymbol
lastOrder=self.transactionPrice[symbol]
# 反马丁格尔加仓模块______________________________________
if (self.posDict[symbol+'_LONG']!=0 and self.nPos < 3): # 持有多头仓位并且加仓次数不超过3次
if bar.close/lastOrder-1>= self.Ratio: # 计算盈利比例,达到2%
self.buy(symbol,bar.close*1.02,self.fixsize*(2**self.nPos)) # 加仓 2手、4手、8手
self.nPos += 1 # 加仓次数减少 1 次
elif (self.posDict[symbol + "_SHORT"] != 0 and self.nPos < 3): # 持有空头仓位并且加仓次数不超过3次
if lastOrder/bar.close-1 >= self.Ratio: # 计算盈利比例,达到2%
self.short(symbol,bar.close*0.98,self.fixsize*(2**self.nPos)) # 加仓 2手、4手、8手
self.nPos += 1 # 加仓次数减少 1 次
# 发出状态更新事件
self.putEvent()
"""
这里的Demo是一个最简单的双均线策略实现
"""
from __future__ import division
from vnpy.trader.vtConstant import *
from vnpy.trader.app.ctaStrategy.ctaBarManager import CtaTemplate
import numpy as np
import talib as ta
from datetime import timedelta
########################################################################
# 策略继承CtaTemplate
class DoubleMaStrategy(CtaTemplate):
"""双指数均线策略Demo"""
className = 'DoubleMaStrategy'
author = 'ChannelCMT'
# 策略参数
barPeriod = 200
fastWindow = 60 # 快速均线参数
slowWindow = 120 # 慢速均线参数
# 参数列表,保存了参数的名称
paramList = ['name',
'className',
'author',
'fastWindow',
'slowWindow']
# 变量列表,保存了变量的名称
varList = ['barPeriod']
nPos = 0
fixsize = 2
transactionPrice = {}
Ratio = 2
# 同步列表,保存了需要保存到数据库的变量名称
syncList = ['posDict', 'eveningDict']
#----------------------------------------------------------------------
def __init__(self, ctaEngine, setting):
# 首先找到策略的父类(就是类CtaTemplate),然后把DoubleMaStrategy的对象转换为类CtaTemplate的对象
super().__init__(ctaEngine, setting)
#----------------------------------------------------------------------
def onInit(self):
"""初始化策略(必须由用户继承实现)"""
self.writeCtaLog(u'双EMA演示策略初始化')
# 生成Bar数组
self.setArrayManagerSize(self.barPeriod)
self.transactionPrice = {s: 0 for s in self.symbolList}
self.mail("chushihuaaaaaaaaaaaaaaaaaaaaaaaaa")
self.putEvent()
#----------------------------------------------------------------------
def onStart(self):
"""启动策略(必须由用户继承实现)"""
self.writeCtaLog(u'双EMA演示策略启动')
self.putEvent()
#----------------------------------------------------------------------
def onStop(self):
"""停止策略(必须由用户继承实现)"""
self.writeCtaLog(u'策略停止')
self.putEvent()
#----------------------------------------------------------------------
def onTick(self, tick):
"""收到行情TICK推送(必须由用户继承实现)"""
pass
#----------------------------------------------------------------------
def onBar(self, bar):
"""收到Bar推送(必须由用户继承实现)"""
symbol = bar.vtSymbol
lastOrder=self.transactionPrice[symbol]
# 马丁格尔加仓模块________________________________________________
if (self.posDict[symbol+'_LONG']!=0 and self.nPos < 3): # 持有多头仓位并且加仓次数不超过3次
if lastOrder/bar.close-1 >= self.Ratio/100: # 计算亏损比例,达到2%
self.buy(symbol,bar.close*1.02,self.fixsize*(2**self.nPos)) # 加仓 2手、4手、8手
self.nPos += 1 # 加仓次数减少 1 次
elif (self.posDict[symbol + "_SHORT"] != 0 and self.nPos < 3): # 持有空头仓位并且加仓次数不超过3次
if bar.close/lastOrder-1 >= self.Ratio/100: # 计算亏损比例,达到2%
self.short(symbol,bar.close*0.98,self.fixsize*(2**self.nPos)) # 加仓 2手、4手、8手
self.nPos += 1 # 加仓次数减少 1 次
# 发出状态更新事件
self.putEvent()
def on30MinBar(self, bar):
"""30分钟K线推送"""
symbol = bar.vtSymbol
am30 = self.getArrayManager(symbol, "30m")
if not am30.inited:
return
# 计算策略需要的信号-------------------------------------------------
fastMa = ta.EMA(am30.close, self.fastWindow)
slowMa = ta.EMA(am30.close, self.slowWindow)
crossOver = fastMa[-1]>slowMa[-1] and fastMa[-2]<=slowMa[-2] # 金叉上穿
crossBelow = fastMa[-1]<slowMa[-1] and fastMa[-2]>=slowMa[-2] # 死叉下穿
# 构建进出场逻辑-------------------------------------------------
# 金叉和死叉的条件是互斥
if crossOver:
# 如果金叉时手头没有持仓,则直接做多
if (self.posDict[symbol+'_LONG']==0) and (self.posDict[symbol+'_SHORT']==0):
self.buy(symbol, bar.close*1.02, self.fixsize)
# 如果有空头持仓,则先平空,再做多
elif self.posDict[symbol+'_SHORT'] >0:
self.cancelAll()
self.cover(symbol,bar.close*1.02, self.posDict[symbol+'_SHORT'])
self.nPos = 0
self.buy(symbol,bar.close*1.02, self.fixsize)
# 死叉和金叉相反
elif crossBelow :
if (self.posDict[symbol+'_LONG']==0) and (self.posDict[symbol+'_SHORT']==0):
self.short(symbol,bar.close*0.98, self.fixsize)
elif self.posDict[symbol+'_LONG'] >0:
self.cancelAll()
self.sell(symbol,bar.close*0.98, self.posDict[symbol+'_LONG'])
self.nPos = 0
self.short(symbol,bar.close*0.98, self.fixsize)
# 发出状态更新事件
self.putEvent()
#----------------------------------------------------------------------
def onOrder(self, order):
"""收到委托变化推送(必须由用户继承实现)"""
# 对于无需做细粒度委托控制的策略,可以忽略onOrder
# print(u'出现未知订单,需要策略师外部干预,ID:%s, symbol:%s,direction:%s,offset:%s'% (order.vtOrderID, order.vtSymbol, order.direction, order.offset))
pass
#----------------------------------------------------------------------
def onTrade(self, trade):
"""收到成交推送(必须由用户继承实现)"""
symbol = trade.vtSymbol
self.transactionPrice[symbol] = trade.price
pass
#----------------------------------------------------------------------
def onStopOrder(self, so):
"""停止单推送"""
pass
from vnpy.trader.app.ctaStrategy.ctaBarManager import BacktestingEngine
import pandas as pd
def runBacktesting(strategyClass, settingDict,
startDate, endDate, size, slippage, rate):
engine = BacktestingEngine()
engine.setBacktestingMode(engine.BAR_MODE)
engine.setDatabase('VnTrader_1Min_Db')
engine.setStartDate(startDate, initHours=200)
engine.setEndDate(endDate)
engine.setSize(size)
engine.setSlippage(slippage)
engine.setRate(rate)
engine.initStrategy(strategyClass, settingDict)
engine.setCapital(100000)
engine.setLog(True, 'E://log//')
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
if __name__ == '__main__':
# 同时传入信号与执行的数据
performanceReport, tradeReport = \
runBacktesting(DoubleMaStrategy, {'symbolList': ['BTCUSDT:binance']},
'20181001 12:00', '20181031 16:00', 100, 0, 5/10000)
# 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 策略回测绩效图已保存
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 策略回测统计图已保存
2018-11-12 22:20:10.410309 计算按日统计结果
tradeReport