#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()

results matching ""

    No results matching ""