vnpy/examples/VnTrader/ctaStrategy123/strategy/strategyKingKeltner.py

198 lines
7.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# encoding: UTF-8
"""
基于King Keltner通道的交易策略适合用在股指上
展示了OCO委托和5分钟K线聚合的方法。
注意事项:
1. 作者不对交易盈利做任何保证,策略代码仅供参考
2. 本策略需要用到talib没有安装的用户请先参考www.vnpy.org上的教程安装
3. 将IF0000_1min.csv用ctaHistoryData.py导入MongoDB后直接运行本文件即可回测策略
"""
from __future__ import division
from vnpy.trader.vtObject import VtBarData
from vnpy.trader.vtConstant import EMPTY_STRING
from vnpy.trader.app.ctaStrategy.ctaTemplate import (CtaTemplate,
BarManager,
ArrayManager)
########################################################################
class KkStrategy(CtaTemplate):
"""基于King Keltner通道的交易策略"""
className = 'KkStrategy'
author = u'用Python的交易员'
# 策略参数
kkLength = 11 # 计算通道中值的窗口数
kkDev = 1.6 # 计算通道宽度的偏差
trailingPrcnt = 0.8 # 移动止损
initDays = 10 # 初始化数据所用的天数
fixedSize = 1 # 每次交易的数量
# 策略变量
kkUp = 0 # KK通道上轨
kkDown = 0 # KK通道下轨
intraTradeHigh = 0 # 持仓期内的最高点
intraTradeLow = 0 # 持仓期内的最低点
buyOrderIDList = [] # OCO委托买入开仓的委托号
shortOrderIDList = [] # OCO委托卖出开仓的委托号
orderList = [] # 保存委托代码的列表
# 参数列表,保存了参数的名称
paramList = ['name',
'className',
'author',
'vtSymbol',
'kkLength',
'kkDev']
# 变量列表,保存了变量的名称
varList = ['inited',
'trading',
'pos',
'kkUp',
'kkDown']
#----------------------------------------------------------------------
def __init__(self, ctaEngine, setting):
"""Constructor"""
super(KkStrategy, self).__init__(ctaEngine, setting)
self.bm = BarManager(self.onBar, 5, self.onFiveBar) # 创建K线合成器对象
self.am = ArrayManager()
self.buyOrderIDList = []
self.shortOrderIDList = []
self.orderList = []
#----------------------------------------------------------------------
def onInit(self):
"""初始化策略(必须由用户继承实现)"""
self.writeCtaLog(u'%s策略初始化' %self.name)
# 载入历史数据,并采用回放计算的方式初始化策略数值
initData = self.loadBar(self.initDays)
for bar in initData:
self.onBar(bar)
self.putEvent()
#----------------------------------------------------------------------
def onStart(self):
"""启动策略(必须由用户继承实现)"""
self.writeCtaLog(u'%s策略启动' %self.name)
self.putEvent()
#----------------------------------------------------------------------
def onStop(self):
"""停止策略(必须由用户继承实现)"""
self.writeCtaLog(u'%s策略停止' %self.name)
self.putEvent()
#----------------------------------------------------------------------
def onTick(self, tick):
"""收到行情TICK推送必须由用户继承实现"""
self.bm.updateTick(tick)
#----------------------------------------------------------------------
def onBar(self, bar):
"""收到Bar推送必须由用户继承实现"""
self.bm.updateBar(bar)
#----------------------------------------------------------------------
def onFiveBar(self, bar):
"""收到5分钟K线"""
# 撤销之前发出的尚未成交的委托(包括限价单和停止单)
for orderID in self.orderList:
self.cancelOrder(orderID)
self.orderList = []
# 保存K线数据
am = self.am
am.updateBar(bar)
if not am.inited:
return
# 计算指标数值
self.kkUp, self.kkDown = am.keltner(self.kkLength, self.kkDev)
# 判断是否要进行交易
# 当前无仓位发送OCO开仓委托
if self.pos == 0:
self.intraTradeHigh = bar.high
self.intraTradeLow = bar.low
self.sendOcoOrder(self.kkUp, self.kkDown, self.fixedSize)
# 持有多头仓位
elif self.pos > 0:
self.intraTradeHigh = max(self.intraTradeHigh, bar.high)
self.intraTradeLow = bar.low
l = self.sell(self.intraTradeHigh*(1-self.trailingPrcnt/100),
abs(self.pos), True)
self.orderList.extend(l)
# 持有空头仓位
elif self.pos < 0:
self.intraTradeHigh = bar.high
self.intraTradeLow = min(self.intraTradeLow, bar.low)
l = self.cover(self.intraTradeLow*(1+self.trailingPrcnt/100),
abs(self.pos), True)
self.orderList.extend(l)
# 发出状态更新事件
self.putEvent()
#----------------------------------------------------------------------
def onOrder(self, order):
"""收到委托变化推送(必须由用户继承实现)"""
pass
#----------------------------------------------------------------------
def onTrade(self, trade):
if self.pos != 0:
# 多头开仓成交后,撤消空头委托
if self.pos > 0:
for shortOrderID in self.shortOrderIDList:
self.cancelOrder(shortOrderID)
# 反之同样
elif self.pos < 0:
for buyOrderID in self.buyOrderIDList:
self.cancelOrder(buyOrderID)
# 移除委托号
for orderID in (self.buyOrderIDList + self.shortOrderIDList):
if orderID in self.orderList:
self.orderList.remove(orderID)
# 发出状态更新事件
self.putEvent()
#----------------------------------------------------------------------
def sendOcoOrder(self, buyPrice, shortPrice, volume):
"""
发送OCO委托
OCO(One Cancel Other)委托:
1. 主要用于实现区间突破入场
2. 包含两个方向相反的停止单
3. 一个方向的停止单成交后会立即撤消另一个方向的
"""
# 发送双边的停止单委托,并记录委托号
self.buyOrderIDList = self.buy(buyPrice, volume, True)
self.shortOrderIDList = self.short(shortPrice, volume, True)
# 将委托号记录到列表中
self.orderList.extend(self.buyOrderIDList)
self.orderList.extend(self.shortOrderIDList)
#----------------------------------------------------------------------
def onStopOrder(self, so):
"""停止单推送"""
pass