#encoding: UTF-8
#首先写系统内置模块
import sys
import os
from datetime import datetime, timedelta,date
from time import sleep
#导入vnpy的基础模块
#就是从对应的文件夹中导入相关要用的模块
#utilSinaClient没有对应的模块,怀疑是他们自己加的
from trader.vtConstant import EMPTY_STRING, EMPTY_INT, DIRECTION_LONG, DIRECTION_SHORT, OFFSET_OPEN,OFFSET_CLOSE,OFFSET_CLOSETODAY,OFFSET_CLOSEYESTERDAY, STATUS_CANCELLED
from trader.utilSinaClient import UtilSinaClient
#然后是CTA的模块
from trader.app.ctaStrategy.ctaTemplate import*
from trader.app.ctaStrategy.ctabase import*
from trader.app.ctaStrategy.ctaLineBar import*
from trader.app.ctaStrategy.ctaPolicy import*
from trader.app.ctaStrategy.ctaPosition import*
class Strategy_TripleMa(CtaTemplate):
"""
螺纹钢,5分钟级别,三均线策略
策略:10,20,120均线,120均线做多空过滤
MA120之上
MA10 上穿 MA20,金叉,做多;
MA10 下穿 MA20,死叉,平多;
MA120之下
MA10 下穿 MA20,死叉,做空;
MA10 上穿 MA20,金叉,平空;
"""
className='Strategy_TripleMa'
author=u'Arthur'
#策略在外部设置的参数
inputSS=1 #参数SS,下单,范围1-100,步长为1,默认为=1,
minDiff=1 #商品的最小交易单位
atrLength=20 #平均波动周期ATR Length
maxPos=4
gridHeight=10 #网格高度
#创建构建函数
def __init__(self,ctaEngine,setting=None):
"""Constructor"""
super(Strategy_TripleMa,self).__init__(ctaEngine,setting)
#增加监控参数项目
self.paramList.append('inputSS')
self.paramList.append('minDiff')
#增加监控变量参数项目
self.varList.append('pos') #仓位
self.varList.append('entrust') #是否正在委托
self.curDateTime=None #当前Tick时间
self.lastOrderTime=None #上一次委托
self.cancelSeconds=60 #撤单时间(秒)
#定义日内的交易窗口
self.openWindow=False #开始窗口
self.tradeWindow=False #交易窗口
self.closeWindow=False #收市平仓窗口
self.inited=False #是否完成了策略初始化
self.backtesting=False #是否回测
self.lineM5=None #5分钟K线
#创建一个策略规则
self.policy=CtaPolicy()
self.atr=10 #平均波动
self.policy.addPos=True #是否激活加仓策略
self.policy.addPosOnPips=1 #加仓策略1,固定点数(动态ATR)
self.highPriceInLong=EMPTY_FLOAT #成交后,最高价格
self.lowPriceInShort=EMPTY_FLOAT #成交后,最低价格
#增加仓位管理模块
self.position=CtaPosition(self)
self.position.maxPos=self.maxPos
#网格列表,首次开仓后,必须有两个值,一个开仓价,一个平仓价。
#当最高价超出最后一个值>n个网格是,自动添加item
self.gridPrices=[]
self.gridOpened=False
self.gridStopPrice=EMPTY_FLOAT
self.gridWinPrice=EMPTY_FLOAT
if setting:
#根据配置文件更新参数
self.setParam(setting)
#创建的M5 K线
lineM5Setting={}
lineM5Setting['name']=u'M5' #K线的名称
lineM5Setting['barTimeInterval']=60*5 #K线的Bar时长
lineM5Setting=['inputMa1Len']=10 #第一条均线
lineM5Setting=['inputMa2Len']=20 #第二条均线
lineM5Setting=['inputMa3Len']=120 #第三条均线
lineM5Setting=['inputAtrLen']=self.atrLength #ATR
lineM5Setting=['inputPreLen']=10 #前高/前低
lineM5Setting=['minDiff']=self.minDiff
lineM5Setting=['shortSymbol']=self.shortSymbol
self.lineM5=CtaLineBar(self,self.onBarM5,lineM5Setting)
try:
mode=setting['mode']
if mode !=EMPTY_STRING:
self.lineM5.setMode(setting['mode'])
except KeyError:
self.lineM5.settMode(self.lineM5.Tick_MODE)
self.onInit()
#初始化策略
def onInit(self,forec=False):
"""初始化"""
if force:
self.writeCtaLog(u'策略强制初始化')
self.inited=False
self.trading=False #控制是否启动交易
else:
self.writeCtaLog(u'策略初始化')
if self.inited:
self.writed:
self.writeCtaLog(u'已经初始化,不再执行')
return
self.pos=EMPTY_INT #初始化持仓
self.entrust=EMPTY_INT #初始化委托状态
if not self.backtesting:
#这里需要加载前置数据
if not self.__initDataFromSina():
self.inited=True #更新初始化标志
self.trading=True #启动交易
self.putEvent()
self.writeCtaLog(u'策略初始化完成')
def __initDataFromSina(self):
"""从Sina初始化5分钟数据"""
sina=UtilSinaClient(self)
ret=sina.getMinBars(symbol=self.symbol,minute=5,callback=self.lineM5.addBar)
if not ret:
self.writeCtaLog(u'获取M5数据失败')
return False
return True
def onStart(self):
"""启动策略"""
self.writeCtaLog(u'启动')
#停止模块
def onStop(self):
"""停止策略"""
self.uncompletedOrders.clear()
self.pos=EMPTY_INT
self.entrust=EMPTY_INT
self.writeCtaLog(u'停止')
self.putEvent()
#交易模块
def onTrade(self,trade):
"""交易更新"""
self.writeCtaLog(u'{0},OnTrade(),当前持仓:{1}',format(self.curDateTime,self.position.pos))
def clearGrid(self):
"""清空网格数据"""
if self.pos !=0:
return
self.gridPrices=[]
self.gridOpened=False
self.gridStopPrice=EMPTY_FLOAT
self.gridWinPrice=EMPTY_FLOAT
def buildGrid(self):
if self.pos==self.inoutSS:
#首次开仓,添加基准价格和上一级网络价格
self.gridPrices.append(self.policy.entryPrice)
self.gridPrices.append(self.policy.entryPrice+self.gridHeight)
elif self.pos==0-self.inputSS:
#首次开仓,添加基准价格和上一级网格价格
self.gridPrices.append(self.policy.entryPrice)
self.gridPrices.append(self.policy.entryPrice-self.gridHeight)
#报单
def onOrder(self,order):
"""报单更新"""
self.writeCtaLog(u'OnOrder()报单更新,orderID:{0},{1},totalVol:{2},tradedVol:{3},offset:{4},price:{5},direction:{6},status:{7}'
.format(order.orderID, order.vtSymbol, order.totalVolume,order.tradedVolume,
order.offset, order.price, order.direction, order.status))
#委托单主键,vnpy使用"gateway.orderid"的组合
orderkey=order.gatewayName+u'.'+order.orderID
if orderkey in self.uncompleteOrders:
if order.totalVolume==order.tradeVolume:
#开仓,平仓委托单全部成交
#平空仓完成(cover)
if self.uncompletedOrder[orderkey]['DIRECTION']==DIRECTION_LONG and order.offset !=OFFSET_OPEN:
self.writeCtaLog(u'平空仓完成,原仓位:{0}',format(self.pos))
self.position.closePos(direction=DIRECTION_LONG,vol=order.tradeVolume)
self.writeCtaLog(u'新仓位:{0}'.format(self.pos))
self.clearGrid()
#平多仓完成(sell)
if self.uncompletedOrders[orderkey]['DIRECTION']==DIRECTION_SHORT and order.offset !=OFFSET_OPEN:
self.writeCtaLog(u'平多仓完成,原仓位:{0}'.format(self.pos))
self.position.closePos(direction=DIRECTION_LONG,vol=order.tradedVolume)
self.writeCtaLog(u'新仓位:{0}'.format(self.pos))
self.clearGrid()
# 开多仓完成
if self.uncompletedOrders[orderkey]['DIRECTION'] == DIRECTION_LONG and order.offset == OFFSET_OPEN:
self.writeCtaLog(u'开多仓完成,原仓位:{0}'.format(self.pos))
self.position.openPos(direction=DIRECTION_LONG, vol=order.tradedVolume, price=order.price)
self.writeCtaLog(u'新仓位:{0}'.format(self.pos))
self.buildGrid()
# 开空仓完成
if self.uncompletedOrders[orderkey]['DIRECTION'] == DIRECTION_SHORT and order.offset == OFFSET_OPEN:
# 更新仓位
self.writeCtaLog(u'开空仓完成,原仓位:{0}'.format(self.pos))
self.position.openPos(direction=DIRECTION_SHORT, vol=order.tradedVolume, price=order.price)
self.writeCtaLog(u'新仓位:{0}'.format(self.pos))
self.buildGrid()
del self.uncompletedOrders[orderkey]
if len(self.uncompletedOrders) == 0:
self.entrust = 0
self.lastOrderTime = None
if self.position.pos == 0:
self.highPriceInLong = EMPTY_FLOAT
self.lowPriceInShort = EMPTY_FLOAT
self.policy.entryPrice = EMPTY_FLOAT
elif order.tradedVolume > 0 and not order.totalVolume == order.tradedVolume and order.offset != OFFSET_OPEN:
# 平仓委托单部分成交
pass
elif order.offset == OFFSET_OPEN and order.status == STATUS_CANCELLED:
# 开仓委托单被撤销
self.entrust = 0
pass
else:
self.writeCtaLog(u'OnOrder()委托单返回,total:{0},traded:{1}'
.format(order.totalVolume, order.tradedVolume,))
self.putEvent() # 更新监控事件
def onStopOrder(self, orderRef):
"""停止单更新"""
self.writeCtaLog(u'{0},停止单触发,orderRef:{1}'.format(self.curDateTime, orderRef))
pass
#数据模式
def onTick(self,tick):
"""
行情更新
:type tick: object
"""
self.curTick=tick
if (tick.datetime.hour>=3 and tick.datetime.hour<=8) or (tick.datetime.hour>=16 and tick.datetime.hour<-20):
self.writeCtaLog(u'休市/集合竞价排名是数据不处理')
return
#跟新策略执行的事件(用于回测时记录发生的时间)
self.curDateTime=tick.datetime
#2.计算交易时间和平仓时间
self.__timeWindow(self.curDateTime)
#推送Tick到lineM5
self.lineM5.onTick()tick
#首先检查是否是实盘运行还是数据预处理阶段
if not (self.inited and len(self.lineM5.lineMa3)>0):
return
#持有多仓/空仓是,更新最高价和最低价
if self.position.pos>0:
if tick.lastPrice>self.highPriceInLong:
self.highPriceInLong=tick.lastPrice
if self.position.pos<0:
if tick.lastPrice<self.lowPriceInShort:
self.lowPriceInShort=tick.lastPrice
def onBar(self,bar):
"""分钟K线数据更新"""
#更新策略执行时间
#回测数据传送的bar.datetime,为bar的开始时间,所以,到达策略时,当前时间为bar的结束时间
self.curDateTime=bar.datetime+timedelta(seconds=self.lineM5.barTimeInterval)
#2.计算交易时间和平仓时间
self.__timeWindow(bar.datetime)
#推送tick到15分钟K线
self.lineM5.addBar(bar)
#4.交易逻辑
#首先检查是否实盘运行还是数据预处理阶段
if not self.inited:
if len(self.lineM5.lineBar)>120+5:
self.inited=True
else:
return
def onBarM5(self,abr):
"""分钟K线数据更新,实盘时,由self.lineM5的回调 """
#调用lineM5的显示bar内容
self.writeCtaLog(self.lineM5.displayLastBar())
#未初始化完成
if not self.inited:
if len(self.lineM5.lineBar)>120+5:
self.inited=True
else:
return
if self.lineM5.mode==self.lineM5.TICK_MODE:
idx=2
else:
idx=1
#更新ATR
if self.lineM5.lineAtr1[-1]>2:
self.atr=max(self.lineM5.lineArt[-1],5)
#2倍的ATR作为跟随止损
self.policy.exitOnLasRtnPips=int((self.atr*2)/self.minDiff)+1
#更新最高价/最低价
if self.backtesting:
#持有多仓/空仓时,更新最高价和最低价
if self.position.pos>0:
if bar.high>self.highPriceInLong:
self.highPriceInLong=bar.high
#增加一个上网格
if self.highPriceInLong-self.gridPrices[-1]>self.gridHeight*1.5:
self.gridPrices.append(self.gridPrices[-1]+self.gridHeight)
if self.position.pos<0:
if bar.low<self.lowShort=bar.low
#增加一个下网格
if self.lowPriceInShort-self.gridPrices[-1]<(0-self.gridHeight*1.5):
self.gridPrices.append(self.gridPrices[-1]-self.gridHeight)
#执行撤单逻辑
self.__cancelLogic(dt=self.curDatetime)
if len(self.lineM5.lineM3)>5:
ma5_Ma120=ta.Ma(numpy.array(self.lineM5.lineMa3,dtype=float),5)[-1]
else:
ma5_Ma120=self.lineM5.lineMa3[-1]
ma5_Ma10=ta.MA(numpy.array(self.lineM5.lineMa1,dtype=float),5)[-1]
#如果未持仓,检查是否符合开仓逻辑
if self.position.pos==0:
#MA10 上穿MA20,MA10>MA120,bar.close>MA120,MA(MA120)<MA120
if self.lineM5.lineM5.lineMa1[-1]>self.lineM5.lineMa2[-1]\
and self.lineM5.lineMa1[-1]>self.lineM5.lineMa3[-1]\
and bar.close>self.LineM5.lineMa3[-1]\
and ma5_Ma120<self.lineM5.lineMa3[-1]\
and self.lineM5.lineMa1[-1]>ma5_Ma10:
self.writeCtaLog(u'{0},开仓多单{1}手,价格:{2}'.format(bar.datetime,self.inputSS,bar.close))
orderid=self.buy(price=bar.close,volume=self.inputSS,orderTime=self.curDatetime)
if orderid:
#更新下单时间(为了定时撤单)
self.lastOrderTime=self.curDateTime
#更新开仓价格
self.policy.entryPrice=bar.close
#设置前低止损价
self.policy.exitOnStopPrice=self.lineM5.prelow[-1]
return
# MA10 下穿MA20, MA10 < MA120, bar.close < MA120, MA(MA120) > MA120
if self.lineM5.lineMa1[-2] > self.lineM5.lineMa2[-2] \
and self.lineM5.lineMa1[-1] < self.lineM5.lineMa2[-1] \
and self.lineM5.lineMa1[-1] < self.lineM5.lineMa3[-1] \
and bar.close < self.lineM5.lineMa3[-1] \
and ma5_Ma120 > self.lineM5.lineMa3[-1] \
and self.lineM5.lineMa1[-1] < ma5_Ma10:
self.writeCtaLog(u'{0},开仓空单{1}手,价格:{2}'.format(bar.datetime, self.inputSS, bar.close))
orderid = self.short(price=bar.close, volume=self.inputSS, orderTime=self.curDateTime)
if orderid:
# 更新下单时间(为了定时撤单)
self.lastOrderTime = self.curDateTime
# 更新开仓价格
self.policy.entryPrice = bar.close
# 更新最低价
self.lowPriceInShort = bar.close
# 设置前高为止损价
self.policy.exitOnStopPrice = self.lineM5.preHigh[-1]
return
#持仓,价差是否满足平仓条件
else:
#MA10下穿MA20,多单离场
if self.lineM5.lineMa1[-1]<self.lineM5.lineMa2[-1]\
and self.position.pos>0 and self.entrust==0:
self.writeCtaLog(u'{0},平仓多单{1}手,价格:{2}'.format(bar.datetime,abs(self.position.pos),bar.close))
orderid=self.sell(price=bar.close,volume=abs(self.position.pos),orderTime=self.curDatetime)
if orderid:
#更新下单时间
self.lastOrderTime=self.curDateTime
return
#MA10上穿MA20,空离场
if self.lineM5.lineMa1[-1]>self.lineM5.lineMa2[-1]\
and self.position.pos<0 and self.entrust==0:
self.writeCtaLog(u'{0},平仓空单{1}手,价格:{2}'.format(bar.datetime,abs(self.position.pos),bar.close))
orderid=self.cover(price=bar.close,volume=abs(self.position.pos),orderTime=self.curDateTime)
if orderid:
#更新下单时间
self.lastOrderTime=self.curDateTime
return
#policy跟随止损
if self.policy.exitOnlastRtnPips>0:
if self.position.pos>0 and self.entrust==0\
and bar.close<(self.highPriceInLong-self.policy.exitOnLastRtnPips*self.minDiff):
self.writeCtaLog(u'{0},跟随止损,平仓多单{1}手,价格:{2}'.format(bar.datetime,abs(self.position.pos),bar.close))
orderid=self.sell(price=bar.close,volume=abs(self.position.pos),orderTime=self.curDateTime)
if orderid:
#更新下单时间
self.lastOrderTime=self.curDateTime
return
if self.position.pos<0 and self.entrust==0\
and bar.close>(self.lowPriceInShort+self.policy.exitOnLastRtnPips*self.minDiff):
self.writeCtaLog(u'{0},跟随止损,平仓空单{1}手,价格:{2}'.format(bar.datetime,abs(self.position.pos),bar.close))
orderid=self.cover(price=bar.close,volume=abs(self.position.pos),orderTime=self.curDateTime)
if orderid:
self.lastOrderTime=self.curDatetime
return
#固定止损
if self.policy.exitOnStopPrice>0:
if self.position.pos>0 and self.entrust==0\
and bar.close< self.policy.exitOnStopPrice:
self.writeCtaLog(0'{0},固定止损,平仓多单{1}手,价格:{2}'.format(bar.datetime,abs(self.position.pos),bar.close))
orderid=self.sell(price=bar.close,volume=abs(self.position.pos),orderTime=self.curDateTime)
if orderid:
#更新下单时间
self.lastOrderTime=self.curDateTime
return
if self.position.pos<0 and self.entrust==0\
and bar.close>self.policy.exitOnStopPrice:
self.writeCtaLog(u'{0},固定止损,平仓空单{1}手,价格:{2}',format(bar.datetime,abs(self.position.pos),bar.close))
orderid=self.cover(price=bar.close,volume=abs(self.position.pos),orderTime=self.curDateTime)
if orderid:
#更新下单时间
self.lastOrderTime=self.curDateTime
return
if len(self.gridPrices)>1:
#满足网格多单加仓:在开仓价以上,均线上升,下穿网格线
if self.position.pos==self.inputSS and self.entrust==0\
and bar.close<self.gridPrices[-1] and bar.close>self.policy.entryPrice \
and self.highPriceInLong>self.gridPrices[-1] \
and ma5_Ma120<self.lineM5.lineMa3[-1]:
self.writeCtaLog(u'{0},加仓网格多单{1}手,价格:{2}'.format(bar.datetime,self.inputSS,bar.close))
orderid=self.buy(price=bar.close,volume=self.inputSS,orderTime=self.curDateTime)
if orderid:
#更新下单时间
self.lastOrderTime=self.curDateTime
#更新网格的止盈止损价格
self.gridStopPrice=self.gridPrices[-1]-self.gridHeight
self.gridWinPrice=self.gridPrices[-1]+self.gridHeight
return
# 满足网格空单加仓,在开仓价以上;均线下升;上穿网格线
if self.position.pos ==(0-self.inputSS) and self.entrust == 0 \
and bar.close > self.gridPrices[-1] and bar.close < self.policy.entryPrice \
and self.lowPriceInShort < self.gridPrices[-1] \
and ma5_Ma120 > self.lineM5.lineMa3[-1]:
self.writeCtaLog(u'{0},加仓网格空单{1}手,价格:{2}'.format(bar.datetime, self.inputSS, bar.close))
orderid = self.short(price=bar.close, volume=self.inputSS, orderTime=self.curDateTime)
if orderid:
# 更新下单时间(为了定时撤单)
self.lastOrderTime = self.curDateTime
# 更新网格的止盈止损价格
self.gridStopPrice = self.gridPrices[-1] + self.gridHeight
self.gridWinPrice = self.gridPrices[-1] - self.gridHeight
return
# 固定止盈多单
if self.position.pos > 1 and bar.close >= self.gridWinPrice and self.entrust == 0:
self.writeCtaLog(u'{0},固定止盈网格单,平仓多单{1}手,价格:{2}'.format(bar.datetime, self.inputSS, bar.close))
orderid = self.sell(price=bar.close, volume=self.inputSS, orderTime=self.curDateTime)
if orderid:
# 更新下单时间(为了定时撤单)
self.lastOrderTime = self.curDateTime
return
# 固定止盈空单
if self.position.pos < -1 and bar.close <= self.gridWinPrice and self.entrust == 0:
self.writeCtaLog(u'{0},固定止盈网格单,平仓空单{1}手,价格:{2}'.format(bar.datetime, self.inputSS, bar.close))
orderid = self.cover(price=bar.close, volume=self.inputSS, orderTime=self.curDateTime)
if orderid:
# 更新下单时间(为了定时撤单)
self.lastOrderTime = self.curDateTime
return
# 固定止损多单
if self.position.pos > 1 and bar.close < self.gridStopPrice and self.entrust == 0:
self.writeCtaLog(u'{0},固定止损网格单,平仓多单{1}手,价格:{2}'.format(bar.datetime, self.inputSS, bar.close))
orderid = self.sell(price=bar.close, volume=self.inputSS, orderTime=self.curDateTime)
if orderid:
# 更新下单时间(为了定时撤单)
self.lastOrderTime = self.curDateTime
return
# 固定止损空单
if self.position.pos < -1 and bar.close > self.gridStopPrice and self.entrust == 0:
self.writeCtaLog(u'{0},固定止损网格单,平仓空单{1}手,价格:{2}'.format(bar.datetime, self.inputSS, bar.close))
orderid = self.cover(price=bar.close, volume=self.inputSS, orderTime=self.curDateTime)
if orderid:
# 更新下单时间(为了定时撤单)
self.lastOrderTime = self.curDateTime
return
# 执行收盘前平仓检查
self.__dailyCloseCheck(bar)
def __cancelLogic(self, dt, force=False):
"撤单逻辑"""
if len(self.uncompletedOrders) < 1:
return
if not self.lastOrderTime:
self.writeCtaLog(u'异常,上一交易时间为None')
return
# 平仓检查时间比开开仓时间需要短一倍
if (self.position.pos >= 0 and self.entrust == 1) \
or (self.position.pos <= 0 and self.entrust == -1):
i = 1
else:
i = 1 # 原来是2,暂时取消
canceled = False
if ((dt - self.lastOrderTime).seconds > self.cancelSeconds / i ) \
or force: # 超过设置的时间还未成交
for order in self.uncompletedOrders.keys():
self.writeCtaLog(u'{0}超时{1}秒未成交,取消委托单:{2}'.format(dt, (dt - self.lastOrderTime).seconds, order))
self.cancelOrder(str(order))
canceled = True
# 取消未完成的订单
self.uncompletedOrders.clear()
if canceled:
self.entrust = 0
self.policy.entryPrice = 0
else:
self.writeCtaLog(u'异常:没有撤单')
def __dailyCloseCheck(self, bar):
"""每天收盘前检查,如果是亏损单,则平掉"""
if self.position.pos == 0 and self.entrust == 0:
return False
if bar.time not in ['14:45:00','14:50:00','14:55:00','22:45:00','22:50:00','22:55:00']:
return False
# 撤销未成交的订单
if len(self.uncompletedOrders) > 0:
for order in self.uncompletedOrders.keys():
self.writeCtaLog(u'{0},收盘前15分钟,仍未成交,取消委托单:{1}'.format(bar.datetime,order))
self.cancelOrder(str(order))
self.uncompletedOrders.clear()
self.entrust = 0
# 强制平仓
if self.position.pos > 0 and bar.close < self.policy.entryPrice + self.atr:
self.writeCtaLog(u'强制日内平亏损多仓')
# 降低两个滑点
orderid = self.sell(price=bar.close-2*self.minDiff, volume=self.inputSS, orderTime=self.curDateTime)
if orderid:
# 更新下单时间
self.lastOrderTime = self.curDateTime
return True
if self.position.pos < 0 and bar.close > self.policy.entryPrice - self.atr:
self.writeCtaLog(u'强制日内平亏损空仓')
orderid = self.cover(price=bar.close+2*self.minDiff, volume=self.inputSS, orderTime=self.curDateTime)
if orderid:
# 更新下单时间(为了定时撤单)
self.lastOrderTime = self.curDateTime
return True
return True
def __timeWindow(self, dt):
"""交易与平仓窗口"""
# 交易窗口 避开早盘和夜盘的前5分钟,防止隔夜跳空。
self.closeWindow = False
self.tradeWindow = False
self.openWindow = False
# 初始化当日的首次交易
# if (tick.datetime.hour == 9 or tick.datetime.hour == 21) and tick.datetime.minute == 0 and tick.datetime.second ==0:
# self.firstTrade = True
# 开市期,波动较大,用于判断止损止盈,或开仓
if (dt.hour == 9 or dt.hour == 21) and dt.minute < 2:
self.openWindow = True
# 日盘
if dt.hour == 9 and dt.minute >= 0:
self.tradeWindow = True
return
if dt.hour == 10:
if dt.minute <= 15 or dt.minute >= 30:
self.tradeWindow = True
return
if dt.hour == 11 and dt.minute <= 30:
self.tradeWindow = True
return
if dt.hour == 13 and dt.minute >= 30:
self.tradeWindow = True
return
if dt.hour == 14:
if dt.minute < 59:
self.tradeWindow = True
return
if dt.minute == 59: # 日盘平仓
self.closeWindow = True
return
# 夜盘
if dt.hour == 21 and dt.minute >= 0:
self.tradeWindow = True
return
# 上期 贵金属, 次日凌晨2:30
if self.shortSymbol in NIGHT_MARKET_SQ1:
if dt.hour == 22 or dt.hour == 23 or dt.hour == 0 or dt.hour == 1:
self.tradeWindow = True
return
if dt.hour == 2:
if dt.minute < 29: # 收市前29分钟
self.tradeWindow = True
return
if dt.minute == 29: # 夜盘平仓
self.closeWindow = True
return
return
# 上期 有色金属,黑色金属,沥青 次日01:00
if self.shortSymbol in NIGHT_MARKET_SQ2:
if dt.hour == 22 or dt.hour == 23:
self.tradeWindow = True
return
if dt.hour == 0:
if dt.minute < 59: # 收市前29分钟
self.tradeWindow = True
return
if dt.minute == 59: # 夜盘平仓
self.closeWindow = True
return
return
# 上期 天然橡胶 23:00
if self.shortSymbol in NIGHT_MARKET_SQ3:
if dt.hour == 22:
if dt.minute < 59: # 收市前1分钟
self.tradeWindow = True
return
if dt.minute == 59: # 夜盘平仓
self.closeWindow = True
return
# 郑商、大连 23:30
if self.shortSymbol in NIGHT_MARKET_ZZ or self.shortSymbol in NIGHT_MARKET_DL:
if dt.hour == 22:
self.tradeWindow = True
return
if dt.hour == 23:
if dt.minute < 29: # 收市前1分钟
self.tradeWindow = True
return
if dt.minute == 29 and dt.second > 30: # 夜盘平仓
self.closeWindow = True
return
return
#----------------------------------------------------------------------
def strToTime(self, t, ms):
"""从字符串时间转化为time格式的时间"""
hh, mm, ss = t.split(':')
tt = datetime.time(int(hh), int(mm), int(ss), microsecond=ms)
return tt
#----------------------------------------------------------------------
def saveData(self, id):
"""保存过程数据"""
# 保存K线
if not self.backtesting:
return
#回测
def testRbByTick():
# 创建回测引擎
engine = BacktestingEngine()
# 设置引擎的回测模式为Tick
engine.setBacktestingMode(engine.TICK_MODE)
# 设置回测用的数据起始日期
engine.setStartDate('20160101')
# 设置回测用的数据结束日期
engine.setEndDate('20160330')
# engine.connectMysql()
engine.setDatabase(dbName='ticks', symbol='rb')
# 设置产品相关参数
engine.setSlippage(0) # 1跳(0.1)2跳0.2
engine.setRate(float(0.0001)) # 万1
engine.setSize(10) # 合约大小
settings = {}
settings['shortSymbol'] = 'RB'
settings['name'] = 'TripleMa'
settings['mode'] = 'tick'
settings['backtesting'] = True
# 在引擎中创建策略对象
engine.initStrategy(Strategy_TripleMa, setting=settings)
# 使用简单复利模式计算
engine.usageCompounding = False # True时,只针对FINAL_MODE有效
# 启用实时计算净值模式REALTIME_MODE / FINAL_MODE 回测结束时统一计算模式
engine.calculateMode = engine.REALTIME_MODE
engine.initCapital = 100000 # 设置期初资金
engine.percentLimit = 30 # 设置资金使用上限比例(%)
engine.barTimeInterval = 60 * 5 # bar的周期秒数,用于csv文件自动减时间
engine.fixCommission = 10 # 固定交易费用(每次开平仓收费)
# 开始跑回测
engine.runBacktesting()
# 显示回测结果
engine.showBacktestingResult()
def testRbByBar():
# 创建回测引擎
engine = BacktestingEngine()
# 设置引擎的回测模式为Tick
engine.setBacktestingMode(engine.BAR_MODE)
# 设置回测用的数据起始日期
engine.setStartDate('20160101')
# 设置回测用的数据结束日期
engine.setEndDate('20161231')
engine.setDatabase(dbName='bars',symbol='rb')
# 设置产品相关参数
engine.setSlippage(0) # 1跳(0.1)2跳0.2
engine.setRate(float(0.0001)) # 万1
engine.setSize(10) # 合约大小
settings = {}
settings['vtSymbol'] = 'rb'
settings['shortSymbol'] = 'RB'
settings['name'] = 'TripleMa'
settings['mode'] = 'bar'
settings['backtesting'] = True
settings['percentLimit'] = 30
# 在引擎中创建策略对象
engine.initStrategy(Strategy_TripleMa, setting=settings)
# 使用简单复利模式计算
engine.usageCompounding = False # True时,只针对FINAL_MODE有效
# 启用实时计算净值模式REALTIME_MODE / FINAL_MODE 回测结束时统一计算模式
engine.calculateMode = engine.REALTIME_MODE
engine.initCapital = 100000 # 设置期初资金
engine.percentLimit = 30 # 设置资金使用上限比例(%)
engine.barTimeInterval = 300 # bar的周期秒数,用于csv文件自动减时间
# 开始跑回测
cta_engine_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
data_file = os.path.abspath(os.path.join(cta_engine_path, 'TestLogs', 'RB88_20100101_20161231_M5.csv'))
engine.runBackTestingWithBarFile(data_file)
# 显示回测结果
engine.showBacktestingResult()
# 从csv文件进行回测
if __name__ == '__main__':
# 提供直接双击回测的功能
# 导入PyQt4的包是为了保证matplotlib使用PyQt4而不是PySide,防止初始化出错
from ctaBacktesting import *
from setup_logger import setup_logger
cta_engine_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
log_file_name = os.path.abspath(os.path.join(cta_engine_path, 'TestLogs',
'{0}_{1}.log'.format(Strategy_TripleMa.className,
datetime.now().strftime('%m%d_%H%M'))))
setup_logger(filename=log_file_name,debug=False)
# 回测螺纹
testRbByBar()