class CciSignal(CtaSignal):
    """CCI信号"""

    # ----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        super(CciSignal, self).__init__()

        self.cciWindow = 10
        self.cciLevel = 20
        self.cciLong = self.cciLevel
        self.cciShort = -self.cciLevel
        self.cciValue = 0.0
        self.bg = BarGenerator(self.onBar, 15, self.on15Bar)
        self.am = ArrayManager()

    # ----------------------------------------------------------------------
    def onTick(self, tick):
        """Tick更新"""
        self.bg.updateTick(tick)

    # ----------------------------------------------------------------------
    def onBar(self, bar):
        """K线更新"""
        self.bg.updateBar(bar)

    def on15Bar(self, bar):

        self.am.updateBar(bar)
        print bar.datetime
        print "@cciSignal"
        print "cci inited: ", self.am.inited

        if not self.am.inited:
            self.setSignalPos(0)
            return

        self.cciValue = self.am.cci(self.cciWindow)

        print "cciValue: ", self.cciValue

        if self.cciValue >= self.cciLong:
            self.setSignalPos(1)
        elif self.cciValue <= self.cciShort:
            self.setSignalPos(-1)
        else:
            self.setSignalPos(0)
class AtrSignal(CtaSignal):
    """Atr信号"""

    # ----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        super(AtrSignal, self).__init__()
        self.atrWindow = 30
        self.bg = BarGenerator(self.onBar, 15, self.on15Bar)
        self.am = ArrayManager()
        self.atrValue = 0.0
        # ----------------------------------------------------------------------

    def onTick(self, tick):
        """Tick更新"""
        self.bg.updateTick(tick)

    # ----------------------------------------------------------------------
    def onBar(self, bar):
        """K线更新"""
        self.bg.updateBar(bar)

    # ----------------------------------------------------------------------
    def on15Bar(self, bar):
        """15分钟K线更新"""
        self.am.updateBar(bar)

        print bar.datetime
        print "@atrSignal"
        print "atr inited: ", self.am.inited

        if not self.am.inited:
            self.setSignalPos(0)
            return

        atrArray = self.am.atr(self.atrWindow, array=True)
        self.atrValue = atrArray[-1]
        atrMa = atrArray[-self.atrWindow:].mean()

        print "atrValue: ", self.atrValue

        # 趋势增强
        if self.atrValue > atrMa:
            self.setSignalPos(1)
        else:
            self.setSignalPos(0)
class MaSignal(CtaSignal):
    """双均线信号"""

    # ----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        super(MaSignal, self).__init__()

        self.fastWindow = 5
        self.slowWindow = 20

        self.bg = BarGenerator(self.onBar, 5, self.onFiveBar)
        self.am = ArrayManager()

        # ----------------------------------------------------------------------

    def onTick(self, tick):
        """Tick更新"""
        self.bg.updateTick(tick)

    # ----------------------------------------------------------------------
    def onBar(self, bar):
        """K线更新"""
        self.bg.updateBar(bar)

    # ----------------------------------------------------------------------
    def onFiveBar(self, bar):
        """5分钟K线更新"""
        self.am.updateBar(bar)

        if not self.am.inited:
            self.setSignalPos(0)

        fastMa = self.am.sma(self.fastWindow)
        slowMa = self.am.sma(self.slowWindow)

        if fastMa > slowMa:
            self.setSignalPos(1)
        elif fastMa < slowMa:
            self.setSignalPos(-1)
        else:
            self.setSignalPos(0)
Exemple #4
0
class MaSignal(CtaSignal):
    """双均线信号"""
    
    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        super(MaSignal, self).__init__()
        
        self.fastWindow = 5
        self.slowWindow = 20
        
        self.bg = BarGenerator(self.onBar, 5, self.onFiveBar)
        self.am = ArrayManager()        
        
    #----------------------------------------------------------------------
    def onTick(self, tick):
        """Tick更新"""
        self.bg.updateTick(tick)
        
    #----------------------------------------------------------------------
    def onBar(self, bar):
        """K线更新"""
        self.bg.updateBar(bar)
    
    #----------------------------------------------------------------------
    def onFiveBar(self, bar):
        """5分钟K线更新"""
        self.am.updateBar(bar)
        
        if not self.am.inited:
            self.setSignalPos(0)
            
        fastMa = self.am.sma(self.fastWindow)
        slowMa = self.am.sma(self.slowWindow)
        
        if fastMa > slowMa:
            self.setSignalPos(1)
        elif fastMa < slowMa:
            self.setSignalPos(-1)
        else:
            self.setSignalPos(0)
class BollSignal(CtaSignal):
    """布林带信号"""

    # ----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        super(BollSignal, self).__init__()

        self.bollWindow = 18
        self.bollDev = 5
        # self.bollUp, self.bollDown = 0.0,0.0
        self.bg = BarGenerator(self.onBar, 15, self.on15Bar)
        self.am = ArrayManager()

        # ----------------------------------------------------------------------

    def onTick(self, tick):
        """Tick更新"""
        self.bg.updateTick(tick)

    # ----------------------------------------------------------------------
    def onBar(self, bar):
        """K线更新"""
        self.bg.updateBar(bar)

    # ----------------------------------------------------------------------
    def on15Bar(self, bar):
        """15分钟K线更新"""
        self.am.updateBar(bar)

        if not self.am.inited:
            self.setSignalPos(0)
        bollUp, bollDown = self.am.boll(self.bollWindow, self.bollDev)

        if bar.close >= bollUp:
            self.setSignalPos(1)
        elif bar.close <= bollDown:
            self.setSignalPos(-1)
        else:
            self.setSignalPos(0)
class MultiSignalStrategy(TargetPosTemplate):
    """CCI+ATR合成信号策略"""
    className = 'MultiSignalStrategy'
    author = 'Y.Raul'
    # 策略参数
    initDays = 10  # 初始化数据所用的天数
    fixedSize = 1  # 每次交易的数量
    # 策略变量
    signalPos = {}  # 信号仓位
    # 参数列表,保存了参数的名称
    paramList = ['name', 'className', 'author', 'vtSymbol']
    # 变量列表,保存了变量的名称
    varList = ['inited', 'trading', 'pos', 'signalPos', 'targetPos']
    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(MultiSignalStrategy, self).__init__(ctaEngine, setting)
        self.cciSignal = CciSignal()
        self.trailingStopSignal = TrailingStopSignal()
        self.atrSignal = AtrSignal()
        self.rsiSignal = RsiSignal()
        self.signalPos = {"cci": 0, "atr": 0, "rsi": 0}
        self.entryPriceList = []
        self.avgEntryPrice = 0.0
        self.bg = BarGenerator(self.onBar, 15, self.on15Bar)

    #----------------------------------------------------------------------
    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推送(必须由用户继承实现)"""
        super(MultiSignalStrategy, self).onTick(tick)

        self.atrSignal.onTick(tick)
        self.cciSignal.onTick(tick)
        self.rsiSignal.onTick(tick)

        if self.pos:
            self.trailingStopSignal.onTick(tick)

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        super(MultiSignalStrategy, self).onBar(bar)

        self.atrSignal.onBar(bar)
        self.cciSignal.onBar(bar)
        self.rsiSignal.onBar(bar)

        # 更新trailingStop中的ATR值
        self.trailingStopSignal.atrValue = self.atrSignal.atrValue
        self.trailingStopSignal.onBar(bar)

        self.bg.updateBar(bar)

    def on15Bar(self, bar):

        self.signalPos['atr'] = self.atrSignal.getSignalPos()
        self.signalPos['cci'] = self.cciSignal.getSignalPos()
        self.signalPos['rsi'] = self.rsiSignal.getSignalPos()

        # 记录log
        log = "-----" * 10 + "\n@on15Bar\n" + \
              "bar.datetime: {0}\n".format(bar.datetime) + \
              "cci: {0}; atr: {1}; trailing: {2}\n".format(self.signalPos['cci'], self.signalPos['atr'],self.trailingStopSignal.signalPos) +\
              "pos: {0}\n".format(self.pos)+\
            "cciValue: {0}, atrValue: {1}, rsiValue: {2}\n".format(self.cciSignal.cciValue,self.atrSignal.atrValue, self.rsiSignal.rsiValue)
        self.writeCtaLog(log)

        self.caculatePos(bar)

    def caculatePos(self, bar):
        """
        根据信号合成计算仓位
        """
        # 记录log
        log = "-----" * 10 + "\n@caculatePos\n" + \
              "bar.datetime: {0}\n".format(bar.datetime) + \
              "cci: {0}; atr: {1}; trailing: {2}\n".format(self.signalPos['cci'], self.signalPos['atr'],self.trailingStopSignal.signalPos) +\
              "pos: {0}\n".format(self.pos)
        self.writeCtaLog(log)

        # 开仓
        if self.pos == 0 and self.signalPos['atr'] == 1:
            if (self.signalPos['cci'] == 1 and self.signalPos['rsi'] == 1):

                # 记录log
                log = '\n [Buy]\n'
                self.writeCtaLog(log)

                self.setTargetPos(self.fixedSize)
            if (self.signalPos['cci'] == -1 and self.signalPos['rsi'] == -1):
                # 记录log
                log = '\n [Short]\n'
                self.writeCtaLog(log)
                self.setTargetPos(-1 * self.fixedSize)

        # 平仓
        if self.pos != 0 and self.trailingStopSignal.getSignalPos() == 0:

            # 记录log
            log = "-----" * 10 + "\n@trailingStop\n" + \
              "bar.datetime: {0}\n".format(bar.datetime) + \
              "atr: {0}; intraHigh: {1}; intraLow: {2}\n".format(self.trailingStopSignal.atrValue, self.trailingStopSignal.intraTradeHigh,
                                                           self.trailingStopSignal.intraTradeLow) + \
              "holdpos: {0}\n".format(self.trailingStopSignal.holdPos) +\
                "longStop: {0}; shortStop: {1}\n".format(self.trailingStopSignal.longStop,self.trailingStopSignal.shortStop) +\
              "close: {0}\n".format(bar.close) +\
                "tailingStop: {0}\n".format(self.trailingStopSignal.getSignalPos())
            self.writeCtaLog(log)

            if self.pos > 0:
                # 记录log
                log = '\n [Sell]\n'
                self.writeCtaLog(log)

            elif self.pos < 0:
                # 记录log
                log = '\n [Cover]\n'
                self.writeCtaLog(log)

            # 重置信号
            self.atrSignal = AtrSignal()
            self.cciSignal = CciSignal()
            self.rsiSignal = RsiSignal()

            # 设置策略仓位
            self.setTargetPos(0)

    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        super(MultiSignalStrategy, self).onOrder(order)

        if order.direction == DIRECTION_LONG and order.offset == OFFSET_OPEN:
            if order.totalVolume == order.tradedVolume:
                # 更新入场价列表,更新平均入场价
                self.entryPriceList.append(order.price)
                self.avgEntryPrice = sum(self.entryPriceList) / len(
                    self.entryPriceList)
                self.trailingStopSignal.intraTradeHigh = self.avgEntryPrice

        elif order.direction == DIRECTION_SHORT and order.offset == OFFSET_OPEN:
            if order.totalVolume == order.tradedVolume:
                # 更新入场价列表,更新平均入场价
                self.entryPriceList.append(order.price)
                self.avgEntryPrice = sum(self.entryPriceList) / len(
                    self.entryPriceList)
                self.trailingStopSignal.intraTradeLow = self.avgEntryPrice

        # 更新trailingStop中的仓位
        self.trailingStopSignal.holdPos = self.pos
        self.putEvent()

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Exemple #7
0
class DT_ChengfaStrategy(CtaTemplate):
    """DualThrust交易策略"""
    className = 'DT_ChengfaStrategy'
    author = u'Leon Zhao'

    # 策略参数
    fixedSize = 1
    k1 = 0.4
    k2 = 0.4
    
    rangeDays = 4
    initDays = 30 # original value is 10
    atrDays = 20


    # 策略变量
    barList = []                # K线对象的列表

    dayOpen = 0
    rangeHigh = 0
    rangeLow = 0
    rangeHighClose = 0
    rangeLowClose = 0
    range1 = 0
    range2 = 0
    
    range = 0
    longEntry = 0
    shortEntry = 0
    exitTime = time(hour=15, minute=20) #will not cover position when day close

    longEntered = False
    shortEntered = False

    # 参数列表,保存了参数的名称
    paramList = ['name',
                 'className',
                 'author',
                 'vtSymbol',
                 'k1',
                 'k2']    

    # 变量列表,保存了变量的名称
    varList = ['inited',
               'trading',
               'pos',
               'range',
               'longEntry',
               'shortEntry',
               'exitTime'] 
    longEntry1 = 0
    shortEntry1 = 0
    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos','range','longEntry1','shortEntry1']    

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(DT_ChengfaStrategy, self).__init__(ctaEngine, setting) 
        
        self.bg = BarGenerator(self.onBar,onDayBar = self.ondayBar,vtSymbol =self.vtSymbol)
        self.am = ArrayManager()
        self.barList = []
        self.longEntry1 = 0
        self.shortEntry1 = 0        
        # Read Parameters from Setting files
        if 'strParams' in setting:
            self.params = setting['strParams']
            if len(self.params)>=3:
                for p in self.params:
                    if p[0] == 'unit':
                        self.fixedSize = p[1]
                    if p[0] == 'p1':
                        self.k1 = p[1]
                    if p[0] == 'p2':
                        self.k2 = p[1]
                    if p[0] == 'p3':
                        self.rangeDays = p[1]
                    if p[0] == 'p4':
                        self.atrDays = p[1]  
                    if p[0] == 'p5':
                        self.initDays = p[1]                                                 

        else:
            # 策略参数
            self.fixedSize = 1
            self.k1 = 0.4
            self.k2 = 0.4
            
            self.rangeDays = 4
            self.atrDays = 20
            self.initDays = 55 # original value is 10     
        #print(self.fixedSize,self.k1,self.k2,self.rangeDays,self.initDays)             
        self.dayOpen = 0
        self.rangeHigh = 0
        self.rangeLow = 0
        self.rangeHighClose = 0
        self.rangeLowClose = 0
        self.range1 = 0
        self.range2 = 0
        self.atrValue = 0
        
        self.range = 0
        self.longEntry = 0
        self.shortEntry = 0
        self.exitTime = time(hour=15, minute=20) #will not cover position when day close
        self.longEntered = False
        self.shortEntered = False
        self.testflag = False
                
    #----------------------------------------------------------------------
    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推送(必须由用户继承实现)"""
        #ignore data before real open
        if (tick.datetime.hour == 8 or tick.datetime.hour ==20):
            return
        self.bg.updateTick(tick)
        
    def calcUnitNo(self,atr,fixSize):
        dtCap = 0.0
        defaultCap = 0.0
        unitNo = 0
        cust = []
        var_sizelist = CtaTemplate.vol_Size
        var_size = 0.0
        var_Symbol = ""
        if len(var_sizelist) == 0:
            return fixSize
        else:
            var_Symbol = var_Symbol.join(list(filter(lambda x: x.isalpha(),self.vtSymbol)))            
            var_size = float(var_sizelist[var_Symbol][0])
            if var_size -0 < 0.01:
                return fixSize
        
        var_temp = 0.0
        if len(CtaTemplate.cust_Setting) > 0:
            cust = CtaTemplate.cust_Setting
        for cs in cust:
            if cs["StrategyGroup"] == "DT" and cs["Status"] == 'True':
                dtCap = cs["CaptialAmt"]
                break
            if cs["StrategyGroup"] == "Default" and cs["Status"] == 'True':
                defaultCap = cs["CaptialAmt"]
        if dtCap > 0:
            self.capConfig = float(dtCap)
        elif defaultCap > 0 :
            self.capConfig = float(defaultCap)
        else:
            self.capConfig = 0.0
        
        unitNo = 0
        if self.capConfig -0 < 0.0001:
            unitNo = fixSize
        elif var_size - 0 < 0.001:
            unitNo = fixSize
        else:
            unitNo = int(self.capConfig * 0.0088 /(atr*var_size))
        if unitNo < 1:
            unitNo = 1
        return unitNo    
        
    #---------calcuate range for the last several days 
    def calcRange(self):
        if self.am.count >= self.atrDays + 1 :
            self.atrValue = self.am.atr(self.atrDays,False)
            if self.atrValue > 0 :
                self.fixedSize = self.calcUnitNo(self.atrValue, self.fixedSize)          
            self.rangeHigh = talib.MAX(self.am.high,self.rangeDays)[-1]
            self.rangeLow =  talib.MIN(self.am.low,self.rangeDays)[-1]
            self.rangeHighClose = talib.MAX(self.am.close,self.rangeDays)[-1]
            self.rangeLowClose  = talib.MIN(self.am.close,self.rangeDays)[-1]
            self.range1 = self.rangeHigh-self.rangeLowClose
            self.range2 = self.rangeHighClose -self.rangeLow
            
            #print(self.rangeHigh,self.rangeLow)
            if (self.range1 > self.range2) :
                calcRange = self.range1
            else:
                calcRange = self.range2
        else:
            calcRange = 0
        return calcRange            
        
    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        self.fixedSize = 1
        if self.reduceCountdown() > 0:
            return
        # 撤销之前发出的尚未成交的委托(包括限价单和停止单)
        self.cancelAll()

        self.bg.updateBar(bar)
        barLength = 0
     
        # 计算指标数值
        self.barList.append(bar)
        
        if len(self.barList) <= 2:
            return
        else:
            self.barList.pop(0)
        lastBar = self.barList[-2]
        print(bar.close)
        
        if self.testflag:
            return
        if self.pos == 0:
            self.buy(bar.close,self.fixedSize)
        elif self.pos > 0:

            self.sell(bar.close,abs(self.pos))
            if not self.shortEntered:
                #self.short(self.shortEntry -2 , self.fixedSize)
                self.short(bar.close,self.fixedSize)
            self.testflag = True
            # 持有空头仓位
        elif self.pos < 0:            
            self.cover(bar.close,abs(self.pos))
            if not self.longEntered:
                self.buy(bar.close,self.fixedSize) 
            self.testflag = True
        # 发出状态更新事件
        self.putEvent()
    #update day chart
    def ondayBar(self, dayBar):
        """收到日线推送(必须由用户继承实现)"""
        self.am.updateBar(dayBar)
        self.range = None
        self.dayOpen = 0
        # 发出状态更新事件
        self.putEvent() 
    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        pass

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        persisttrade(self.vtSymbol,self.className ,trade)
        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Exemple #8
0
class EMAC_IntraDayCommonStrategy(CtaTemplate):
    """DualThrust交易策略"""
    className = 'EMAC_IntraDayCommonStrategy'
    author = u'Leon Zhao'

    # 策略参数
    fixedSize = 1
    fast1 = 5
    slow1 = 21

    fast2 = 8
    slow2 = 34

    fast3 = 13
    slow3 = 55
    dbpath = "./sr.csv"
    cumrange = 0
    shreshhold = 0.3
    atrDays = 20
    atrValue = 0
    initDays = 35
    # 策略变量
    barList = []  # K线对象的列表

    longEntry = 0
    shortEntry = 0
    exitTime = time(hour=15,
                    minute=20)  #will not cover position when day close

    longEntered = False
    shortEntered = False

    # 参数列表,保存了参数的名称
    paramList = ['name', 'className', 'author', 'vtSymbol']

    # 变量列表,保存了变量的名称
    varList = [
        'inited', 'trading', 'pos', 'cumrange', 'longEntry', 'shortEntry',
        'exitTime'
    ]
    range = 0
    longEntry1 = 0
    shortEntry1 = 0
    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos', 'range', 'longEntry1', 'shortEntry1']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(EMAC_IntraDayCommonStrategy, self).__init__(ctaEngine, setting)

        self.bg = BarGenerator(self.onBar,
                               onDayBar=self.ondayBar,
                               vtSymbol=self.vtSymbol)
        self.am = ArrayManager()
        self.indexam = ArrayManager()
        self.barList = []
        self.longEntry1 = 0
        self.shortEntry1 = 0
        # Read Parameters from Setting files
        if 'strParams' in setting:
            self.params = setting['strParams']
            if len(self.params) >= 3:
                for p in self.params:
                    if p[0] == 'unit':
                        self.fixedSize = p[1]
                    if p[0] == 'p1':
                        self.fast1 = p[1]
                    if p[0] == 'p2':
                        self.slow1 = p[1]
                    if p[0] == 'p3':
                        self.fast2 = p[1]
                    if p[0] == 'p4':
                        self.slow2 = p[1]
                    if p[0] == 'p5':
                        self.fast3 = p[1]
                    if p[0] == 'p6':
                        self.slow3 = p[1]
                    if p[0] == 'p7':
                        self.dbpath = p[1]
        else:
            # 策略参数
            self.fast1 = 5
            self.slow1 = 21

            self.fast2 = 8
            self.slow2 = 34

            self.fast3 = 13
            self.slow3 = 55
            self.dbpath = "./sr.csv"
        #print(self.fixedSize,self.k1,self.k2,self.rangeDays,self.initDays)
        self.cumrange = 0
        self.shreshhold = 0.3
        self.atrDays = 20
        self.atrValue = 0
        self.initDays = 100
        self.longEntry = 0
        self.shortEntry = 0
        self.exitTime = time(
            hour=15, minute=20)  #will not cover position when day close
        self.longEntered = False
        self.shortEntered = False
        self.emac_kpi = 0
        self.emac1scalar = 7.5
        self.emac2scalar = 5.3
        self.emac3scalar = 3.7
        self.pcstd = 0
        self.weights = [0.35, 0.3, 0.35]

    def loadIndexBar(self, dbpath):
        csvfile = "../TdxData/bar_data/" + dbpath
        #print(csvfile)
        dfindex = pd.read_csv(csvfile, parse_dates=True, index_col=0)
        #print(dbpath)
        dfindex["pc"] = dfindex["close"] - dfindex["close"].shift(-1)
        #dfordered = dfindex.sort_index( ascending=False)
        daybar = VtBarData()

        dt = datetime.now()
        for idx, indexbar in dfindex.iterrows():
            #print(idx)
            daybar.vtSymbol = self.vtSymbol
            daybar.symbol = self.vtSymbol
            daybar.exchange = ""

            daybar.open = indexbar["open"]
            daybar.high = indexbar["high"]
            daybar.low = indexbar["low"]
            daybar.close = indexbar["close"]
            #dt = datetime.strptime(str(indexbar["trade_date"]),"%Y%m%d")
            #change bar Date to next day if time is night
            #nextDay =
            daybar.datetime = idx  # 以第一根分钟K线的开始时间戳作为X分钟线的时间戳
            daybar.date = daybar.datetime.strftime('%Y%m%d')
            daybar.time = daybar.datetime.strftime('%H:%M:%S.%f')
            #print(daybar.datetime,daybar.close)
            self.indexam.updateBar(daybar)
        temp = dfindex["pc"].rolling(20, min_periods=20).std()
        temp = temp.dropna()
        self.pcstd = temp.iloc[-1]

    #----------------------------------------------------------------------
    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        self.writeCtaLog(u'%s策略初始化' % self.name)

        # 载入历史数据,并采用回放计算的方式初始化策略数值
        initData = self.loadBar(self.initDays)
        #dbpath = ""
        self.loadIndexBar(self.dbpath)
        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推送(必须由用户继承实现)"""
        #ignore data before real open
        if (tick.datetime.hour == 8 or tick.datetime.hour == 20):
            return
        self.bg.updateTick(tick)

    def calcUnitNo(self, atr, fixSize):
        dtCap = 0.0
        defaultCap = 0.0
        unitNo = 0
        cust = []
        var_sizelist = CtaTemplate.vol_Size
        var_size = 0.0
        var_Symbol = ""
        if len(var_sizelist) == 0:
            return fixSize
        else:
            var_Symbol = var_Symbol.join(
                list(filter(lambda x: x.isalpha(), self.vtSymbol)))
            var_size = float(var_sizelist[var_Symbol][0])
            if var_size - 0 < 0.01:
                return fixSize

        var_temp = 0.0
        if len(CtaTemplate.cust_Setting) > 0:
            cust = CtaTemplate.cust_Setting
        for cs in cust:
            if cs["StrategyGroup"] == "DT" and cs["Status"] == 'True':
                dtCap = cs["CaptialAmt"]
                break
            if cs["StrategyGroup"] == "Default" and cs["Status"] == 'True':
                defaultCap = cs["CaptialAmt"]
        if dtCap > 0:
            self.capConfig = float(dtCap)
        elif defaultCap > 0:
            self.capConfig = float(defaultCap)
        else:
            self.capConfig = 0.0

        unitNo = 0
        if self.capConfig - 0 < 0.0001:
            unitNo = fixSize
        elif var_size - 0 < 0.001:
            unitNo = fixSize
        else:
            unitNo = int(self.capConfig * 0.0088 / (atr * var_size))
        if unitNo < 1:
            unitNo = 1

        return unitNo

    #---------calcuate range for the last several days
    def getUnitNo(self):
        if self.am.count >= self.atrDays + 1:
            self.atrValue = self.am.atr(self.atrDays, False)
            if self.atrValue > 0:
                self.fixedSize = self.calcUnitNo(self.atrValue, self.fixedSize)
        else:
            pass

    def CalcKPI(self):
        #pass
        emafast1 = self.indexam.ema(self.fast1)
        emaslow1 = self.indexam.ema(self.slow1)
        emafast2 = self.indexam.ema(self.fast2)
        emaslow2 = self.indexam.ema(self.slow2)
        emafast3 = self.indexam.ema(self.fast3)
        emaslow3 = self.indexam.ema(self.slow3)

        kpi = self.emac1scalar * (
            emafast1 -
            emaslow1) * self.weights[0] / self.pcstd + self.emac2scalar * (
                emafast2 -
                emaslow2) * self.weights[1] / self.pcstd + self.emac3scalar * (
                    emafast3 - emaslow3) * self.weights[2] / self.pcstd
        return kpi
        #indexvol = self.indexam

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""

        if self.reduceCountdown() > 0:
            return
        # 撤销之前发出的尚未成交的委托(包括限价单和停止单)

        self.cancelAll()

        self.bg.updateBar(bar)
        barLength = 0
        barLength = self.atrDays + 1
        if self.am.count < barLength:
            return
        # 计算指标数值
        self.barList.append(bar)

        if len(self.barList) <= 2:
            return
        else:
            self.barList.pop(0)
        lastBar = self.barList[-2]

        self.getUnitNo()
        self.emac_kpi = self.CalcKPI()
        #print(self.emac_kpi,bar.close)
        pos_multiple = 1
        if abs(self.emac_kpi) > 30:
            pos_multiple = 2
        else:
            pos_multiple = 1
        #print(self.emac_kpi)
        if True:  # Trade Time, no matter when, just send signal
            if self.pos == 0:
                self.longEntered = False
                self.shortEntered = False
                if self.emac_kpi > 1:
                    self.buy(bar.close, self.fixedSize * pos_multiple)
                elif self.emac_kpi < -1:
                    self.short(bar.close, self.fixedSize * pos_multiple)
                else:
                    pass

            # 持有多头仓位
            elif self.pos > 0:
                self.longEntered = True
                self.shortEntered = False
                # 多头止损单
                if self.emac_kpi < 1 and self.emac_kpi > -1:
                    #self.sell(self.shortEntry -2 , self.fixedSize)
                    self.sell(bar.close, abs(self.pos))
                    # 空头开仓单
                elif self.emac_kpi < -1:
                    self.sell(bar.close,
                              abs(self.pos))  # close first then open new
                    if not self.shortEntered:
                        #self.short(self.shortEntry -2 , self.fixedSize)
                        self.short(bar.close, self.fixedSize * pos_multiple)
            # 持有空头仓位
            elif self.pos < 0:
                self.shortEntered = True
                self.longEntered = False
                # 空头止损单
                if self.emac_kpi > -1 and self.emac_kpi < 1:
                    #self.cover(self.longEntry + 2, self.fixedSize)
                    self.cover(bar.close, abs(self.pos))
                    # 多头开仓单

                elif self.emac_kpi > 1:
                    self.cover(bar.close,
                               abs(self.pos))  # close first then open new
                    if not self.longEntered:
                        #self.buy(self.longEntry + 2, self.fixedSize)
                        self.buy(bar.close, self.fixedSize)
        # 收盘平仓 This will not execute
        else:
            if self.pos > 0:
                self.sell(bar.close * 0.99, abs(self.pos))
            elif self.pos < 0:
                self.cover(bar.close * 1.01, abs(self.pos))

        # 发出状态更新事件
        self.putEvent()

    #update day chart
    def ondayBar(self, dayBar):
        """收到日线推送(必须由用户继承实现)"""
        self.am.updateBar(dayBar)
        self.range = None
        self.dayOpen = 0
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        pass

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        persisttrade(self.vtSymbol, self.className, trade)
        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
class MultiTimeframeStrategy(CtaTemplate):
    """跨时间周期交易策略"""
    className = 'MultiTimeframeStrategy'
    author = u'用Python的交易员'

    # 策略参数
    rsiSignal = 20          # RSI信号阈值
    rsiWindow = 14          # RSI窗口
    fastWindow = 5          # 快速均线窗口
    slowWindow = 20         # 慢速均线窗口
    
    initDays = 10           # 初始化数据所用的天数
    fixedSize = 1           # 每次交易的数量

    # 策略变量
    rsiValue = 0                        # RSI指标的数值
    rsiLong = 0                         # RSI买开阈值
    rsiShort = 0                        # RSI卖开阈值
    fastMa = 0                          # 5分钟快速均线
    slowMa = 0                          # 5分钟慢速均线
    maTrend = 0                         # 均线趋势,多头1,空头-1
    
    # 参数列表,保存了参数的名称
    paramList = ['name',
                 'className',
                 'author',
                 'vtSymbol',
                 'rsiSignal',
                 'rsiWindow',
                 'fastWindow',
                 'slowWindow']    

    # 变量列表,保存了变量的名称
    varList = ['inited',
               'trading',
               'pos',
               'rsiValue',
               'rsiLong',
               'rsiShort',
               'fastMa',
               'slowMa',
               'maTrend']  
    
    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(MultiTimeframeStrategy, self).__init__(ctaEngine, setting)
        
        self.rsiLong = 50 + self.rsiSignal
        self.rsiShort = 50 - self.rsiSignal
        
        # 创建K线合成器对象
        self.bg5 = BarGenerator(self.onBar, 5, self.on5MinBar)
        self.am5 = ArrayManager()
        
        self.bg15 = BarGenerator(self.onBar, 15, self.on15MinBar)
        self.am15 = ArrayManager()
        
    #----------------------------------------------------------------------
    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推送(必须由用户继承实现)"""
        # 只需要要在一个BarGenerator中合成1分钟K线
        self.bg5.updateTick(tick)

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        # 基于15分钟判断趋势过滤,因此先更新
        self.bg15.updateBar(bar)
        
        # 基于5分钟判断
        self.bg5.updateBar(bar)
        
    #----------------------------------------------------------------------
    def on5MinBar(self, bar):
        """5分钟K线"""
        self.cancelAll()

        # 保存K线数据
        self.am5.updateBar(bar)
        if not self.am5.inited:
            return
        
        # 如果15分钟数据尚未初始化完毕,则直接返回
        if not self.maTrend:
            return

        # 计算指标数值
        self.rsiValue = self.am5.rsi(self.rsiWindow)

        # 判断是否要进行交易
        
        # 当前无仓位
        if self.pos == 0:
            if self.maTrend > 0 and self.rsiValue >= self.rsiLong:
                self.buy(bar.close+5, self.fixedSize)
                
            elif self.maTrend < 0 and self.rsiValue <= self.rsiShort:
                self.short(bar.close-5, self.fixedSize)

        # 持有多头仓位
        elif self.pos > 0:
            if self.maTrend < 0 or self.rsiValue < 50:
                self.sell(bar.close-5, abs(self.pos))
            
        # 持有空头仓位
        elif self.pos < 0:
            if self.maTrend > 0 or self.rsiValue > 50:
                self.cover(bar.close+5, abs(self.pos))

        # 发出状态更新事件
        self.putEvent()        
    
    #----------------------------------------------------------------------
    def on15MinBar(self, bar):
        """15分钟K线推送"""
        self.am15.updateBar(bar)
        
        if not self.am15.inited:
            return
        
        # 计算均线并判断趋势
        self.fastMa = self.am15.sma(self.fastWindow)
        self.slowMa = self.am15.sma(self.slowWindow)
        
        if self.fastMa > self.slowMa:
            self.maTrend = 1
        else:
            self.maTrend = -1

    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        pass

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
class BollChannelStrategy(CtaTemplate):
    """基于布林通道的交易策略"""
    className = 'BollChannelStrategy'
    author = u'用Python的交易员'

    # 策略参数
    bollWindow = 18                     # 布林通道窗口数
    bollDev = 3.4                       # 布林通道的偏差
    cciWindow = 10                      # CCI窗口数
    atrWindow = 30                      # ATR窗口数
    slMultiplier = 5.2                  # 计算止损距离的乘数
    initDays = 10                       # 初始化数据所用的天数
    fixedSize = 1                       # 每次交易的数量

    # 策略变量
    bollUp = 0                          # 布林通道上轨
    bollDown = 0                        # 布林通道下轨
    cciValue = 0                        # CCI指标数值
    atrValue = 0                        # ATR指标数值
    
    intraTradeHigh = 0                  # 持仓期内的最高点
    intraTradeLow = 0                   # 持仓期内的最低点
    longStop = 0                        # 多头止损
    shortStop = 0                       # 空头止损

    # 参数列表,保存了参数的名称
    paramList = ['name',
                 'className',
                 'author',
                 'vtSymbol',
                 'bollWindow',
                 'bollDev',
                 'cciWindow',
                 'atrWindow',
                 'slMultiplier',
                 'initDays',
                 'fixedSize']    

    # 变量列表,保存了变量的名称
    varList = ['inited',
               'trading',
               'pos',
               'bollUp',
               'bollDown',
               'cciValue',
               'atrValue',
               'intraTradeHigh',
               'intraTradeLow',
               'longStop',
               'shortStop']  
    
    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos',
                'intraTradeHigh',
                'intraTradeLow']    

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(BollChannelStrategy, self).__init__(ctaEngine, setting)
        
        self.bg = BarGenerator(self.onBar, 15, self.onXminBar)        # 创建K线合成器对象
        self.bg30 = BarGenerator(self.onBar, 30, self.on30minBar)
        self.am = ArrayManager()
        
    #----------------------------------------------------------------------
    def on30minBar(self, bar):
        """"""
        
        
    #----------------------------------------------------------------------
    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.bg.updateTick(tick)

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        self.bg.updateBar(bar)
    
    #----------------------------------------------------------------------
    def onXminBar(self, bar):
        """收到X分钟K线"""
        # 全撤之前发出的委托
        self.cancelAll()
    
        # 保存K线数据
        am = self.am
        
        am.updateBar(bar)
        
        if not am.inited:
            return
        
        # 计算指标数值
        self.bollUp, self.bollDown = am.boll(self.bollWindow, self.bollDev)
        self.cciValue = am.cci(self.cciWindow)
        self.atrValue = am.atr(self.atrWindow)
        
        # 判断是否要进行交易
    
        # 当前无仓位,发送开仓委托
        if self.pos == 0:
            self.intraTradeHigh = bar.high
            self.intraTradeLow = bar.low            
            
            if self.cciValue > 0:
                self.buy(self.bollUp, self.fixedSize, True)
                
            elif self.cciValue < 0:
                self.short(self.bollDown, self.fixedSize, True)
    
        # 持有多头仓位
        elif self.pos > 0:
            self.intraTradeHigh = max(self.intraTradeHigh, bar.high)
            self.intraTradeLow = bar.low
            self.longStop = self.intraTradeHigh - self.atrValue * self.slMultiplier
            
            self.sell(self.longStop, abs(self.pos), True)
    
        # 持有空头仓位
        elif self.pos < 0:
            self.intraTradeHigh = bar.high
            self.intraTradeLow = min(self.intraTradeLow, bar.low)
            self.shortStop = self.intraTradeLow + self.atrValue * self.slMultiplier
            
            self.cover(self.shortStop, abs(self.pos), True)
            
        # 同步数据到数据库
        self.saveSyncData()        
    
        # 发出状态更新事件
        self.putEvent()        

    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        pass

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
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']
    
    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos',
                'intraTradeHigh',
                'intraTradeLow']    

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(KkStrategy, self).__init__(ctaEngine, setting)
        
        self.bg = BarGenerator(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.bg.updateTick(tick)

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        self.bg.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.saveSyncData()    
    
        # 发出状态更新事件
        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
Exemple #12
0
class tempStrategy(CtaTemplate):
    """双指数均线策略Demo"""
    className = 'DoubleMaStrategy'
    author = u'用Python的交易员'

    # 策略参数
    fastWindow = 12  # 快速均线参数
    slowWindow = 26  # 慢速均线参数
    initDays = 0  # 初始化数据所用的天数

    # 策略变量
    fastMa0 = EMPTY_FLOAT  # 当前最新的快速EMA
    fastMa1 = EMPTY_FLOAT  # 上一根的快速EMA

    slowMa0 = EMPTY_FLOAT
    slowMa1 = EMPTY_FLOAT
    exitTime = time(hour=15, minute=0)

    # 参数列表,保存了参数的名称
    paramList = [
        'name', 'className', 'author', 'vtSymbol', 'fastWindow', 'slowWindow'
    ]

    # 变量列表,保存了变量的名称
    varList = [
        'inited', 'trading', 'pos', 'fastMa0', 'fastMa1', 'slowMa0', 'slowMa1'
    ]

    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting, tickadd=5):
        """Constructor"""
        super(tempStrategy, self).__init__(ctaEngine, setting)
        self.bg = BarGenerator(self.onBar)
        self.am = zhibiao()
        self.tickadd = tickadd

        #策略相关
        self.celve0 = zerocelve(self.tickadd)
        self.celve1 = lianmianKongcelve(self.tickadd)
        self.celve2 = lianmianduocelve(self.tickadd)
        self.celve3 = newzerocelve(self.tickadd, self.cancelAll)
        self.tickCelvezu = [
            #self.celve0,
            # self.celve1 ,
            self.celve3
        ]
        self.barCelvezu = [  #self.celve0 ,
            # ,self.celve2
            self.celve3
        ]
        self.tradingcelve = [
            #self.celve0 ,
            #,self.celve2
            self.celve3
        ]

        for ce in self.tradingcelve:
            ce.am = self.am
        #策略参数

        #断网恢复变量
        self.stopcount = None

        #交易时间和监控联网状态变量
        self.yepan = True
        self.yepanhour = 23
        self.yepanminute = 00
        self.lastbardatetime = None

        #交易变量相关
        self.tradetime = None

        #控制开仓和平仓稳定变量
        self.tradecount = 0

        # 注意策略类中的可变对象属性(通常是list和dict等),在策略初始化时需要重新创建,
        # 否则会出现多个策略实例之间数据共享的情况,有可能导致潜在的策略逻辑错误风险,
        # 策略类中的这些可变对象属性可以选择不写,全都放在__init__下面,写主要是为了阅读
        # 策略时方便(更多是个编程习惯的选择)

    #----------------------------------------------------------------------
    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略初始化')

        initData = self.loadBar(self.initDays)
        for bar in initData:
            pass


#            self.onBar(bar)
        self.am.inited = True

        self.putEvent()

    #----------------------------------------------------------------------
    def onStart(self):
        """启动策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略启动')
        self.putEvent()

    #----------------------------------------------------------------------
    def closeAllPosistion(self, price):
        self.cancelAll()
        print('--closeallpos--')
        if self.pos > 0:
            self.short(price - self.tickadd, abs(self.pos))
        elif self.pos < 0:
            self.cover(price + self.tickadd, abs(self.pos))

        # ----------------------------------------------------------------------
    def datetimePlusMinute(self, datelatime, minute):
        newdatetime = datetime.now()
        if datelatime.minute + minute < 60:
            newdatetime.minute = datelatime.minute + minute
        else:
            newdatetime.hour = datelatime.hour + 1
            newdatetime.minute = datelatime.minute + minute - 60
        return newdatetime

    # ----------------------------------------------------------------------
    def iscontinueTime(self, firstdatetime, seconddatetime):
        if (firstdatetime.hour == seconddatetime.hour and firstdatetime.minute + 1 == seconddatetime.minute) \
                or (
                firstdatetime.hour == seconddatetime.hour - 1 and firstdatetime.minute == 59 and seconddatetime.minute == 0):
            return True

    # ----------------------------------------------------------------------
    def isTradeContinueTime(self, firstdatetime, seconddatetime):
        if self.iscontinueTime(firstdatetime, seconddatetime):
            return True
        elif firstdatetime.hour == 10 and (
                firstdatetime.minute == 15 or firstdatetime.minute == 14
        ) and seconddatetime.hour == 10 and seconddatetime.minute == 30:
            return True
        elif firstdatetime.hour == 11 and (
                firstdatetime.minute == 29 or firstdatetime.minute == 30
        ) and seconddatetime.hour == 13 and seconddatetime.minute == 30:
            return True
        elif self.yepan and (seconddatetime.hour == 9 or
                             (seconddatetime.hour == 8
                              and seconddatetime.minute == 59)) and (
                                  firstdatetime.hour == self.yepanhour or
                                  (firstdatetime.hour == self.yepanhour - 1
                                   and firstdatetime.minute == 59)):
            return True
        elif (firstdatetime.hour == 15 or
              (firstdatetime.hour == 14 and firstdatetime.minute == 59)) and (
                  (seconddatetime.hour == 9 and seconddatetime.minute == 0) or
                  (seconddatetime.hour == 8 and seconddatetime.minute == 59)):
            return True
        elif ((firstdatetime.hour == 14 and firstdatetime.minute == 59)
              or firstdatetime.hour == 15) and (
                  seconddatetime.hour == 21 or
                  (seconddatetime.hour == 20 and seconddatetime.minute == 59)):
            return True
        else:
            print('dus conne', firstdatetime, seconddatetime)
            return False

    # ----------------------------------------------------------------------

    def tickcelve(self, zhibiao, price, tick):
        for celve in self.tickCelvezu:
            xinhao = celve.celveOntick(zhibiao)
            if xinhao == 100:
                print(price, 'kaicangduo', tick.datetime)
            if xinhao == 50:
                print(price, 'pingcang', tick.datetime)
            if xinhao == 200:
                print(price, 'kongcang', tick.datetime)
            if xinhao == 250:
                print(price, 'pingkongcang', tick.datetime)
            self.chulikaipingcang(xinhao, price)
            # ----------------------------------------------------------------------

    def barcelve(self, zhibiao, price):
        for celve in self.barCelvezu:
            xinhao = celve.celveOnbar(zhibiao)
            if xinhao == 100:
                print('kaicangduo,bar')
            if xinhao == 50:
                print('pingcang,bar')
            self.chulikaipingcang(xinhao, price)

    # ----------------------------------------------------------------------

    def chulikaipingcang(self, celve, price):
        # if celve == 100:
        #     self.buy(price,1)
        print('chuli', celve, self.celve3.cangwei)
        selfpos = 0
        if celve != 0 and celve is not None:
            print('nowposis', self.pos, 'celveis', celve, 'andpriceis', price,
                  self.am.datetime)
        if self.pos == 0 and celve == 100:
            if self.pos == 0:
                # self.weituopos = 1
                self.buy(price + 1, 1)
                # 如果有空头持仓,则先平空,再做多
            elif self.pos < selfpos:
                # self.weituopos = 1
                self.cover(price, 1)
                self.buy(price, 1)
        elif self.pos == 0 and celve == paiduikong:
            self.short(price, 1)
        elif self.pos == -1 and celve == paiduikongping:
            self.cover(price, 1)
        elif self.pos == 1 and celve == 50:
            if self.pos > selfpos:
                # self.weituopos = 0
                self.sell(price - 1, 1)
        elif self.pos == 0 and celve == 200:
            if self.pos == selfpos:
                # self.weituopos = -1
                self.short(price - 1, 1)
            elif self.pos > selfpos:
                self.sell(price, 1)
                self.short(price, 1)
                # self.weituopos = -1
        elif self.pos == 0 and celve == paiduiduo:
            self.buy(price, 1)
        elif self.pos > 0 and celve == paiduiduoping:
            self.sell(price, 1)
        elif self.pos == -1 and celve == 250:
            # self.weituopos += 1
            self.cover(price + 1, 1)
        # ----------------------------------------------------------------------

    def onStop(self):
        """停止策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略停止')
        self.putEvent()

    #----------------------------------------------------------------------
    def onTick(self, tick):
        """收到行情TICK推送(必须由用户继承实现)"""
        self.bg.updateTick(tick)
        self.am.updateTick(tick)
        if not self.stopcount:
            if not self.tradecount:
                self.tickcelve(self.am, tick.lastPrice, tick)
            elif tick.datetime.second > 55:
                self.tickcelve(self.am, tick.lastPrice, tick)

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        print('begin')
        #过滤掉非交易时间的bar
        ntt = False
        if self.celve3.cancelorder is None and ntt:
            print('fuzhid')
            self.celve3.cancelorder = self.cancelOrder(self)
        else:
            ntt = True
        if self.notintradingTime(bar):
            return

        #数据合成和计算相关
        am = self.am
        am.updateBar(bar)
        self.bg.updateBar(bar)

        #处理是否断网
        self.checkIfConnecting(bar)

        # 处理bar上的刚开仓
        self.handleTradeCount()

        #检查是否断网所需的上一根bar时间
        self.lastbardatetime = bar.datetime

        # if not am.inited:
        #     print('retr')
        # return
        # 计算快慢均线

        #bar策略相关
        for ce in self.tradingcelve:
            ce.nowtime = bar.datetime
        if not self.stopcount:
            self.barcelve(am, bar.close)

        # 金叉和死叉的条件是互斥
        # 所有的委托均以K线收盘价委托(这里有一个实盘中无法成交的风险,考虑添加对模拟市价单类型的支持)

        am.endBar()
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def handleTradeCount(self):
        if self.tradecount > 0:
            self.tradecount -= 1

    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        # 对于无需做细粒度委托控制的策略,可以忽略onOrder
        self.celve3.order = order.vtOrderID
        print 'order', order.price, order.direction, order.offset, order.vtOrderID
        pass

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        """收到成交推送(必须由用户继承实现)"""
        # 对于无需做细粒度委托控制的策略,可以忽略onOrder\
        if trade.direction == u'多' and trade.offset == u'开仓':
            self.tradecount = 5
        # print('kaiduo')
        if trade.direction == u'空' and trade.offset == u'开仓':
            self.tradecount = 5
        #  print('kaikong')

        if trade.direction == u'多' and trade.offset != u'开仓':
            self.cancelAll()
            print('slls', self.cancelAll() is None)
            self.celve2.cangwei = 0
        #  print('pingkong')
        if trade.direction == u'空' and trade.offset != u'开仓':
            self.cancelAll()
            self.celve2.cangwei = 0
            #self.celve0.cangwei -= trade.volume
        # print('pingduo')

        print 'trade', trade.price, trade.direction, trade.offset, trade.tradeTime

        #这里有待修正
        if trade.offset == u'开仓':
            for ce in self.tickCelvezu:
                print('set tradeprice')
                if ce.cangwei != 0:
                    ce.tradePrice = trade.price
        if trade.offset != u'开仓':
            for ce in self.tickCelvezu:
                if ce.cangwei == 0:
                    ce.tradePrice = None

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass

    def handleDisConnected(self, price):
        print('DISCONNECTED', self.lastbardatetime, self.am.datetime)
        self.closeAllPosistion(price)
        self.stopcount = 15

    def notintradingTime(self, bar):
        if bar.datetime.hour == 15 and bar.datetime.minute > 0:
            return True

    def closingTime(self, datetime):
        if datetime.hour == 14 and datetime.minute == 59:
            return True

    def checkIfConnecting(self, bar):
        if self.lastbardatetime is None:
            self.lastbardatetime = bar.datetime
        else:
            if not self.isTradeContinueTime(self.lastbardatetime,
                                            bar.datetime):
                #断网了,需要处理断网状态
                self.handleDisConnected(bar.close)
            #没有断网
            else:
                if self.stopcount > 0:
                    self.stopcount -= 1
Exemple #13
0
class TestLogOrderStrategy(CtaTemplate):
    """DualThrust交易策略"""
    className = 'TestLogOrderStrategy'
    author = u'Leon Zhao'

    # 策略参数
    flipcoil = 0
    timeinterval = 0
    hasorder = False
    countdown = 0
    # 策略变量
    barList = []                # K线对象的列表
    # 参数列表,保存了参数的名称
    paramList = ['name',
                 'className',
                 'author',
                 'vtSymbol'
                 ]    
    # 变量列表,保存了变量的名称
    varList = ['inited',
               'trading',
               'pos'
               ] 
    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos']    

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(TestLogOrderStrategy, self).__init__(ctaEngine, setting) 
        
        self.bg = BarGenerator(self.onBar)
        self.am = ArrayManager()
        self.barList = []
        self.flipcoil = 0 
        self.timeinterval =  3
        self.hasorder = False
        self.countdown = 0
        self.orderentred = False
                
    #----------------------------------------------------------------------
    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        self.writeCtaLog(u'%s策略初始化' %self.name)
    
        # 载入历史数据,并采用回放计算的方式初始化策略数值
        initData = self.loadBar(10)
        for bar in initData:
            self.onBar(bar)
        self.countdown = 0
        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推送(必须由用户继承实现)"""
        #ignore data before real open
        if (tick.datetime.hour == 8 or tick.datetime.hour ==20):
            return
        self.bg.updateTick(tick)
        
        
    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        # 撤销之前发出的尚未成交的委托(包括限价单和停止单)
        
        if (bar.datetime.hour < 14 or (bar.datetime.hour == 14 and bar.datetime.minute < 40)):            
            if self.countdown > 0:
                self.countdown = self.countdown - 1
                print(self.countdown)
                return
        self.cancelAll()
        print(self.countdown)

        self.bg.updateBar(bar)
    # 计算指标数值
        self.barList.append(bar)
        
        if len(self.barList) <= 2:
            return
        else:
            self.barList.pop(0)
        lastBar = self.barList[-2]
        

        
        self.flipcoil = random.random() 
        orderqty = [2,2,2]
        if self.pos == 0:
            if self.flipcoil > 0.5:
                self.buy(bar.close,random.choice(orderqty))
                self.countdown = self.timeinterval
            else:
                self.short(bar.close,random.choice(orderqty))
                self.countdown = self.timeinterval
        elif self.pos > 0:
            if self.flipcoil < 0.5:
                self.sell(bar.close,self.pos)
                self.countdown = self.timeinterval
                self.short(bar.close,2)
                    
                    
        else:
            if self.flipcoil > 0.5:
                self.cover(bar.close,abs(self.pos))
                self.countdown = self.timeinterval
                self.buy(bar.close,2)
        
            
            
            
        print(self.countdown)
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        pass

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        #logtext = logtext + ","+trade.date
        #logtext = logtext + "," +trade.datetime
        logtext = ""
        logtext = logtext + "," + trade.offset        
        logtext = logtext + "," + trade.direction
        logtext = logtext + "," + str(trade.volume)
        logtext = logtext + "," + str(trade.price) 
        self.writeCtaLog(logtext)
        persisttrade(self.vtSymbol,self.className ,trade)     
           
        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
class TripleMAStrategy05(CtaTemplate):
    """基于三均线的交易策略"""
    className = 'TripleMAStrategy05'
    author = 'Y.Raul'

    # 策略参数
    initDays = 10  # 初始化数据所用的天数
    windowCheck = True  #交易窗口开关
    openWindowSize = 5  #开盘观察窗口,单位分钟
    closeWindowSize = 10  #收盘平仓窗口,单位分钟
    minDiff = 1  #最小变动单位

    # 策略变量
    # 仓位设置
    stepPos = 1  # 每次交易的数量
    maxPos = 4  # 仓位上限
    addPosRatio = 3

    # 均线设置
    maWindow1 = 10
    maWindow2 = 20
    maWindow3 = 120
    maWindow4 = 5
    atrWindow = 30  # ATR窗口数

    # 分级出场设置
    trailingStart1 = 50
    trailingStart2 = 80
    exitOnTrailingStop1 = 30  # Trailing Stop 距离
    exitOnTrailingStop2 = 20  # Trailing Stop 距离
    exitOnLossStop = 5  # Loss Stop 距离

    # 价格相关变量
    intraTradeHigh = 0  # 持仓期内的最高点
    intraTradeLow = 0  # 持仓期内的最低点
    longExit = 0  # 多头止损
    shortExit = 0  # 空头止损
    longEntry = 0  # 多头开仓
    shortEntry = 0
    avgEntryPrice = 0

    # 指标相关变量
    # ma次新值
    ma10 = 0
    ma20 = 0
    ma30 = 0
    # ma最新值
    ma11 = 0
    ma21 = 0
    ma31 = 0
    atrValue = 0  # ATR指标数值

    orderList = []  # 保存委托代码的列表

    # 参数列表,保存了参数的名称
    paramList = [
        'name', 'className', 'author', 'vtSymbol', 'maWindow1', 'maWindow2',
        'maWindow3', 'maWindow4', 'initDays', 'addPos', 'stepPos', 'maxPos',
        'exitOnTrailingStop', 'exitOnLossStop'
    ]

    # 变量列表,保存了变量的名称
    varList = [
        'inited', 'trading', 'pos', 'ma10', 'ma11', 'ma20', 'ma21', 'ma30',
        'ma31', 'atrValue', 'avgEntryPrice'
    ]
    # 同步列表
    syncList = ['pos']

    # ----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(TripleMAStrategy05, self).__init__(ctaEngine, setting)
        self.entryPriceList = []
        self.bm = BarGenerator(self.onBar, 5, self.onFiveBar)
        self.am = ArrayManager(size=150)

        self.backTesting = True
        # 策略信号
        self.buySig = False
        self.shortSig = False
        self.sellSig = False
        self.coverSig = False

    # ----------------------------------------------------------------------
    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        self.writeCtaLog(u'%s策略初始化' % self.name)

        if self.backTesting:
            # 载入历史数据,并采用回放计算的方式初始化策略数值
            self.writeCtaLog(u"回测模式,载入历史数据,并采用回放计算的方式初始化策略数值")
            initData = self.loadBar(self.initDays)
            for bar in initData:
                self.onBar(bar)
        else:
            # self.trading = True
            self.inited = True
            self.writeCtaLog(u"实盘模式")
        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.curDateTime = tick.datetime
        # 计算交易时间和平仓时间
        if self.windowCheck == True:
            self.__timeWindow(tick.datetime)
        else:
            self.tradeWindow = True

        self.bm.updateTick(tick)

    # ----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        # 回测数据传送的bar.datetime,为bar的开始时间

        self.curDateTime = bar.datetime
        # 计算交易时间和平仓时间
        if self.windowCheck == True:
            self.__timeWindow(bar.datetime)
        else:
            self.tradeWindow = True

        self.bm.updateBar(bar)

        if self.pos == 0:
            self.intraTradeLow = bar.low
            self.intraTradeHigh = bar.high
        else:
            self.intraTradeHigh = max(bar.high, self.intraTradeHigh)
            self.intraTradeLow = min(bar.low, self.intraTradeLow)

        print "-----" * 10
        print "@onBar"
        print "bar.datetime: {0}; pos: {1} ".format(bar.datetime, self.pos)
        print "buySig: {0}; shortSig: {1}".format(self.buySig, self.shortSig)
        print "sellSig: {0}; coverSig: {1}".format(self.sellSig, self.coverSig)
        print "intraTradeHigh: {0}".format(self.intraTradeHigh)
        print "intraTradeLow: {0}".format(self.intraTradeLow)

        #检查交易信号
        if self.buySig:

            self.longEntry = max(self.longEntry, bar.close)
            self.buy(self.longEntry, self.stepPos, True)

            # self.LossStopPrice = round(self.longEntry * (100.0 - self.exitOnLossStop) / 100)
            self.entryPriceList.append(self.longEntry)
            self.avgEntryPrice = sum(self.entryPriceList) / len(
                self.entryPriceList)
            self.LossStopPrice = round(self.avgEntryPrice *
                                       (100.0 + self.exitOnLossStop) / 100)

            self.intraTradeHigh = max(bar.high, self.avgEntryPrice)
            self.intraTradeLow = min(bar.low, self.avgEntryPrice)

            # 记录log
            log = "\n Trading: {0}\n".format(self.trading) + \
                  "{0} Buy : longEntry: {1};\n".format(bar.datetime, self.longEntry) + \
                  " ma10:{0}; ma11:{1}; ma20:{2}; ma21:{3}; ma30:{4};ma31:{5}\n".format(self.ma10, self.ma11, self.ma20,
                                                                                        self.ma21, self.ma30,
                                                                                        self.ma31) + \
                  "ma1_ma5:{0}; ma3_ma5:{1}\n".format(self.ma1_ma5, self.ma3_ma5)
            # "LossStopPrice:{0}\n".format(self.LossStopPrice)
            self.writeCtaLog(log)

            self.buySig = False
            return

        if self.shortSig:

            self.shortEntry = min(self.shortEntry, bar.close)
            self.short(self.shortEntry, self.stepPos, True)

            # self.LossStopPrice = round(self.shortEntry * (100.0 + self.exitOnLossStop) / 100)
            self.entryPriceList.append(self.shortEntry)
            self.avgEntryPrice = sum(self.entryPriceList) / len(
                self.entryPriceList)
            self.LossStopPrice = round(self.avgEntryPrice *
                                       (100.0 + self.exitOnLossStop) / 100)

            self.intraTradeHigh = max(bar.high, self.avgEntryPrice)
            self.intraTradeLow = min(bar.low, self.avgEntryPrice)

            # 记录log
            log = "\n Trading: {0}\n".format(self.trading) + \
                  "{0} Short : shortEntry: {1};\n".format(bar.datetime, self.shortEntry) + \
                  " ma10:{0}; ma11:{1}; ma20:{2}; ma21:{3}; ma30:{4};ma31:{5}\n".format(self.ma10, self.ma11,
                                                                                        self.ma20, self.ma21,
                                                                                        self.ma30, self.ma31) + \
                  "ma1_ma5:{0}; ma3_ma5:{1}\n".format(self.ma1_ma5, self.ma3_ma5)
            # "LossStopPrice:{0}\n".format(self.LossStopPrice)
            self.writeCtaLog(log)

            self.shortSig = False
            return

        if self.sellSig:

            self.longExit = min(bar.close, self.longExit)
            self.sell(self.longExit, abs(self.pos), True)

            # 记录log
            # log = "\n{0} Sell(Trailing Stop) : longExit: {1};\n".format(bar.datetime, self.longExit) + \
            #       "intraTradeHigh:{0}; atrValue:{1}; \n".format(self.intraTradeHigh, self.atrValue) + \
            #       "LongExit:{0}\n".format(self.longExit)
            # self.writeCtaLog(log)

            self.entryPriceList = []
            self.sellSig = False
            return

        if self.coverSig:

            self.shortExit = max(bar.close, self.shortExit)
            self.cover(self.shortExit, abs(self.pos), True)

            # 记录log
            # log = "\n{0} Cover(Trailing Stop) : bar.close: {1};\n".format(bar.datetime, bar.close) + \
            #       "intraTradeLow:{0}; atrValue:{1};\n".format(self.intraTradeLow, self.atrValue) + \
            #       "shortExit:{0}\n".format(self.shortExit)
            # self.writeCtaLog(log)

            self.entryPriceList = []
            self.coverSig = False
            return

    # ----------------------------------------------------------------------
    def onFiveBar(self, bar):
        """收到5分钟K线"""

        print "-----" * 10
        print "@onFiveBar"
        print "bar.datetime: ", bar.datetime
        print "ma11: %f, ma10 %f" % (self.ma11, self.ma10)
        print "ma21: %f, ma20 %f" % (self.ma21, self.ma20)
        print "ma31: %f, ma30 %f" % (self.ma31, self.ma30)

        # 保存K线数据
        self.am.updateBar(bar)
        print "bar count: ", self.am.count
        print "am.inited: ", self.am.inited
        if not self.am.inited:
            return

        # 撤销之前发出的尚未成交的委托(包括限价单和停止单)
        # 等于策略信号的生存期只有5分钟
        self.cancelAll()

        import talib

        # 计算指标数值
        ma3Array = self.am.sma(self.maWindow3, True)
        self.ma30 = round(ma3Array[-2])
        self.ma31 = round(ma3Array[-1])
        self.ma3_ma5 = round(talib.SMA(ma3Array, self.maWindow4)[-1])

        ma1Array = self.am.sma(self.maWindow1, True)
        self.ma10 = round(ma1Array[-2])
        self.ma11 = round(ma1Array[-1])
        self.ma1_ma5 = talib.SMA(ma1Array, self.maWindow4)[-1]

        ma2Array = self.am.sma(self.maWindow2, True)
        self.ma20 = round(ma2Array[-2])
        self.ma21 = round(ma2Array[-1])

        self.atrValue = round(self.am.atr(self.atrWindow))

        # 当前为空仓
        if self.pos == 0:

            self.intraTradeHigh = bar.high
            self.intraTradeLow = bar.low
            self.avgEntryPrice = 0
            self.entryPriceList = []

            if self.tradeWindow:
                # 开多, bar.close > MA120,MA10 > MA120,MA10 上穿MA20,MA10、MA120向上
                if bar.close > self.ma31 and self.ma11 > self.ma31 \
                        and self.ma10 < self.ma20 and self.ma11 > self.ma21\
                        and self.ma31 > self.ma3_ma5 and self.ma11 > self.ma1_ma5:

                    self.buySig = True
                    self.longEntry = bar.close

                # 开空, bar.close < MA120,MA10 < MA120,MA10 下穿MA20, MA10,MA120向下
                elif bar.close < self.ma31 and self.ma11 < self.ma31 \
                        and self.ma10 > self.ma20 and self.ma11 < self.ma21\
                        and self.ma31 < self.ma3_ma5 and self.ma11 < self.ma1_ma5:

                    self.shortSig = True
                    self.shortEntry = bar.close
        if self.pos != 0:
            self.intraTradeHigh = max(self.intraTradeHigh, bar.high)
            self.intraTradeLow = min(self.intraTradeLow, bar.low)

            if self.tradeWindow:
                if self.pos > 0:
                    # 二级止赢判断 盈利80跳
                    if self.intraTradeHigh >= self.avgEntryPrice + self.trailingStart2 * self.minDiff:
                        # 回撤20跳
                        if (bar.close <= self.intraTradeHigh -
                                self.exitOnTrailingStop2 * self.minDiff):
                            self.longExit = self.intraTradeHigh - self.exitOnTrailingStop2 * self.minDiff
                            self.sellSig = True
                            if bar.close < self.longExit:
                                self.longExit = bar.close
                            # 记录log
                            log = "\n{0} Sell(Trailing Stop2)\n".format(bar.datetime) + \
                                'bar.close: {0}; bar.low: {1}; longExit: {2}'.format(bar.close,bar.low, self.longExit)+ \
                                'intraTradeHigh: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeHigh,self.avgEntryPrice, bar.open)
                            self.writeCtaLog(log)
                    # 一级止赢判断,盈利50跳
                    elif self.intraTradeHigh >= self.avgEntryPrice + self.trailingStart1 * self.minDiff:
                        # 回撤20跳
                        if (bar.close <= self.intraTradeHigh -
                                self.exitOnTrailingStop1 * self.minDiff):
                            self.longExit = self.intraTradeHigh - self.exitOnTrailingStop1 * self.minDiff
                            self.sellSig = True
                            if bar.close < self.longExit:
                                self.longExit = bar.close
                            # 记录log
                            log = "\n{0} Sell(Trailing Stop1)\n".format(bar.datetime) + \
                                  'bar.close: {0}; bar.low: {1}; longExit: {2}'.format(bar.close, bar.low,
                                                                                       self.longExit)+ \
                                  'intraTradeHigh: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeHigh,self.avgEntryPrice, bar.open)
                            self.writeCtaLog(log)
                    # 止损,回撤20跳
                    elif (bar.close <= self.avgEntryPrice -
                          self.exitOnLossStop * self.minDiff):
                        self.longExit = self.avgEntryPrice - self.exitOnLossStop * self.minDiff
                        self.sellSig = True
                        if bar.close < self.longExit:
                            self.longExit = bar.close
                        # 记录log
                        log = "\n{0} Sell(Loss Stop)\n".format(bar.datetime) + \
                              'bar.close: {0}; bar.low: {1}; longExit: {2}'.format(bar.close, bar.low,
                                                                                   self.longExit)+ \
                              'intraTradeHigh: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeHigh,
                                                                                              self.avgEntryPrice,
                                                                                              bar.open)
                        self.writeCtaLog(log)

            elif self.pos < 0:
                # 二级止赢判断 盈利80跳
                if self.intraTradeLow <= self.avgEntryPrice - self.trailingStart2 * self.minDiff:
                    # 回撤20跳
                    if (bar.close >= self.intraTradeLow +
                            self.exitOnTrailingStop2 * self.minDiff):
                        self.shortExit = self.intraTradeLow + self.exitOnTrailingStop2 * self.minDiff
                        self.coverSig = True
                        if bar.close > self.shortExit:
                            self.shortExit = bar.close
                        # 记录log
                        log = "\n{0} Cover(Trailing Stop1)\n".format(bar.datetime) + \
                              'bar.close: {0}; bar.low: {1}; shortExit: {2}'.format(bar.close, bar.low,
                                                                                   self.shortExit)+ \
                              'intraTradeLow: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeLow,
                                                                                              self.avgEntryPrice,
                                                                                              bar.open)
                        self.writeCtaLog(log)
                # 一级止赢判断,盈利50跳
                elif self.intraTradeLow <= self.avgEntryPrice - self.trailingStart1 * self.minDiff:
                    # 回撤20跳
                    if (bar.close >= self.intraTradeLow +
                            self.exitOnTrailingStop1 * self.minDiff):
                        self.shortExit = self.intraTradeLow + self.exitOnTrailingStop1 * self.minDiff
                        self.coverSig = True
                        if bar.close > self.shortExit:
                            self.shortExit = bar.close
                        # 记录log
                        log = "\n{0} Cover(Trailing Stop2)\n".format(bar.datetime) + \
                              'bar.close: {0}; bar.low: {1}; shortExit: {2}'.format(bar.close, bar.low,
                                                                                   self.shortExit)+ \
                              'intraTradeLow: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeLow,
                                                                                             self.avgEntryPrice,
                                                                                             bar.open)
                        self.writeCtaLog(log)
                # 止损,回撤20跳
                elif (bar.close >=
                      self.avgEntryPrice + self.exitOnLossStop * self.minDiff):
                    self.shortExit = self.avgEntryPrice + self.exitOnLossStop * self.minDiff
                    self.coverSig = True
                    if bar.close > self.shortExit:
                        self.shortExit = bar.close
                    # 记录log
                    log = "\n{0} Cover(Loss Stop)\n".format(bar.datetime) + \
                          'bar.close: {0}; bar.low: {1}; shortExit: {2}'.format(bar.close, bar.low,
                                                                                self.shortExit)+ \
                          'intraTradeLow: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeLow,
                                                                                         self.avgEntryPrice,
                                                                                         bar.open)
                    self.writeCtaLog(log)

                # # 加仓
                # if self.addPos and (self.maxPos - abs(self.pos) > 0):
                #     # print self.pos, (self.maxPos - abs(self.pos) )
                #     # print self.entryPriceList
                #
                #     lastEntryPrice = self.entryPriceList[-1]
                #     # 固定百分比加仓
                #     addPosOnPips= round(lastEntryPrice* self.addPosRatio/100)
                #
                #     self.writeCtaLog(u'\n 加仓判断:{0},当前仓位:{1}'.format(bar.datetime, self.pos))
                #     # 加多仓
                #     if self.pos > 0 \
                #             and bar.close >= (lastEntryPrice + addPosOnPips* self.minDiff):
                #
                #         self.buySig = True
                #         self.longEntry = bar.close
                #
                #         # 记录log
                #         self.writeCtaLog(u'\n {0},加仓多单{1}手,价格:{2}'.format(bar.datetime, self.stepPos, self.longEntry))
                #
                #         return
                #
                #     # 加空仓
                #     if self.pos < 0 \
                #             and bar.close <= (lastEntryPrice + addPosOnPips*self.minDiff):
                #
                #         self.shortSig = True
                #         self.shortEntry = bar.close
                #         # 记录log
                #         self.writeCtaLog(u'{0},加仓空单{1}手,价格:{2}'.format(bar.datetime, self.stepPos, self.shortEntry))

        # 执行收盘前平仓检查
        # self.__dailyCloseCheck(bar)
        # 发出状态更新事件
        self.putEvent()

        # ----------------------------------------------------------------------

    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        log = u'\n OnOrder()更新,orderID:{0},{1},totalVol:{2},tradedVol:{3},offset:{4},price:{5},direction:{6},status:{7},orderTime: {7}'\
                         .format(order.orderID, order.vtSymbol, order.totalVolume,order.tradedVolume,
                                 order.offset, order.price, order.direction, order.status, order.orderTime)
        # self.writeCtaLog(log)
        self.putEvent()

    # ----------------------------------------------------------------------
    def onTrade(self, trade):

        log = u'\n OnTrade()更新,orderID:{0},{1},Vol:{2},price:{3},direction:{4},tradeTime:{5}' \
            .format(trade.orderID, trade.vtSymbol, trade.volume,trade.price, trade.direction,trade.tradeTime)
        # self.writeCtaLog(log)
        # 发出状态更新事件
        self.putEvent()

    # ----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        log = u'\n OnStopOrder()停止单更新,stopOrderID:{0},Vol:{1},price:{2},direction:{3},status:{4}' \
            .format(so.stopOrderID, so.volume,so.price, so.direction,so.status)
        # self.writeCtaLog(log)

    def __timeWindow(self, dt):
        """交易与平仓窗口"""

        # 螺纹钢交易窗口 避开早盘和夜盘的前5分钟,防止隔夜跳空。
        # 日内平仓窗口
        self.closeWindow = False
        # 交易窗口
        self.tradeWindow = False
        # 开盘窗口
        self.openWindow = False

        # 开市期头5分钟波动较大
        if (dt.hour == 9 or dt.hour == 21) and dt.minute < self.openWindowSize:
            self.openWindow = False
            return

        # 日盘
        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 < 60 - self.closeWindowSize:
                self.tradeWindow = True
                return
            else:
                self.closeWindow = True
                return

        # 夜盘

        if dt.hour == 21 and dt.minute >= 0:
            self.tradeWindow = True
            return

        if dt.hour == 22 and dt.minute < 60 - self.closeWindowSize:
            self.tradeWindow = True
            return
        else:
            self.closeWindow = True
            return

    def __dailyCloseCheck(self, bar):
        """每天收盘前检查,如果是亏损单,则平掉"""

        if self.pos == 0:
            return False

        if not self.closeWindow:
            return False

        # 撤销未成交的订单
        self.cancelAll()
        log = u'{0},收盘前{1}分钟,撤单及平仓'.format(bar.datetime, self.closeWindowSize)
        self.writeCtaLog(log)
        self.avgEntryPrice = (sum(self.entryPriceList)) / len(
            self.entryPriceList)
        # 记录log
        log = "\n{0} __dailyCloseCheck : bar.close: {1};\n".format(bar.datetime, bar.close) + \
              "avgPrice:{0}\n".format(self.avgEntryPrice)+\
            "pos:{0}\n".format(self.pos)

        self.writeCtaLog(log)

        # 强制平仓
        if self.pos > 0 and bar.close < self.avgEntryPrice:
            self.writeCtaLog(u'强制日内平亏损多仓')

            # 降低两个滑点
            self.sell(bar.close - 2 * self.minDiff, abs(self.pos), True)
            # 记录log
            log = "\n{0} Sell(Force) : bar.close: {1};\n".format(bar.datetime, bar.close) + \
                  "entryPrice:{0}\n".format(bar.close - 2 * self.minDiff)
            self.writeCtaLog(log)

            return True

        if self.pos < 0 and bar.close > self.avgEntryPrice:
            self.writeCtaLog(u'强制日内平亏损空仓')

            self.cover(bar.close + 2 * self.minDiff, abs(self.pos), True)
            # 记录log
            log = "\n{0} Cover(Force) : bar.close: {1};\n".format(bar.datetime, bar.close) + \
                  "forcePrice:{0}\n".format(bar.close - 2 * self.minDiff)
            self.writeCtaLog(log)
            return True

        return True
Exemple #15
0
class GridStrategy(CtaTemplate):
    className = 'GridStrategy'
    author = u'BillyZhang'

    # 策略参数
    historyBars = 200  # 历史数据大小,用来确定网格基准线
    initDays = 20  # 初始化数据所用的天数,随着历史数据大小要改变
    gridlines = 10  # 网格线数量,单边数量
    ordersize = 10  # 最大持仓数量
    order = 1  # 每次下单手数
    barMins = 30  #bar的时间
    frozenBars = 1  #平仓后,frozenBars个bar不再开反向单
    atrWindow = 30  # ATR窗口数
    slMultiplier = 5.0  # 计算止损距离的乘数

    # 基本变量
    upline = 0  #当前上线
    bottomline = 0  #当前下线
    frozen = 0  #当前是否冻结开反向单
    intraTradeHigh = 0
    intraTradeLow = 0
    atrValue = 0

    # 参数列表,保存了参数的名称
    paramList = [
        'name', 'className', 'author', 'vtSymbol', 'historyBars', 'initDays',
        'gridlines', 'barMins', 'order', 'ordersize', 'atrWindow',
        'slMultiplier'
    ]
    # 变量列表,保存了变量的名称
    varList = [
        'inited', 'trading', 'pos', 'frozen', 'upline', 'bottomline'
        'atrValue'
    ]
    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos', 'frozen']

    # ----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(GridStrategy, self).__init__(ctaEngine, setting)
        self.bg = BarGenerator(self.onBar, self.barMins,
                               self.onXminBar)  # 创建K线合成器对象
        self.am = ArrayManager(self.historyBars + 50)

    # ----------------------------------------------------------------------
    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 onXminBar(self, bar):
        """收到X分钟K线"""
        # 全撤之前发出的委托
        self.cancelAll()
        # 保存K线数据
        am = self.am
        am.updateBar(bar)
        if not am.inited:
            return
        # 这里采用了均量交易法,就是每笔。
        # 空仓时候,每次突破上线是开多单,突破下线是开空单;
        # 有多单时候,突破上线加多单,突破下线情况清空所有多单,
        # 有空单时候,突破下线加空单,突破上线清空所有空单,
        # 为防止在一个线上下波动,造成重复开平仓情况,如果突破平仓,比如平多单,后面n个bar不能再开多单,只能开空单;反之平空单后,
        # 后面n个bar只能开多单。
        # 计算网格,返回通道队列, 再算出当前点位所在通道,0为最下通道,2*self.gridlines - 1为最上通道
        baseline = self.am.sma(self.historyBars)
        # 过去300的标准差,按照顶一个gridlines取整做出一个队列
        intervallist = baseline + np.array([
            n * 1.00 / self.gridlines
            for n in range(-1 * self.gridlines, self.gridlines + 1)
        ]) * self.am.std(self.historyBars)

        griploc = pd.cut([bar.close],
                         intervallist,
                         labels=[nx for nx in range(0, 2 * self.gridlines)])[0]
        # 如果返回为nan,说明现在bar.close在标准差范围以外,如果没有仓位,先不处理;如果有,按照ATR波动移动止盈
        if isnan(griploc):
            # 持有多头仓位
            if self.pos > 0:
                self.intraTradeHigh = max(self.intraTradeHigh, bar.high)
                self.intraTradeLow = bar.low
                self.longStop = self.intraTradeHigh - self.atrValue * self.slMultiplier
                self.sell(self.longStop, abs(self.pos), True)
            # 持有空头仓位
            elif self.pos < 0:
                self.intraTradeHigh = bar.high
                self.intraTradeLow = min(self.intraTradeLow, bar.low)
                self.shortStop = self.intraTradeLow + self.atrValue * self.slMultiplier
                self.cover(self.shortStop, abs(self.pos), True)
            return
        #返回上下线:
        self.upline = intervallist[griploc + 1]
        self.bottomline = intervallist[griploc]

        # 空仓时候,每次突破上线是开多单,突破下线是开空单;
        # 如果此时在最下一个通道,此时只挂往上的多单, 如果在最上面通道,此时只挂往下空单;如果在中间的,则同时开上下单
        if self.pos == 0:
            if griploc == 0:
                self.buy(self.upline, self.order, True)
            elif griploc == 2 * self.gridlines - 1:
                self.short(self.bottomline, self.order, True)
            else:
                #此时如果frozen 为0, 直接开上下单:
                if self.frozen == 0:
                    self.buy(self.upline, self.order, True)
                    self.short(self.bottomline, self.order, True)
                #此时如果大于0,只能开空单,如果小于0,只能开多单
                elif self.frozen > 0:
                    self.frozen = self.frozen - 1
                    self.short(self.bottomline, self.order, True)
                elif self.frozen < 0:
                    self.frozen = self.frozen + 1
                    self.buy(self.upline, self.order, True)
        #如果持有多仓时候,如果在中间通道,同时开上下单;如果最高点位不再开单,突破最大标准差高点,
        elif self.pos > 0:
            # 在最下通道不可能有多单,只用考量在中间段,pos 小于ordersize可以增多仓,否则只能向下平仓;和最高段情况,最高段设置往下平仓,
            if griploc == 2 * self.gridlines - 1:
                self.intraTradeHigh = bar.high
                self.sell(self.bottomline, abs(self.pos), True)
            else:
                if abs(self.pos) < self.ordersize:
                    self.buy(self.upline, self.order, True)
                    self.sell(self.bottomline, abs(self.pos), True)
                else:
                    self.sell(self.bottomline, abs(self.pos), True)
        elif self.pos < 0:
            # 最上通道通道不可能有空单,只用考虑中间段,和最低档情况
            if griploc == 0:
                self.intraTradeLow = bar.low
                self.cover(self.upline, abs(self.pos), True)
            else:
                if abs(self.pos) < self.ordersize:
                    self.cover(self.upline, abs(self.pos), True)
                    self.sell(self.bottomline, self.order, True)
                else:
                    self.cover(self.upline, abs(self.pos), True)

    # ----------------------------------------------------------------------
    def onTick(self, tick):
        """收到行情TICK推送(必须由用户继承实现)"""
        self.bg.updateTick(tick)

    # ----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        self.bg.updateBar(bar)

    # ----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托推送"""
        pass

    # ----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        # 如果收到成交,清空所有挂单
        self.cancelAll()
        # 如果交易多头方向,且现在仓位为0,则应该是空头平仓,不再开空单
        if trade.direction == DIRECTION_LONG and self.pos == 0:
            self.frozen = -1 * self.frozen
        # 如果交易空头方向,且现在仓位为0,则应该是多平仓,不再开多单
        elif trade.direction == DIRECTION_SHORT and self.pos == 0:
            self.frozen = self.frozen

        self.putEvent()

    # ----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Exemple #16
0
class BollChannelStrategy01(CtaTemplate):
    """基于布林通道的交易策略"""
    className = 'BollChannelStrategy01'
    author = 'Y.Raul'

    # 策略参数
    bollWindow = 18  # 布林通道窗口数
    bollDev = 5  # 布林通道的偏差
    cciWindow = 10  # CCI窗口数
    atrWindow = 30  # ATR窗口数
    slMultiplier = 5  # 计算止损距离的乘数
    initDays = 10  # 初始化数据所用的天数
    fixedSize = 1  # 每次交易的数量

    # 策略变量
    bollUp = 0  # 布林通道上轨
    bollDown = 0  # 布林通道下轨
    cciValue = 0  # CCI指标数值
    atrValue = 0  # ATR指标数值
    filterTime = True  #是否过滤9点开盘后头五分钟,15点收盘前五分钟

    intraTradeHigh = 0  # 持仓期内的最高点
    intraTradeLow = 0  # 持仓期内的最低点
    longStop = 0  # 多头止损
    shortStop = 0  # 空头止损
    avgEntryPrice = 0  #平均入场价
    avgExitPrice = 0  #平均出场价
    buySig = False
    shortSig = False
    exitOnLossStop = 2
    miniDiff = 1

    # 参数列表,保存了参数的名称
    paramList = [
        'name', 'className', 'author', 'vtSymbol', 'bollWindow', 'bollDev',
        'cciWindow', 'atrWindow', 'slMultiplier', 'initDays', 'fixedSize'
    ]

    # 变量列表,保存了变量的名称
    varList = [
        'inited', 'trading', 'pos', 'bollUp', 'bollDown', 'cciValue',
        'atrValue', 'intraTradeHigh', 'intraTradeLow', 'longStop', 'shortStop'
    ]

    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos', 'intraTradeHigh', 'intraTradeLow']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(BollChannelStrategy01, self).__init__(ctaEngine, setting)

        self.bm = BarGenerator(self.onBar, 15, self.on5minBar)  # 创建K线合成器对象
        self.am = ArrayManager()
        self.entryPriceList = []
        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):

        self.bm.updateBar(bar)
        if not self.trading:
            # 记录log
            log = "-----" * 10 + "\n@onBar\n" + \
                    "trading: {0}\n".format(self.trading)+\
                  "bar.datetime: {0}; pos: {1} \n".format(bar.datetime, self.pos) + \
                  "buySig: {0}; shortSig: {1}\n".format(self.buySig, self.shortSig)
            self.writeCtaLog(log)
            print log
            self.buySig = False
            self.shortSig = False
            return

        # 检查开仓信号
        if self.buySig:
            res = self.buy(self.bollUp, self.fixedSize)
            self.orderList.extend(res)

            # 记录log
            log = "-----" * 10 + "\n@onBar\n" + \
                  "bar.datetime: {0}; pos: {1} \n".format(bar.datetime, self.pos) + \
                  "buySig: {0}; shortSig: {1}\n".format(self.buySig, self.shortSig)
            self.writeCtaLog(log)

            log = "\n Trading: {0}\n".format(self.trading) + \
                  "{0} Buy : bar.close: {1};\n".format(bar.datetime, bar.close) + \
                  " entryUp:{0}; cci:{1};\n".format(self.bollUp, self.cciValue)
            self.writeCtaLog(log)
            self.buySig = False
            print log

        if self.shortSig:
            res = self.short(self.bollDown, self.fixedSize)
            self.orderList.extend(res)

            # 记录log
            log = "-----" * 10 + "\n@onBar\n" + \
                  "bar.datetime: {0}; pos: {1} \n".format(bar.datetime, self.pos) + \
                  "buySig: {0}; shortSig: {1}\n".format(self.buySig, self.shortSig)
            self.writeCtaLog(log)

            log = "\n Trading: {0}\n".format(self.trading) + \
                  "{0} Short : bar.close: {1};\n".format(bar.datetime, bar.close) + \
                  " entryDown:{0}; cci:{1};\n".format(self.bollDown, self.cciValue)
            self.writeCtaLog(log)
            self.shortSig = False
            print log

        self.putEvent()

    #----------------------------------------------------------------------
    def on5minBar(self, bar):
        """收到X分钟K线"""
        # 全撤之前发出的委托
        self.cancelAll()

        # 保存K线数据
        am = self.am

        am.updateBar(bar)

        if not am.inited:
            return

        # 计算指标数值
        self.bollUp, self.bollDown = am.boll(self.bollWindow, self.bollDev)
        self.cciValue = am.cci(self.cciWindow)

        atrArray = am.atr(self.atrWindow, array=True)
        self.atrValue = atrArray[-1]
        self.atrMa = atrArray[-self.atrWindow:].mean()
        # 判断是否要进行交易

        # 当前无仓位,发送开仓委托,限价单
        if self.pos == 0:
            self.intraTradeHigh = bar.high
            self.intraTradeLow = bar.low
            self.entryPriceList = []
            self.orderList = []
            self.avgEntryPrice = []
            import datetime
            timeWindow = True
            if self.filterTime:
                timeWindow = bar.datetime.time() > datetime.time(
                    9) and bar.datetime.time() < datetime.time(14, 55)

            if timeWindow:
                if self.cciValue > 0 and self.atrValue > self.atrMa:
                    # if self.cciValue > 0 :
                    self.buySig = True

                elif self.cciValue < 0 and self.atrValue < self.atrMa:
                    # elif self.cciValue < 0:
                    self.shortSig = True

            # 记录log
            log = "-----" * 10 + "\n@on5minBar\n" + \
                "timeWidow: {0}\n".format(timeWindow) +\
                "bar.datetime: {0}; pos: {1} ; close: {2}\n".format(bar.datetime, self.pos, bar.close) + \
                "buySig: {0}; shortSig: {1}\n".format(self.buySig, self.shortSig) + \
                "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \
                "intraTradeLow: {0}\n".format(self.intraTradeLow)
            self.writeCtaLog(log)
            print log

        # 当前有仓位,以本地停止单止损
        # 持有多头仓位
        elif self.pos > 0:
            self.intraTradeHigh = max(self.intraTradeHigh, bar.high)
            self.intraTradeLow = bar.low
            self.longStop = self.intraTradeHigh - self.atrValue * self.slMultiplier

            # if bar.close < self.stopExit:
            # 固定止损
            # self.sell(bar.close, abs(self.pos), True)
            # else:
            #     跟随止损
            # self.sell(self.longStop, abs(self.pos), True)
            self.sell(self.longStop, abs(self.pos), True)

            # 记录log
            log = "-----" * 10 + "\n@on5minBar\n" + \
                  "bar.datetime: {0}; pos: {1} ; close: {2}\n".format(bar.datetime, self.pos, bar.close) + \
                  "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \
                  "intraTradeLow: {0}\n".format(self.intraTradeLow)
            "avgEntryPrice: {0}\n".format(self.avgEntryPrice) + \
            "longStop: {0}\n".format(self.longStop) + \
            "stopExit:{0}\n".format(self.stopExit)

            self.writeCtaLog(log)
            print log

        # 持有空头仓位
        elif self.pos < 0:
            self.intraTradeHigh = bar.high
            self.intraTradeLow = min(self.intraTradeLow, bar.low)
            self.shortStop = self.intraTradeLow + self.atrValue * self.slMultiplier

            # if bar.close > self.stopExit:
            #     固定止损
            # self.cover(bar.close, abs(self.pos), True)
            # else:
            # 跟随止损
            # self.cover(self.shortStop, abs(self.pos), True)
            self.cover(self.shortStop, abs(self.pos), True)

            # 记录log
            log = "-----" * 10 + "\n@on5minBar\n" + \
                  "bar.datetime: {0}; pos: {1} ; close: {2}\n".format(bar.datetime, self.pos, bar.close) + \
                  "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \
                  "intraTradeLow: {0}\n".format(self.intraTradeLow) +\
                  "avgEntryPrice: {0}\n".format(self.avgEntryPrice) + \
                  "shortStop: {0}\n".format(self.longStop) + \
                  "stopExit:{0}\n".format(self.stopExit)
            self.writeCtaLog(log)
            print log
            # 同步数据到数据库
        self.saveSyncData()
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onOrder(self, order):
        '''
        处理order更新
        :param order:
        :return:
        '''
        # 记录log
        log = "-----" * 10 + "\n@onOrder\n" + \
              "orderTime: {0}; pos: {1} \n".format(order.orderTime, order.totalVolume) + \
              u"status {0}; vtOrderID: {1}\n".format(order.status, order.vtOrderID)+ \
              u"direction:{0}\n".format(order.direction)
        self.writeCtaLog(log)
        print log

        # 对于开仓,记录相关价格
        if order.direction == DIRECTION_LONG and order.offset == OFFSET_OPEN:
            if order.totalVolume == order.tradedVolume:
                # 更新入场价列表,更新平均入场价
                self.entryPriceList.append(order.price)
                self.avgEntryPrice = sum(self.entryPriceList) / len(
                    self.entryPriceList)
                self.stopExit = round(self.avgEntryPrice *
                                      (100 - self.exitOnLossStop) /
                                      100)  # 固定止损价

        elif order.direction == DIRECTION_SHORT and order.offset == OFFSET_OPEN:
            # 更新入场价列表,更新平均入场价
            if order.totalVolume == order.tradedVolume:
                # 更新入场价列表,更新平均入场价
                self.entryPriceList.append(order.price)
                self.avgEntryPrice = sum(self.entryPriceList) / len(
                    self.entryPriceList)
                self.stopExit = round(self.avgEntryPrice *
                                      (1 + self.exitOnLossStop) / 100)  # 固定止损价

        self.putEvent()

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
class BollingerBotStrategy01(CtaTemplate):
    """基于布林通道的交易策略"""
    className = 'BollingerBotStrategy01'
    author = 'Y.Raul'

    # 策略参数
    bollWindow = 28  # 通道窗口数
    entryDevUp = 4  # 开仓偏差
    entryDevDown = 3.2
    # exitDev = 1.2           # 平仓偏差
    # trailingPrcnt = 0.4
    # 移动止损百分比
    maWindow = 10  # 过滤用均线窗口
    initDays = 10  # 初始化数据所用的天数
    fixedSize = 1  # 每次交易的数量

    # 策略变量
    bollMid = 0  # 布林带中轨
    bollStd = 0  # 布林带宽度
    entryUp = 0  # 开仓上轨
    # exitUp = 0                          # 平仓上轨
    entryDown = 0  #开仓下轨
    # exitDown = 0                        #平仓下轨

    dispacedLen = 0  #均线平移长度
    maFilter = 0  # 均线过滤
    maFilter1 = 0  # 上一期均线

    # 分级出场设置
    trailingStart1 = 20
    trailingStart2 = 30
    exitOnTrailingStop1 = 5  # Trailing Stop 距离
    exitOnTrailingStop2 = 10  # Trailing Stop 距离
    exitOnLossStop = 20  # Loss Stop 距离

    # 价格相关变量
    intraTradeHigh = 0  # 持仓期内的最高点
    intraTradeLow = 0  # 持仓期内的最低点
    avgEntryPrice = 0
    minDiff = 1
    trailingExit = 0  #
    stopExit = 0  # 空头止损
    # longEntry = 0  # 多头开仓
    # shortEntry = 0

    # 信号相关变量
    buySig = False
    shortSig = False
    sellSig = False
    coverSig = False
    # entrusted = False #是否已有委托

    orderList = []  # 保存委托代码的列表

    # 参数列表,保存了参数的名称
    paramList = [
        'name', 'className', 'author', 'vtSymbol', 'bollWindow', 'entryDevUp',
        'entryDevDown', 'trailingStart1', 'trailingStart2',
        'exitOnTrailingStop1', 'exitOnTrailingStop2', 'maWindow', 'initDays',
        'fixedSize'
    ]

    # 变量列表,保存了变量的名称
    varList = [
        'inited', 'trading', 'pos', 'buySig', 'shortSig', 'sellSig',
        'coverSig', 'entryUp', 'entryDown', 'trailingExit', 'stopExit',
        'intraTradeHigh', 'intraTradeLow', 'avgEntryPrice'
    ]

    # 同步列表
    syncList = ['pos', 'intraTradeHigh']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(BollingerBotStrategy01, self).__init__(ctaEngine, setting)

        self.bm = BarGenerator(self.onBar, 5, self.onFiveBar)
        self.am = ArrayManager(30)
        self.orderList = []
        self.entryPriceList = []

    #----------------------------------------------------------------------
    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推送(必须由用户继承实现)"""
        # 观察周期1 Min,根据信号进行交易
        # 回测数据传送的bar.datetime,为bar的开始时间
        self.bm.updateBar(bar)
        if not self.trading:
            return

        self.date = bar.date
        self.time = bar.time
        # 检查交易信号
        if self.buySig:
            res = self.buy(bar.close, self.fixedSize, True)
            self.orderList.extend([x.split('.')[1] for x in res])
            # self.orderList.extend(res.split('.')[1])

            # self.entryPriceList.append(self.longEntry)
            # self.avgEntryPrice = sum(self.entryPriceList) / len(self.entryPriceList)
            # self.LossStopPrice = round(self.avgEntryPrice * (100.0 + self.exitOnLossStop) / 100)

            # self.intraTradeHigh = max(bar.high, self.avgEntryPrice)
            # self.intraTradeLow = min(bar.low, self.avgEntryPrice)
            log = "-----" * 10 + "\n@onBar\n" + \
                  "bar.datetime: {0}; pos: {1} \n".format(bar.datetime, self.pos) + \
                  "buySig: {0}; shortSig: {1}\n".format(self.buySig, self.shortSig) + \
                  "sellSig: {0}; coverSig: {1}\n".format(self.sellSig, self.coverSig) + \
                  "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \
                  "intraTradeLow: {0}\n".format(self.intraTradeLow)
            self.writeCtaLog(log)
            # 记录log
            log = "\n Trading: {0}\n".format(self.trading) + \
                  "{0} Buy : longEntry: {1};\n".format(bar.datetime, bar.close) + \
                  " entryUp:{0}; maFilter:{1}; maFilter1:{2}; \n".format(self.entryUp, self.maFilter, self.maFilter1)
            self.writeCtaLog(log)
            self.buySig = False
            # return

        if self.shortSig:
            self.res = self.short(bar.close, self.fixedSize, True)
            self.orderList.extend([x.split('.')[1] for x in self.res])
            # self.orderList.extend(res.split('.')[1])

            # self.LossStopPrice = round(self.shortEntry * (100.0 + self.exitOnLossStop) / 100)
            # self.entryPriceList.append(self.shortEntry)
            # self.avgEntryPrice = sum(self.entryPriceList) / len(self.entryPriceList)
            # self.LossStopPrice = round(self.avgEntryPrice * (100.0 + self.exitOnLossStop) / 100)
            #
            # self.intraTradeHigh = max(bar.high, self.avgEntryPrice)
            # self.intraTradeLow = min(bar.low, self.avgEntryPrice)
            log = "-----" * 10 + "\n@onBar\n" + \
                  "bar.datetime: {0}; pos: {1} \n".format(bar.datetime, self.pos) + \
                  "buySig: {0}; shortSig: {1}\n".format(self.buySig, self.shortSig) + \
                  "sellSig: {0}; coverSig: {1}\n".format(self.sellSig, self.coverSig) + \
                  "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \
                  "intraTradeLow: {0}\n".format(self.intraTradeLow)
            self.writeCtaLog(log)
            # 记录log
            log = "\n Trading: {0}\n".format(self.trading) + \
                  "{0} Short : shortEntry: {1};\n".format(bar.datetime, bar.close) + \
                  " entryDown:{0}; maFilter:{1}; maFilter1:{2}; \n".format(self.entryDown, self.maFilter, self.maFilter1)
            self.writeCtaLog(log)

            self.shortSig = False
            # return

        if self.sellSig:
            if bar.close > self.stopExit:
                price = self.trailingExit
            else:
                price = bar.close
            res = self.sell(price, abs(self.pos), True)
            # self.orderList.extend(res)
            log = "-----" * 10 + "\n@onBar\n" + \
                  "bar.datetime: {0}; pos: {1} \n".format(bar.datetime, self.pos) + \
                  "buySig: {0}; shortSig: {1}\n".format(self.buySig, self.shortSig) + \
                  "sellSig: {0}; coverSig: {1}\n".format(self.sellSig, self.coverSig) + \
                  "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \
                  "intraTradeLow: {0}\n".format(self.intraTradeLow)
            self.writeCtaLog(log)
            # 记录log
            log = "\n Trading: {0}\n".format(self.trading) + \
                  "{0} Sell : {1};\n".format(bar.datetime, bar.close) + \
                  " price:{0}; stopExit: {1}\n".format(price,self.stopExit)
            self.writeCtaLog(log)

            # self.entryPriceList = []
            # self.avgEntryPrice = 0
            # self.stopExit = 0
            self.sellSig = False
            # return

        if self.coverSig:
            if bar.close < self.stopExit:
                price = self.trailingExit
            else:
                price = bar.close
            res = self.cover(price, abs(self.pos), True)
            # self.orderList.extend(res)
            log = "-----" * 10 + "\n@onBar\n" + \
                  "bar.datetime: {0}; pos: {1} \n".format(bar.datetime, self.pos) + \
                  "buySig: {0}; shortSig: {1}\n".format(self.buySig, self.shortSig) + \
                  "sellSig: {0}; coverSig: {1}\n".format(self.sellSig, self.coverSig) + \
                  "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \
                  "intraTradeLow: {0}\n".format(self.intraTradeLow)
            self.writeCtaLog(log)
            # 记录log
            log = "\n Trading: {0}\n".format(self.trading) + \
                  "{0} Cover : {1};\n".format(bar.datetime, bar.close) + \
                  " price:{0}; stopExit: {1}\n".format(price,self.stopExit)
            self.writeCtaLog(log)

            # self.entryPriceList = []
            # self.avgEntryPrice = 0
            # self.stopExit = 0
            self.coverSig = False
            # return
        self.putEvent()

    #----------------------------------------------------------------------
    def onFiveBar(self, bar):
        """收到5分钟K线"""
        # 策略周期5Min,生成交易信号
        # 保存K线数据
        if not self.trading:
            return
        self.am.updateBar(bar)

        if not self.am.inited:
            return

        # 撤销之前发出的尚未成交的委托(包括限价单和停止单)
        self.cancelAll()

        # 计算指标数值
        self.bollMid = self.am.sma(self.bollWindow,
                                   True)[-1 * (self.dispacedLen + 1)]
        self.bollStd = self.am.std(self.bollWindow)
        self.entryUp = round(self.bollMid + self.bollStd * self.entryDevUp)
        self.entryDown = round(self.bollMid - self.bollStd * self.entryDevDown)
        maArray = self.am.sma(self.maWindow, True)
        self.maFilter = round(maArray[-1])
        self.maFilter1 = round(maArray[-2])

        # 判断是否要进行交易
        # 当前无仓位
        if self.pos == 0:
            self.intraTradeHigh = bar.high
            self.intraTradeLow = bar.low
            self.entryPriceList = []
            self.orderList = []
            self.avgEntryPrice = 0

            if bar.close > self.maFilter and self.maFilter > self.maFilter1:
                # 均线多头过滤
                if bar.close >= self.entryUp:
                    # 上轨突破
                    self.buySig = True

            if bar.close < self.maFilter and self.maFilter < self.maFilter1:
                # 均线空头过滤
                if bar.close <= self.entryDown:
                    # 下轨突破
                    self.shortSig = True

            log = "-----" * 10 + "\n@onFiveBar\n" + \
                  "bar.datetime: {0}; pos: {1} ; close: {2}\n".format(bar.datetime, self.pos,bar.close) + \
                  "buySig: {0}; shortSig: {1}\n".format(self.buySig, self.shortSig) + \
                  "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \
                  "intraTradeLow: {0}\n".format(self.intraTradeLow)
            self.writeCtaLog(log)

        # 当前有仓位
        else:
            self.intraTradeHigh = max(self.intraTradeHigh, bar.high)
            self.intraTradeLow = min(self.intraTradeLow, bar.low)

            if self.pos > 0:
                # self.stopExit = self.avgEntryPrice - self.exitOnLossStop * self.minDiff #固定止损价位

                if self.intraTradeHigh >= self.avgEntryPrice + self.trailingStart2 * self.minDiff:
                    # 二级止赢判断 盈利80跳
                    if (bar.close <= self.intraTradeHigh -
                            self.exitOnTrailingStop2 * self.minDiff):
                        # 回撤20跳
                        self.trailingExit = self.intraTradeHigh - self.exitOnTrailingStop2 * self.minDiff
                        self.sellSig = True
                        # if bar.close < self.longExit:
                        #     self.longExit = bar.close
                        # 记录log
                        # log = "\n{0} Sell(Trailing Stop2)\n".format(bar.datetime) + \
                        #     'bar.close: {0}; bar.low: {1}; longExit: {2}'.format(bar.close,bar.low, self.longExit)+ \
                        #     'intraTradeHigh: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeHigh,self.avgEntryPrice, bar.open)
                        # self.writeCtaLog(log)

                elif self.intraTradeHigh >= self.avgEntryPrice + self.trailingStart1 * self.minDiff:
                    # 一级止赢判断,盈利50跳
                    if (bar.close <= self.intraTradeHigh -
                            self.exitOnTrailingStop1 * self.minDiff):
                        # 回撤20跳
                        self.trailingExit = self.intraTradeHigh - self.exitOnTrailingStop1 * self.minDiff
                        self.sellSig = True
                        # if bar.close < self.longExit:
                        #     self.longExit = bar.close
                        # 记录log
                        # log = "\n{0} Sell(Trailing Stop1)\n".format(bar.datetime) + \
                        #       'bar.close: {0}; bar.low: {1}; longExit: {2}'.format(bar.close, bar.low,
                        #                                                            self.longExit)+ \
                        #       'intraTradeHigh: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeHigh,self.avgEntryPrice, bar.open)
                        # self.writeCtaLog(log)
                elif self.stopExit != 0:
                    if (bar.close <= self.stopExit):
                        # 固定止损,回撤20跳
                        self.sellSig = True
                log = "-----" * 10 + "\n@onFiveBar\n" + \
                      "bar.datetime: {0}; pos: {1} ; close:{2}\n".format(bar.datetime, self.pos, bar.close) + \
                      "sellSig: {0}; coverSig: {1}\n".format(self.sellSig, self.coverSig) + \
                      "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \
                      "intraTradeLow: {0}\n".format(self.intraTradeLow) + \
                      "trailingStart1: {0}\n".format(self.avgEntryPrice + self.trailingStart1 * self.minDiff) + \
                      "trailingStart2: {0}\n".format(self.avgEntryPrice + self.trailingStart2 * self.minDiff) + \
                      "avgEntryPrice: {0}\n".format(self.avgEntryPrice) + \
                      "trailingStop: {0}\n".format(self.trailingExit) + \
                      "stopExit: {0}\n".format(self.stopExit)

                self.writeCtaLog(log)
                # if bar.close < self.longExit:
                #     self.longExit = bar.close
                # 记录log
                # log = "\n{0} Sell(Loss Stop)\n".format(bar.datetime) + \
                #       'bar.close: {0}; bar.low: {1}; longExit: {2}'.format(bar.close, bar.low,
                #                                                            self.longExit)+ \
                #       'intraTradeHigh: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeHigh,
                #                                                                       self.avgEntryPrice,
                #                                                                       bar.open)
                # self.writeCtaLog(log)

            elif self.pos < 0:
                # self.stopExit = self.avgEntryPrice + self.exitOnLossStop * self.minDiff #固定止损价
                if self.intraTradeLow <= self.avgEntryPrice - self.trailingStart2 * self.minDiff:
                    # 二级止赢判断 盈利80跳
                    if (bar.close >= self.intraTradeLow +
                            self.exitOnTrailingStop2 * self.minDiff):
                        # 回撤20跳
                        self.trailingExit = self.intraTradeLow + self.exitOnTrailingStop2 * self.minDiff
                        self.coverSig = True
                        # if bar.close > self.shortExit:
                        #     self.shortExit = bar.close
                        # 记录log
                        # log = "\n{0} Cover(Trailing Stop1)\n".format(bar.datetime) + \
                        #       'bar.close: {0}; bar.low: {1}; shortExit: {2}'.format(bar.close, bar.low,
                        #                                                            self.shortExit)+ \
                        #       'intraTradeLow: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeLow,
                        #                                                                       self.avgEntryPrice,
                        #                                                                       bar.open)
                        # self.writeCtaLog(log)

                elif self.intraTradeLow <= self.avgEntryPrice - self.trailingStart1 * self.minDiff:
                    # 一级止赢判断,盈利50跳
                    if (bar.close >= self.intraTradeLow +
                            self.exitOnTrailingStop1 * self.minDiff):
                        # 回撤20跳
                        self.trailingExit = self.intraTradeLow + self.exitOnTrailingStop1 * self.minDiff
                        self.coverSig = True
                        # if bar.close > self.shortExit:
                        #     self.shortExit = bar.close
                        # 记录log
                        # log = "\n{0} Cover(Trailing Stop2)\n".format(bar.datetime) + \
                        #       'bar.close: {0}; bar.low: {1}; shortExit: {2}'.format(bar.close, bar.low,
                        #                                                            self.shortExit)+ \
                        #       'intraTradeLow: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeLow,
                        #                                                                      self.avgEntryPrice,
                        #                                                                      bar.open)
                        # self.writeCtaLog(log)
                elif self.stopExit != 0:
                    if (bar.close >= self.stopExit):
                        # 固定止损,回撤20跳
                        # self.shortExit = self.avgEntryPrice + self.exitOnLossStop * self.minDiff
                        self.coverSig = True
                # if bar.close > self.shortExit:
                #     self.shortExit = bar.close
                # 记录log
                # log = "\n{0} Cover(Loss Stop)\n".format(bar.datetime) + \
                #       'bar.close: {0}; bar.low: {1}; shortExit: {2}'.format(bar.close, bar.low,
                #                                                             self.shortExit)+ \
                #       'intraTradeLow: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeLow,
                #                                                                      self.avgEntryPrice,
                #                                                                      bar.open)
                # self.writeCtaLog(log)

                log = "-----" * 10 + "\n@onFiveBar\n" + \
                      "bar.datetime: {0}; pos: {1} ; close:{2}\n".format(bar.datetime, self.pos, bar.close) + \
                      "sellSig: {0}; coverSig: {1}\n".format(self.sellSig, self.coverSig) + \
                      "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \
                      "intraTradeLow: {0}\n".format(self.intraTradeLow) + \
                      "trailingStart1: {0}\n".format(self.avgEntryPrice - self.trailingStart1 * self.minDiff)+\
                      "trailingStart2: {0}\n".format(self.avgEntryPrice - self.trailingStart2 * self.minDiff)+\
                      "avgEntryPrice: {0}\n".format(self.avgEntryPrice)+\
                      "trailingStop: {0}\n".format(self.trailingExit)+\
                      "stopExit: {0}\n".format(self.stopExit)

                self.writeCtaLog(log)
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        # CTA引擎中涉及到的交易方向类型
        # CTAORDER_BUY = u'买开'
        # CTAORDER_SELL = u'卖平'
        # CTAORDER_SHORT = u'卖开'
        # CTAORDER_COVER = u'买平'
        log = "-----" * 10 + "\n@onOrder\n" + \
              "orderTime: {0}; pos: {1} \n".format(order.orderTime, order.totalVolume) + \
              u"status {0}; vtOrderID: {1}\n".format(order.status, order.vtOrderID)
        self.writeCtaLog(log)

        # 对于开仓,记录相关价格
        # if order.vtOrderID in self.orderList:
        if order.direction == DIRECTION_LONG and order.offset == OFFSET_OPEN:
            if order.totalVolume == order.tradedVolume:
                # 更新入场价列表,更新平均入场价
                self.entryPriceList.append(order.price)
                self.avgEntryPrice = sum(self.entryPriceList) / len(
                    self.entryPriceList)
                self.stopExit = self.avgEntryPrice - self.exitOnLossStop * self.minDiff  # 固定止损价
                # self.orderList.remove(order.vtOrderID)

        elif order.direction == DIRECTION_SHORT and order.offset == OFFSET_OPEN:
            # 更新入场价列表,更新平均入场价
            if order.totalVolume == order.tradedVolume:
                # 更新入场价列表,更新平均入场价
                self.entryPriceList.append(order.price)
                self.avgEntryPrice = sum(self.entryPriceList) / len(
                    self.entryPriceList)
                self.stopExit = self.avgEntryPrice + self.exitOnLossStop * self.minDiff  # 固定止损价
                # self.orderList.remove(order.vtOrderID)

        self.putEvent()

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        data = trade.__dict__

        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        data = so.__dict__
        self.putEvent()
Exemple #18
0
class BreakThroughAndCallbackStrategy(CtaTemplate):
    className = 'BreakThroughAndCallbackStrategy'
    author = u'用Python的交易员'

    # 策略参数
    fastWindow = 5  # 快速均线参数
    first_N = 0
    pre_N = 0
    current_N = 0
    length_of_N = 20
    PDC = 0
    slowWindow = 20  # 慢速均线参数
    long_window = 144  # 长趋势
    initDays = 20  # 初始化数据所用的天数
    unit_size_of_position = 0  # 头寸规模,根据海龟交易法则进行制定,每天变化,无持仓变化
    future_name = "RB"
    new_day = True
    total_capital = 100000
    donchian_up = 0
    donchian_down = 0
    stop_donchian_up = 0
    stop_donchian_down = 0
    buy_open_price = 0
    buy_append_price = 0
    sell_open_price = 0
    sell_append_price = 0

    # 策略参数
    long_window = 144  # 长趋势

    longMA0 = EMPTY_FLOAT
    longMA1 = EMPTY_FLOAT

    # 参数列表,保存了参数的名称
    paramList = ['name',
                 'className',
                 'author',
                 'vtSymbol',
                 'fastWindow',
                 'slowWindow']

    # 变量列表,保存了变量的名称
    varList = ['inited',
               'trading',
               'pos',
               'fastMa0',
               'fastMa1',
               'slowMa0',
               'slowMa1']

    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos']

    # ----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(DoubleMaStrategy, self).__init__(ctaEngine, setting)

        self.bg = BarGenerator(self.onBar)
        self.am = ArrayManager()
        self.bg15 = BarGenerator(self.onBar, 15, self.on15MinBar)
        self.am15 = ArrayManager()
        # rq.init()

        # 注意策略类中的可变对象属性(通常是list和dict等),在策略初始化时需要重新创建,
        # 否则会出现多个策略实例之间数据共享的情况,有可能导致潜在的策略逻辑错误风险,
        # 策略类中的这些可变对象属性可以选择不写,全都放在__init__下面,写主要是为了阅读
        # 策略时方便(更多是个编程习惯的选择)

    # ----------------------------------------------------------------------
    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略初始化')

        initData = self.loadBar(self.initDays)
        for bar in initData:
            self.onBar(bar)

        self.putEvent()

    # ----------------------------------------------------------------------
    def onStart(self):
        """启动策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略启动')
        self.putEvent()

    # ----------------------------------------------------------------------
    def onStop(self):
        """停止策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略停止')
        self.putEvent()

    # ----------------------------------------------------------------------
    def onTick(self, tick):
        """收到行情TICK推送(必须由用户继承实现)"""
        self.bg.updateTick(tick)

    # ----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        self.bg15.updateBar(bar)
        am = self.am
        am.updateBar(bar)
        if not am.inited:
            return
        if not self.am15.inited:
            return
        if not self.unit_size_of_position:
            self.get_unit_size_of_position()
        if not self.donchian_up:
            (self.donchian_up, self.donchian_down) = am.donchian(300)  # 15 *20
            (self.stop_donchian_up, self.stop_donchian_down) = am.donchian(150)  # 15 * 10
            return  # 没有计算过通道之前不进行交易判断
        # TODO 先使用最简单的入市策略,后续再根据海龟策略的系统1中的讲解,添加入市的策略
        long_ma = am.sma(self.long_window, array=True)
        self.longMA0 = long_ma[-1]
        self.longMA1 = long_ma[-2]
        rising_trend = self.longMA0 > self.longMA1
        down_trend = self.longMA0 < self.longMA1

        if am.high[-1] > self.donchian_up and self.pos == 0 and rising_trend:  # 超出通道上线买入
            self.buy(am.close[-1], 1)
            self.buy_open_price = am.close[-1]
            self.buy_append_price = self.buy_open_price
        if am.low[-1] < self.donchian_down and self.pos == 0 and down_trend:  # 跌穿通道下沿卖出
            self.short(am.close[-1], 1)
            self.sell_open_price = am.close[-1]
            self.sell_append_price = self.sell_open_price
        # 加仓逻辑
        if self.pos:
            # 多头加仓
            if 4 > self.pos > 0:
                if am.high[-1] >= (self.buy_append_price + self.current_N / 2):
                    self.buy(am.close[-1], 1)
                    self.buy_append_price = am.close[-1]
            if -4 < self.pos < 0:
                if am.low[-1] <= (self.sell_append_price - self.current_N / 2):
                    self.short(am.close[-1], 1)
                    self.sell_append_price = am.close[-1]
        # 退出逻辑
        if self.pos:
            if self.pos > 0:
                if am.close[-1] < self.stop_donchian_down:
                    self.sell(am.close[-1], abs(self.pos))
            if self.pos < 0:
                if am.close[-1] > self.stop_donchian_up:
                    self.cover(am.close[-1], abs(self.pos))
        # 止损逻辑
        if self.pos:
            if self.pos > 0:
                if am.close[-1] < self.buy_append_price - 2 * self.current_N:
                    self.sell(am.close[-1], abs(self.pos))
            if self.pos < 0:
                if am.close[-1] > self.sell_append_price + 2 * self.current_N:
                    self.cover(am.close[-1], abs(self.pos))

        (self.donchian_up, self.donchian_down) = am.donchian(300)  # 15 *20
        (self.stop_donchian_up, self.stop_donchian_down) = am.donchian(150)  # 15 * 10

        # 发出状态更新事件
        self.putEvent()

    def on15MinBar(self, bar):
        """15分钟K线推送"""
        self.am15.updateBar(bar)
        if not self.am15.inited:
            return
        #        if self.am15.close[-20] > 1:    # 一共有了20根bar再进行指标的计算
        #            print bar.datetime.strftime("%Y-%m-%d,%H:%M")
        #            print self.am15.close[-20:]
        if not self.first_N:
            self.calculate_first_N()
        if not self.pre_N:
            self.pre_N = self.first_N
            self.current_N = self.pre_N  # 期初使用preN 作为 currentN
        else:
            self.current_N = (self.pre_N * 19 + self.calculate_TR()) / self.length_of_N
            self.pre_N = self.current_N

    def calculate_TR(self):
        current_day_H_minus_L = self.am15.high[-1] - self.am15.low[-1]
        current_day_H_minus_yesterday_C = abs(self.am15.high[-1] - self.am15.close[-2])
        yesterday_C_minus_current_day_L = abs(self.am15.close[-2] - self.am15.low[-1])
        TR = max(current_day_H_minus_L, current_day_H_minus_yesterday_C, yesterday_C_minus_current_day_L)
        return TR

    # 用前二十一天的数据计算第一个N值
    def calculate_first_N(self):
        TR_list = []
        for i in range(-20, 0):
            current_day_H_minus_L = self.am15.high[i] - self.am15.low[i]
            current_day_H_minus_yesterday_C = abs(self.am15.high[i] - self.am15.close[i - 1])
            yesterday_C_minus_current_day_L = abs(self.am15.close[i - 1] - self.am15.low[i])
            TR = max(current_day_H_minus_L, current_day_H_minus_yesterday_C, yesterday_C_minus_current_day_L)
            TR_list.append(TR)
        self.first_N = np.array(TR_list).mean()

    # ----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        # 对于无需做细粒度委托控制的策略,可以忽略onOrder
        pass

    # ----------------------------------------------------------------------
    def onTrade(self, trade):
        """收到成交推送(必须由用户继承实现)"""
        # 对于无需做细粒度委托控制的策略,可以忽略onOrder
        pass

    # ----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass

    def get_unit_size_of_position(self):
        if self.new_day and not self.pos:
            time_of_today = datetime.now().strftime("%Y%m%d")
            # 验证策略暂时先不管这一块儿,后续耗时的操作都在开盘前一个小时做好,然后策略从本地文件中读取数据
            # 在数据库中记录策略上一次运行的时间,用来判断是否需要重新计算unit_size_of_position
            # temp_future_name = rq.get_dominant_future(self.future_name, time_of_today)[-1]
            # temp_info = rq.instruments(temp_future_name)
            # margin_rate = temp_info.margin_rate
            # contract_multiplier = temp_info.contract_multiplier  # 合约乘数
            contract_multiplier = 10
            margin_rate = 0.09
            self.unit_size_of_position = (0.01 * self.total_capital) / (self.current_N * contract_multiplier)
            self.unit_size_of_position = self.unit_size_of_position * margin_rate * 2  # 期货公司收取的保证金率为最低的三倍左右
            self.unit_size_of_position = int(self.unit_size_of_position)
Exemple #19
0
class TripleMAStrategy02(CtaTemplate):
    """基于三均线的交易策略"""
    className = 'TripleMAStrategy'
    author = 'Y.Raul'

    # 策略参数
    # 三均线长度设置
    maWindow1 = 10
    maWindow2 = 20
    maWindow3 = 120
    maWindow4 = 5

    initDays = 10  # 初始化数据所用的天数
    fixedSize = 1  # 每次交易的数量

    # 策略变量
    # ma次新值
    ma10 = 0
    ma20 = 0
    # ma最新值
    ma11 = 0
    ma21 = 0
    ma31 = 0

    longEntry = 0  # 多头开仓
    longExit = 0  # 多头平仓
    shortEntry = 0
    shortExit = 0

    orderList = []  # 保存委托代码的列表

    # 参数列表,保存了参数的名称
    paramList = [
        'name', 'className', 'author', 'vtSymbol', 'maWindow1', 'maWindow2',
        'maWindow3', 'maWindow4'
        'initDays', 'fixedSize'
    ]

    # 变量列表,保存了变量的名称
    varList = ['inited', 'trading', 'pos', 'ma10', 'ma11', 'ma20', 'ma21']
    # 同步列表
    syncList = ['pos']

    # ----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(TripleMAStrategy02, self).__init__(ctaEngine, setting)

        self.bm = BarGenerator(self.onBar, 5, self.onFiveBar)
        # 由于maWindow3的长度是120,所以ArrayManager的size要增加至150
        self.am = ArrayManager(size=150)

    # ----------------------------------------------------------------------
    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线"""
        # 保存K线数据
        self.am.updateBar(bar)
        if not self.am.inited:
            return

            # 撤销之前发出的尚未成交的委托(包括限价单和停止单)
        self.cancelAll()

        import talib
        # 计算指标数值
        ma3Array = self.am.sma(self.maWindow3, True)
        self.ma30 = ma3Array[-2]
        self.ma31 = ma3Array[-1]
        ma3_ma5 = talib.SMA(ma3Array, self.maWindow4)[-1]
        # ma3_ma5 = ma3Array.rolling(window = self.maWindow4)[-1]

        ma1Array = self.am.sma(self.maWindow1, True)
        self.ma10 = ma1Array[-2]
        self.ma11 = ma1Array[-1]
        # ma1_ma5 = ma1Array.rolling(window = self.maWindow4)[-1]
        ma1_ma5 = talib.SMA(ma1Array, self.maWindow4)[-1]
        ma2Array = self.am.sma(self.maWindow2, True)
        self.ma20 = ma2Array[-2]
        self.ma21 = ma2Array[-1]
        # 判断是否要进行交易
        # 当前无仓位,发送OCO开仓委托
        if self.pos == 0:
            # 开多, bar.close > MA120,MA10 > MA120,MA10 上穿MA20,MA10、MA120向上
            if bar.close > self.ma31 and self.ma11 > self.ma31 \
                    and self.ma10 < self.ma20 and self.ma11 > self.ma21\
                    and self.ma31 > ma3_ma5 and self.ma11 > ma1_ma5:
                self.longEntry = bar.close
                self.buy(self.longEntry, self.fixedSize, True)
            # 开空, bar.close < MA120,MA10 < MA120,MA10 下穿MA20, MA10,MA120向下
            elif bar.close < self.ma31 and self.ma11 < self.ma31 \
                    and self.ma10 > self.ma20 and self.ma11 < self.ma21\
                    and self.ma31 < ma3_ma5 and self.ma11 < ma1_ma5:
                self.shortEntry = bar.close
                self.short(self.shortEntry, self.fixedSize, True)
        else:
            # 持有多头仓位
            if self.pos > 0:
                self.longExit = bar.close
                # 平多,MA10下穿MA20
                if self.ma10 > self.ma20 and self.ma11 < self.ma21:
                    self.sell(self.longExit, abs(self.pos), True)
            # 持有空头仓位
            if self.pos < 0:
                self.shortExit = bar.close
                # 平空, MA10上穿MA20
                if self.ma10 < self.ma20 and self.ma11 > self.ma21:
                    self.cover(self.shortExit, abs(self.pos), True)
        # 发出状态更新事件
        self.putEvent()

        # ----------------------------------------------------------------------

    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        pass

    # ----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        self.putEvent()

    # ----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Exemple #20
0
class SARKELStrategy(CtaTemplate):
    """基于sar and Keltner 交易策略"""
    className = 'SARKELStrategy'
    author = u'张老师'

    # 策略参数
    sarAcceleration = 0.02  #加速线
    sarMaximum = 0.2  #
    cciWindow = 20  # CCI窗口数
    keltnerWindow = 25  # keltner窗口数
    keltnerlMultiplier = 6.0  # 乘数
    initDays = 10  # 初始化数据所用的天数
    fixedSize = 1  # 每次交易的数量
    barMins = 15
    barMinsClose = 10
    # 策略变量
    sarValue = 0  # sar指标数值
    cciValue = 0  # CCI指标数值
    keltnerup = 0
    keltnerdown = 0
    longStop = 0  # 多头止损
    shortStop = 0  # 空头止损

    # 参数列表,保存了参数的名称
    paramList = [
        'name', 'className', 'author', 'vtSymbol', 'sarAcceleration',
        'sarMaximum', 'cciWindow', 'keltnerWindow', 'keltnerlMultiplier',
        'initDays', 'fixedSize', 'barMinsClose', 'barMins'
    ]

    # 变量列表,保存了变量的名称
    varList = ['inited', 'trading', 'pos', 'sarValue', 'cciValue', 'atrValue']

    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos']

    # ----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(SARKELStrategy, self).__init__(ctaEngine, setting)

        self.bg = BarGenerator(self.onBar, self.barMins,
                               self.onXminBar)  # 创建K线合成器对象
        self.am = ArrayManager()

        self.bgclose = BarGenerator(self.onBar, self.barMinsClose,
                                    self.onminBarClose)
        self.amClose = ArrayManager()

    # ----------------------------------------------------------------------
    def onminBarClose(self, bar):
        """分钟作为清仓周期"""
        # 如果没有仓位,那么不用care,直接skip

        # 保存K线数据
        amClose = self.amClose

        amClose.updateBar(bar)

        if not amClose.inited:
            return

        # 计算指标数值
        self.sarValue = amClose.sar(self.sarAcceleration, self.sarMaximum)

        # 判断是否要进行交易
        if self.pos == 0:
            return

        # 当前无仓位,发送开仓委托
        # 持有多头仓位
        elif self.pos > 0:
            self.cancelAll()
            self.sell(self.sarValue, abs(self.pos), True)

        # 持有空头仓位
        elif self.pos < 0:
            self.cancelAll()
            self.cover(self.sarValue, abs(self.pos), True)

        # 同步数据到数据库
        self.saveSyncData()

        # 发出状态更新事件
        self.putEvent()

        # ----------------------------------------------------------------------

    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.bg.updateTick(tick)

    # ----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        self.bg.updateBar(bar)
        self.bgclose.updateBar(bar)

    # ----------------------------------------------------------------------
    def onXminBar(self, bar):
        """收到X分钟K线"""
        # 全撤之前发出的委托
        self.cancelAll()

        # 保存K线数据
        am = self.am

        am.updateBar(bar)

        if not am.inited:
            return

        # 计算指标数值
        self.cciValue = am.cci(self.cciWindow)
        self.keltnerup, self.keltnerdown = am.keltner(self.keltnerWindow,
                                                      self.keltnerlMultiplier)

        # 判断是否要进行交易

        # 当前无仓位,发送开仓委托
        if self.pos == 0:

            if self.cciValue > 0:
                # ru
                self.buy(self.keltnerup, self.fixedSize, True)

            elif self.cciValue < 0:
                self.short(self.keltnerdown, self.fixedSize, True)

        # 同步数据到数据库
        self.saveSyncData()

        # 发出状态更新事件
        self.putEvent()

    # ----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        pass

    # ----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        self.putEvent()

    # ----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Exemple #21
0
class BollChannelStrategy(CtaTemplate):
    """基于布林通道的交易策略"""
    className = 'BollChannelStrategy'
    author = u'用Python的交易员'

    # 策略参数
    bollWindow = 18  # 布林通道窗口数
    bollDev = 3.4  # 布林通道的偏差
    cciWindow = 10  # CCI窗口数
    atrWindow = 30  # ATR窗口数
    slMultiplier = 5.2  # 计算止损距离的乘数
    initDays = 10  # 初始化数据所用的天数
    fixedSize = 1  # 每次交易的数量

    # 策略变量
    bollUp = 0  # 布林通道上轨
    bollDown = 0  # 布林通道下轨
    cciValue = 0  # CCI指标数值
    atrValue = 0  # ATR指标数值

    intraTradeHigh = 0  # 持仓期内的最高点
    intraTradeLow = 0  # 持仓期内的最低点
    longStop = 0  # 多头止损
    shortStop = 0  # 空头止损

    # 参数列表,保存了参数的名称
    paramList = [
        'name', 'className', 'author', 'vtSymbol', 'bollWindow', 'bollDev',
        'cciWindow', 'atrWindow', 'slMultiplier', 'initDays', 'fixedSize'
    ]

    # 变量列表,保存了变量的名称
    varList = [
        'inited', 'trading', 'pos', 'bollUp', 'bollDown', 'cciValue',
        'atrValue', 'intraTradeHigh', 'intraTradeLow', 'longStop', 'shortStop'
    ]

    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos', 'intraTradeHigh', 'intraTradeLow']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(BollChannelStrategy, self).__init__(ctaEngine, setting)

        self.bg = BarGenerator(self.onBar, 15, self.onXminBar)  # 创建K线合成器对象
        self.bg30 = BarGenerator(self.onBar, 30, self.on30minBar)
        self.am = ArrayManager()

    #----------------------------------------------------------------------
    def on30minBar(self, bar):
        """"""

    #----------------------------------------------------------------------
    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.bg.updateTick(tick)

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        self.bg.updateBar(bar)

    #----------------------------------------------------------------------
    def onXminBar(self, bar):
        """收到X分钟K线"""
        # 全撤之前发出的委托
        self.cancelAll()

        # 保存K线数据
        am = self.am

        am.updateBar(bar)

        if not am.inited:
            return

        # 计算指标数值
        self.bollUp, self.bollDown = am.boll(self.bollWindow, self.bollDev)
        self.cciValue = am.cci(self.cciWindow)
        self.atrValue = am.atr(self.atrWindow)

        # 判断是否要进行交易

        # 当前无仓位,发送开仓委托
        if self.pos == 0:
            self.intraTradeHigh = bar.high
            self.intraTradeLow = bar.low

            if self.cciValue > 0:
                self.buy(self.bollUp, self.fixedSize, True)

            elif self.cciValue < 0:
                self.short(self.bollDown, self.fixedSize, True)

        # 持有多头仓位
        elif self.pos > 0:
            self.intraTradeHigh = max(self.intraTradeHigh, bar.high)
            self.intraTradeLow = bar.low
            self.longStop = self.intraTradeHigh - self.atrValue * self.slMultiplier

            self.sell(self.longStop, abs(self.pos), True)

        # 持有空头仓位
        elif self.pos < 0:
            self.intraTradeHigh = bar.high
            self.intraTradeLow = min(self.intraTradeLow, bar.low)
            self.shortStop = self.intraTradeLow + self.atrValue * self.slMultiplier

            self.cover(self.shortStop, abs(self.pos), True)

        # 同步数据到数据库
        self.saveSyncData()

        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        pass

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Exemple #22
0
class strategyHedge(CtaTemplate):
    """European"""
    className = 'strategyDemo_syt'
    author = u'syt'

    # 策略参数
    takeProfitPoint = 2  #止赢点数
    stopLossPoint = 1  #止损点数
    # 策略变量
    longPosition = 0
    shortPosition = 0
    # 参数列表,保存了参数的名称
    paramList = ['name', 'className', 'author', 'vtSymbol']

    # 变量列表,保存了变量的名称
    varList = ['inited', 'trading', 'pos', 'hedgeratio']
    posAdd = 0
    paramFilename = 'strategyHedge_Param_Setting.json'
    path = os.path.abspath(os.path.dirname(__file__))
    path1 = os.path.join(path, paramFilename)

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        self.paramSetting()
        super(strategyHedge, self).__init__(ctaEngine, setting)

        # self.contractMode='Double'     #主力合约与次主力合约模式
        self.contractMode = 'Dominant'  #主力合约模式
        self.num = pd.Series([])
        self.num_unit = pd.Series([])
        self.lastOrder = None
        self.lastTrade = None

        self.orderType = ''
        self.contractname = ''
        self.contractnameAdd = ''
        self.initialFlag = True
        self.PositionCodeList = []
        self.signalGroupList = []
        self.rollingDays = 0
        #开单条件:远-近 价差大于10,开仓
        self.isBuySign = False
        self.isShortSign = False
        self.isBuyCoverSign = False
        self.isShortCoverSign = False

        #记录价格序列
        self.tickListPrice = []
        self.tickListAddPrice = []

        self.dayList = []
        self.dayListPrice = []
        self.dayDates = []
        self.spot = pd.Series([])
        self.bg = BarGenerator(self.onDay, 1, self.onXminDay)
        self.am = ArrayManager()

        self.future = pd.Series([])
        self.period = 10  #套保周期
        self.Qs = 10000  #现货数量
        self.direction = "LongHedging"
        #self.datastartdate="2015-01-01"
        #self.startdate="2015-03-01"
        #self.enddate="2015-05-01"

        self.contractList = defaultdict(dict)
        self.LongHedging_openSignal = defaultdict(dict)
        self.LongHedging_CloseSignal = defaultdict(dict)
        self.ShortHedging_openSignal = defaultdict(dict)
        self.ShortHedging_CloseSignal = defaultdict(dict)
        self.adjdates = []
        self.hedgeDF = pd.Series([])
        self.numDF = pd.Series([])
        self.hedgeratio = 0

    #----------------------------------------------------------------------
    def paramSetting(self):
        #策略参数写入名为“strategyHedge_Param_Setting”的文件中
        with open(self.path1) as f:
            param = json.load(f)
            d = self.__dict__
            for key in param:
                d[key] = param[key]
#----------------------------------------------------------------------

    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        if self.initialFlag:
            # 初始化仓位
            self.initialStrategyPos(self.className)
            self.initialFlag = False
            # plt.ion()
            # fig1 = plt.figure()
        self.writeCtaLog(u'商品套期保值策略初始化')

    #----------------------------------------------------------------------
    def onStart(self):
        """启动策略(必须由用户继承实现)"""
        self.isNewDay = True
        self.isRollingClose = True
        #每天检查持仓
        self.PositionCodeList = self.ctaEngine.dbClient[POSITION_DB_NAME][
            self.className].distinct("vtSymbol")
        self.signalGroupList = self.ctaEngine.dbClient[POSITION_DB_NAME][
            self.className].distinct("signalGroup")

        if self.adjdates == []:
            self.dateList(self.period, startdate=self.startdate)
        if len(self.spot) == 0:
            self.spot = self.spotDF(self.spotID)
        self.writeCtaLog(u'商品套期保值策略启动')
        self.check_loggerPosition()

        self.putEvent()

    #----------------------------------------------------------------------
    def onStop(self):
        """停止策略(必须由用户继承实现)"""
        self.writeCtaLog(u'追涨Tick演示策略停止')
        self.putEvent()

    #----------------------------------------------------------------------
    def confirmDominant(self, tick):
        # 确定主力合约与次主力合约
        for key, details in self.ctaEngine.contract_dict[tick.date].items():

            if details['property'] == 'DOMINANT':
                self.contractList[details['symbolInit']].update(
                    {'DOMINANT': key})
            if details['property'] == 'SUBDOMINANT':
                self.contractList[details['symbolInit']].update(
                    {'SUBDOMINANT': key})

    def onTick(self, tick):
        #检查是否还有挂单,并处理,回测与模拟盘检查挂单方式有差异,待解决
        if self.ctaEngine.workingLimitOrderDict.keys():
            self.killOrder(tick, 60, 3)
        '''推送行情前,先检查最新主力合约,否则isNewDay会错误关闭'''
        if self.isNewDay:  # 每天判断一次
            symbolInit = self.ctaEngine.contract_dict[tick.date][
                tick.vtSymbol]['symbolInit']
            if self.contractList == {} or self.rollingDays != 0 or self.ctaEngine.rollingFlag:
                self.confirmDominant(tick)
            self.isNewDay = False
        """收到行情TICK推送(必须由用户继承实现)"""
        self.bg.updateTick(tick)

    def beta(self, x, y):
        if len(x) == len(y):
            rho = np.corrcoef(x, y)[0][1]
            hedgeratio = np.std(y) * rho / np.std(x)
        else:
            print(u"自变量与因变量序列长度不匹配")
            exit()
        return hedgeratio

    def linear(self, x, y):
        model = LinearRegression()

        try:
            model.fit(x, y)
        except:
            # model.fit(x.values.reshape(-1,1),y)
            X = []
            Y = []
            for xx, yy in zip(x.values, y.values):
                X.append([float(xx)])
                Y.append([float(yy)])
            model.fit(X, Y)
        hedgeratio = model.coef_[0]
        return hedgeratio

    def spotDF(self, ID):  #ID是现货指标的wind代码,字符串格式
        commodity = self.symbol
        spotcollection = self.ctaEngine.dbClient["SPOT_DB"][commodity]
        ID = str(ID)
        datelist = sorted(self.ctaEngine.contract_dict.keys())
        datadf = pd.DataFrame(
            list(spotcollection.find({
                "ID": ID,
                "Date": {
                    "$gte": datelist[0]
                }
            })))
        spotdf = datadf["Price"]
        #spotdf.index=datadf["Date"]
        #spotdf=spotdf.sort_index()
        spotdf = spotdf[0:len(datelist)]
        spotdf.index = datelist
        return spotdf

    def dateList(self, period, initdelta=None, startdate=None, fixdate=10):
        if period % 20 != 0:
            fixdate = None
        datelist = sorted(self.ctaEngine.contract_dict.keys())
        if startdate in datelist:
            dateList = datelist[datelist.index(startdate):]
        else:
            while startdate not in datelist:
                startdate = (
                    datetime.datetime.strptime(startdate, "%Y-%m-%d") +
                    datetime.timedelta(days=1)).strftime("%Y-%m-%d")
            dateList = datelist[datelist.index(startdate):]
        if (datetime.datetime.strptime(startdate, "%Y-%m-%d") -
                datetime.datetime.strptime(datelist[0],
                                           "%Y-%m-%d")).days > period + 10:
            adj = []
            testDf = pd.DataFrame([])
            if fixdate:
                #dateDF = pd.DataFrame([], index=dateList, columns=[["Year", "Month", "Day"]])
                for date in dateList:
                    #dateDF.loc[date, "Year"] = date.split("-")[0]
                    testDf.ix[date, 'Year'] = date.split("-")[0]
                    testDf.ix[date, 'Month'] = date.split("-")[1]
                    testDf.ix[date, 'Day'] = date.split("-")[2]
                for name, group in testDf.groupby(["Year", "Month"]):
                    if fixdate > len(group):
                        fixdate = len(group)
                    adj.append(group.index[fixdate - 1])
                adjdates = adj[0::int(period / 20)]
                self.adjdates = adjdates[1:]
            else:
                self.adjdates = dateList[0::period]
        else:
            print(u"回测时间太短,请重新设置startdate")
            exit()

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        self.bg.updateBar(bar)

    #----------------------------------------------------------------------
    def onDay(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        self.bg.updateDay(bar)

    #----------------------------------------------------------------------
    def onXminDay(self, bar):
        """收到Tick推送(必须由用户继承实现)"""
        symbolInit = re.findall("[A-Za-z]+", bar.vtSymbol)[0].upper()
        if self.isRollingClose:
            # 检查是否有换月,编写处理逻辑,全平或设定相关条件或移仓
            for code in self.ctaEngine.rollingContract:
                # 找出涉及换月的合约
                dbCusor = self.ctaEngine.dbClient[POSITION_DB_NAME][
                    self.className].find({'vtSymbol': code})

                for contract in dbCusor:
                    # 找出涉及换月的singalGroup所有合约
                    dbCusor2 = self.ctaEngine.dbClient[POSITION_DB_NAME][
                        self.className].find(
                            {'signalGroup': contract['signalGroup']})
                    if contract['signalGroup'].split('_')[0] == 'LongHedging':
                        self.LongHedging_openSignal.update({symbolInit: True})
                    elif contract['signalGroup'].split(
                            '_')[0] == 'ShortHedging':
                        self.ShortHedging_openSignal.update({symbolInit: True})
                    for d in dbCusor2:
                        self.oneKeyClean_Bar(bar, d, contract['signalGroup'])

                    # 关闭信号
                    if contract['signalGroup'].split('_')[0] == 'LongHedging':
                        self.LongHedging_openSignal.update(
                            {contract['signalGroup'].split('_')[1]: True})
                    if contract['signalGroup'].split('_')[0] == 'ShortHedging':
                        self.ShortHedging_openSignal.update(
                            {contract['signalGroup'].split('_')[1]: True})
            self.isRollingClose = False

        DominantCode = self.contractList[symbolInit]['DOMINANT']

        self.future[bar.date] = bar.close
        # self.adjdates=self.dateList(self.period,startdate=self.startdate)

        if bar.date in self.adjdates[0:]:
            self.rF = (np.log(self.future).diff(self.period)).dropna()
            self.rS = (np.log(self.spot[self.future.index]).diff(
                self.period)).dropna()
            hedgeratio = self.beta(self.rF, self.rS)
            self.hedgeDF[bar.date] = hedgeratio
            mult = self.ctaEngine.contract_dict[bar.date][bar.vtSymbol]["size"]
            self.n = int((hedgeratio * self.Qs * self.spot[bar.date]) /
                         (mult * self.future[bar.date]))
            self.n_unit = int((self.Qs * self.spot[bar.date]) /
                              (mult * self.future[bar.date]))
            self.num[bar.date] = self.n
            self.num_unit[bar.date] = self.n_unit

            if self.direction == "LongHedging":
                self.LongHedging_openSignal.update({symbolInit: True})
                #如果旧持仓信号则平仓开启
                if self.direction + '_' + symbolInit in self.signalGroupList:
                    self.LongHedging_CloseSignal.update({symbolInit: True})

            if self.direction == "ShortHedging":
                self.ShortHedging_openSignal.update({symbolInit: True})
                # 如果旧持仓信号则平仓开启
                if self.direction + '_' + symbolInit in self.signalGroupList:
                    self.ShortHedging_CloseSignal.update({symbolInit: True})

        # self.hedgeDF = (self.hedgeDF.reindex(self.rF.index).fillna(method="ffill")).dropna()
        # if bar.date in adjdates[0:]:
        #     if self.direction=="LongHedging" not in self.signalGroupList:
        #         self.LongHedging_openSignal.update({symbolInit: True})
        #     if self.direction=="ShortHedging" not in self.signalGroupList:
        #         self.ShortHedging_openSignal.update({symbolInit: True})

        MinimumPriceChange = self.ctaEngine.Param_setting_dict[symbolInit][
            'MinimumPriceChange']  #最小跳价
        if self.LongHedging_CloseSignal[symbolInit] == True:
            # 买入套保平仓
            # 净头寸调仓待优化
            self.signalName = 'LongHedging_%s' % symbolInit
            dbCusorOrder = self.ctaEngine.dbClient[POSITION_DB_NAME][
                self.className].find({'signalGroup': self.signalName})
            for d in dbCusorOrder:
                self.oneKeyClean_Bar(bar, d, self.signalName, info='套期保值到期平仓')
            self.LongHedging_CloseSignal.update({symbolInit: False})

        if self.ShortHedging_CloseSignal[symbolInit] == True:
            # 卖出套保平仓
            # 待优化同步平仓
            self.signalName = 'ShortHedging_%s' % symbolInit
            dbCusorOrder = self.ctaEngine.dbClient[POSITION_DB_NAME][
                self.className].find({'signalGroup': self.signalName})
            for d in dbCusorOrder:
                self.oneKeyClean_Bar(bar, d, self.signalName, info='套期保值到期平仓')

            self.ShortHedging_CloseSignal.update({symbolInit: False})

        #买入套保开仓
        if self.LongHedging_openSignal[symbolInit] == True:
            self.signalName = 'LongHedging_%s' % symbolInit
            self.ctaEngine.sendOrder(DominantCode, CTAORDER_BUY,
                                     bar.close + MinimumPriceChange, self.n,
                                     self)
            self.writeCtaLog(u'信号' + self.signalName + ': ' + u'下单时间:' +
                             str(self.ctaEngine.dt) + u' 合约 ' + DominantCode +
                             u' 买入套保开仓 ' + str(self.n) + u' 手 ' + ' u价格: ' +
                             str(bar.close + MinimumPriceChange))
            self.LongHedging_openSignal.update({symbolInit: False})

        # 卖出套保开仓
        if self.ShortHedging_openSignal[symbolInit] == True:
            self.signalName = 'ShortHedging_%s' % symbolInit
            self.ctaEngine.sendOrder(DominantCode, CTAORDER_SHORT,
                                     bar.close - MinimumPriceChange, self.n,
                                     self)
            self.writeCtaLog('信号' + self.signalName + ': ' + '下单时间:' +
                             str(self.ctaEngine.dt) + ' 合约 ' + DominantCode +
                             ' 卖出套保开仓 ' + str(self.n) + ' 手 ' + ' 价格: ' +
                             str(bar.close + MinimumPriceChange))
            self.ShortHedging_openSignal.update({symbolInit: False})

    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        # 对于无需做细粒度委托控制的策略,可以忽略onOrder
        self.lastOrder = order
        self.writeCtaLog(
            self.ctaEngine.orderStrategyDict[order.orderID][self.className] +
            '委托订单成交' + ': ' + '下单时间:' + str(order.orderTime) + ' 合约 ' +
            order.vtSymbol + ' ' + order.direction + ' ' + order.offset +
            str(order.totalVolume) + ' 手 ' + ' 委托订单状态: ' + order.status)

        # print self.ctaEngine.orderStrategyDict[order.orderID][self.className],order.vtSymbol, order.direction, order.offset, order.totalVolume, '手', order.status

        #更新持仓列表,没有考虑是否成交
        self.PositionCodeList = self.ctaEngine.dbClient[POSITION_DB_NAME][
            self.className].distinct("vtSymbol")
        self.signalGroupList = self.ctaEngine.dbClient[POSITION_DB_NAME][
            self.className].distinct("signalGroup")

        self.check_loggerPosition()

    def check_loggerPosition(self):
        dbCursor = self.ctaEngine.dbClient[POSITION_DB_NAME][
            self.className].aggregate([{
                '$group': {
                    '_id': '$vtSymbol',
                    'shortTd': {
                        '$sum': '$shortTd'
                    },
                    'longTd': {
                        '$sum': '$longTd'
                    },
                    'longPosTarget': {
                        '$sum': '$longPosTarget'
                    },
                    'shortPosTarget': {
                        '$sum': '$shortPosTarget'
                    }
                }
            }])
        for d in dbCursor:
            self.writeCtaLog('持仓:' + ' 合约 ' + d['_id'] + ' 多头目标持仓 ' +
                             str(d['longPosTarget']) + ' 多头可用持仓: ' +
                             str(d['longTd']) + ' 空头目标持仓 ' +
                             str(d['shortPosTarget']) + ' 空头可用持仓: ' +
                             str(d['shortTd']))

        self.writeCtaLog('持有信号:' + str(self.signalGroupList)[1:-1])

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        """收到成交推送(必须由用户继承实现)"""
        self.lastTrade = trade
        order = self.ctaEngine.workingLimitOrderDict[str(trade.orderID)]
        # 对于无需做细粒度委托控制的策略,可以忽略onTrade
        self.writeCtaLog(
            self.ctaEngine.orderStrategyDict[trade.orderID][self.className] +
            '成交' + ': ' + '成交时间:' + str(trade.tradeTime) + ' 合约 ' +
            trade.vtSymbol + ' ' + order.direction + ' ' + order.offset +
            str(trade.volume) + ' 手 ' + ' 价格: ' + str(trade.price))
        signalName = self.ctaEngine.orderStrategyDict[order.orderID][
            self.className]
        self.updateTradedPos(trade, signalName, order.status)
        #清空0持仓数据库文档
        self.cleanDataBasePos(order, signalName)

    def oneKeyClean(self, tick, d, signalName):
        if tick.vtSymbol == d['vtSymbol']:
            shortPos = d['shortTd'] + d['shortYd']
            longPos = d['longTd'] + d['longYd']
            signalList = []
            self.signalName = d['signalGroup']

            if longPos < shortPos:
                signalList.extend(
                    self.ctaEngine.sendOrder(d['vtSymbol'], CTAORDER_COVER,
                                             tick.askPrice1 + 10, shortPos,
                                             self))  # 下单并返回orderID
                # self.updatePosTarget(signalList, d['signalGroup'])
                # self.sType = 0
                print u'换月强平', tick.datetime, signalName, u'买入平仓', d[
                    'vtSymbol'], shortPos, u'手'
            else:
                signalList.extend(
                    self.ctaEngine.sendOrder(d['vtSymbol'], CTAORDER_SELL,
                                             tick.bidPrice1 - 10, longPos,
                                             self))
                # self.updatePosTarget(signalList, d['signalGroup'])
                # self.bType = 0
                print u'换月强平', tick.datetime, signalName, u'卖出平仓', d[
                    'vtSymbol'], longPos, u'手'

    def oneKeyClean_Bar(self, bar, d, signalName, info='换月强平 '):
        shortPos = d['shortTd'] + d['shortYd']
        longPos = d['longTd'] + d['longYd']
        self.signalName = d['signalGroup']

        if longPos < shortPos:
            self.ctaEngine.sendOrder(d['vtSymbol'], CTAORDER_COVER,
                                     self.bg.lastTick[d['vtSymbol']].askPrice1,
                                     shortPos, self)  # 下单并返回orderID
            self.writeCtaLog('信号' + signalName + ':' + str(bar.datetime) +
                             info + ' 合约 ' + d['vtSymbol'] + ' 买入平仓 ' +
                             str(shortPos) + ' 手')
            # print   u'换月强平',bar.datetime, signalName, u'买入平仓', d['vtSymbol'], shortPos, u'手'
        else:
            try:
                self.ctaEngine.sendOrder(
                    d['vtSymbol'], CTAORDER_SELL,
                    self.bg.lastTick[d['vtSymbol']].bidPrice1, longPos, self)
                self.writeCtaLog('信号' + signalName + ':' + str(bar.datetime) +
                                 info + ' 合约 ' + d['vtSymbol'] + ' 卖出平仓 ' +
                                 str(longPos) + ' 手')
            except:
                self.writeCtaLog(u'error: ')

    #----------------------------------------------------------------------
    def fixedTakeProfit(self):
        """固定止赢处理,以股指示例,2个点止赢"""
        if self.bType == 1 and self.pos > 0:
            if self.tickList[
                    3].askPrice1 - self.lastOrder.price > self.takeProfitPoint:  #如果多单赢利大于2个点
                self.sell(self.tickList[3].bidPrice1, 1)
                self.bType = 0
                self.writeCtaLog(u'多单固定止盈,--平仓价:' +
                                 str(self.tickList[3].bidPrice1) + u'--赢利点数:' +
                                 str(self.tickList[3].bidPrice1 -
                                     self.lastOrder.price))
        elif self.sType == 1 and self.pos < 0:
            if self.lastOrder.price - self.tickList[
                    3].askPrice1 > self.takeProfitPoint:  #如果空单赢利大于2个点
                self.cover(self.tickList[3].askPrice1, 1)
                self.sType = 0
                self.writeCtaLog(u'空单固定止盈,--平仓价:' +
                                 str(self.tickList[3].askPrice1) + u'--赢利点数:' +
                                 str(self.lastOrder.price -
                                     self.tickList[3].askPrice1))

    #----------------------------------------------------------------------
    def fixedStopLoss(self):
        """固定止损处理,以股指示例,1个点止损"""
        if self.bType == 1 and self.pos > 0:
            if self.lastTrade.price - self.tickList[
                    3].lastPrice > self.stopLossPoint:  #如果多单亏损大于1个点
                self.sell(self.tickList[3].bidPrice1, 1)
                self.bType = 0
                self.writeCtaLog(u'多单固定止损,--平仓价:' +
                                 str(self.tickList[3].bidPrice1) + u'--亏损点数:' +
                                 str(self.tickList[3].bidPrice1 -
                                     self.lastTrade.price))
        elif self.sType == 1 and self.pos < 0:
            if self.tickList[
                    3].lastPrice - self.lastTrade.price > self.stopLossPoint:  #如果空单亏损大于1个点
                self.cover(self.tickList[3].askPrice1, 1)
                self.sType = 0
                self.writeCtaLog(u'空单固定止损,--平仓价:' +
                                 str(self.tickList[3].askPrice1) + u'--亏损点数:' +
                                 str(self.lastTrade.price -
                                     self.tickList[3].askPrice1))

    #----------------------------------------------------------------------
    def calculateDailyResult(self):
        self.hedgeDF = (self.hedgeDF.reindex(
            self.rF.index).fillna(method="ffill")).dropna()
        if self.direction == '买入套保':
            rHedged = (-self.rS + self.hedgeDF * self.rF).dropna()
            rUnit = (-self.rS[self.hedgeDF.index] +
                     self.rF[self.hedgeDF.index]).dropna()
            rUnhedged = -self.rS[self.hedgeDF.index]

        elif self.direction == '卖出套保':
            rHedged = (self.rS - self.hedgeDF * self.rF).dropna()
            rUnit = (self.rS[self.hedgeDF.index] -
                     self.rF[self.hedgeDF.index]).dropna()
            rUnhedged = self.rS[self.hedgeDF]

        nvHedged = rHedged.shift(1).fillna(0).cumsum() + 1
        nvUnit = rUnit.shift(1).fillna(0).cumsum() + 1
        nvUnhedged = rUnhedged.shift(1).fillna(0).cumsum() + 1

        line = Line("套保方案净值图")
        line.add("最优套保", nvHedged.index, nvHedged.values)
        line.add("传统套保", nvUnit.index, nvUnit.values)
        line.add("未套保", nvUnhedged.index, nvUnhedged.values)
        # line.show_config()
        line.render()
class DualThrust_IntraDayStrategy(CtaTemplate):
    """DualThrust交易策略"""
    className = 'DualThrust_IntraDayStrategy'
    author = u'Leon Zhao'

    # 策略参数
    fixedSize = 2
    k1 = 0.4
    k2 = 0.4

    initDays = 10  # original value is 10
    rangeDays = 4

    # 策略变量
    barList = []  # K线对象的列表

    dayOpen = 0
    rangeHigh = 0
    rangeLow = 0
    rangeHighClose = 0
    rangeLowClose = 0
    range1 = 0
    range2 = 0

    range = 0
    longEntry = 0
    shortEntry = 0
    exitTime = time(hour=15,
                    minute=20)  #will not cover position when day close

    longEntered = False
    shortEntered = False

    # 参数列表,保存了参数的名称
    paramList = ['name', 'className', 'author', 'vtSymbol', 'k1', 'k2']

    # 变量列表,保存了变量的名称
    varList = [
        'inited', 'trading', 'pos', 'range', 'longEntry', 'shortEntry',
        'exitTime'
    ]

    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(DualThrust_IntraDayStrategy, self).__init__(ctaEngine, setting)

        self.bg = BarGenerator(self.onBar, onDayBar=self.ondayBar)
        self.am = ArrayManager()
        self.barList = []

    #----------------------------------------------------------------------
    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.bg.updateTick(tick)

    #---------calcuate range for the last several days
    def calcRange(self):
        if self.am.count >= self.rangeDays:
            self.rangeHigh = talib.MAX(self.am.high, self.rangeDays)[-1]
            self.rangeLow = talib.MIN(self.am.low, self.rangeDays)[-1]
            self.rangeHighClose = talib.MAX(self.am.close, self.rangeDays)[-1]
            self.rangeLowClose = talib.MIN(self.am.close, self.rangeDays)[-1]
            self.range1 = self.rangeHigh - self.rangeLowClose
            self.range2 = self.rangeHighClose - self.rangeLow
            if (self.range1 > self.range2):
                calcRange = self.range1
            else:
                calcRange = self.range2
        else:
            calcRange = 0
        return calcRange

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        # 撤销之前发出的尚未成交的委托(包括限价单和停止单)
        self.cancelAll()

        self.bg.updateBar(bar)

        if self.am.count < self.rangeDays:
            return
        # 计算指标数值
        self.barList.append(bar)

        if len(self.barList) <= 2:
            return
        else:
            self.barList.pop(0)
        lastBar = self.barList[-2]

        # 新的一天
        #for commodity trade at night 9 also need because some day night is canncel due to holiday
        if (lastBar.datetime.hour == 15 or
            (lastBar.datetime.hour == 14 and lastBar.datetime.minute
             == 59)) and ((bar.datetime.hour == 21 or bar.datetime.hour == 9)):
            #for commodity not trade at night:
            #if (lastBar.datetime.hour == 15 or lastBar.datetime.hour==14 and lastBar.datetime.minute==59) and ((bar.datetime.hour == 9)  ):
            # 如果已经初始化
            self.range = self.calcRange()
            self.dayOpen = bar.open
            if self.range:
                self.longEntry = bar.open + self.k1 * self.range
                self.shortEntry = bar.open - self.k2 * self.range

            #self.longEntered = False
            #self.shortEntered = False
        else:
            pass

        # 尚未到收盘
        if not self.range:
            self.range = self.calcRange()
            self.dayOpen = bar.open
            if self.range:
                self.longEntry = bar.open + self.k1 * self.range
                self.shortEntry = bar.open - self.k2 * self.range

        if True:  # Trade Time, no matter when, just send signal
            if self.pos == 0:
                self.longEntered = False
                self.shortEntered = False
                if bar.close > self.longEntry:
                    #if not self.longEntered:
                    #self.buy(self.longEntry + 2, self.fixedSize)
                    self.buy(bar.close + 2, self.fixedSize)
                elif bar.close < self.shortEntry:
                    #if not self.shortEntered:
                    #self.short(self.shortEntry - 2, self.fixedSize)
                    self.short(bar.close - 2, self.fixedSize)
                else:
                    pass

            # 持有多头仓位
            elif self.pos > 0:
                self.longEntered = True
                self.shortEntered = False
                # 多头止损单
                if bar.close < self.shortEntry:
                    #self.sell(self.shortEntry -2 , self.fixedSize)
                    self.sell(bar.close - 2, self.fixedSize)
                    # 空头开仓单
                    if not self.shortEntered:
                        #self.short(self.shortEntry -2 , self.fixedSize)
                        self.short(bar.close - 2, self.fixedSize)
            # 持有空头仓位
            elif self.pos < 0:
                self.shortEntered = True
                self.longEntered = False
                # 空头止损单
                if bar.close > self.longEntry:
                    #self.cover(self.longEntry + 2, self.fixedSize)
                    self.cover(bar.close + 2, self.fixedSize)
                    # 多头开仓单
                    if not self.longEntered:
                        #self.buy(self.longEntry + 2, self.fixedSize)
                        self.buy(bar.close + 2, self.fixedSize)
        # 收盘平仓 This will not execute
        else:
            if self.pos > 0:
                self.sell(bar.close * 0.99, abs(self.pos))
            elif self.pos < 0:
                self.cover(bar.close * 1.01, abs(self.pos))

        # 发出状态更新事件
        self.putEvent()

    #update day chart
    def ondayBar(self, dayBar):
        """收到日线推送(必须由用户继承实现)"""
        self.am.updateBar(dayBar)
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        pass

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Exemple #24
0
class KeltnerCommonStrategy(CtaTemplate):
    """DualThrust交易策略"""
    className = 'KeltnerCommonStrategy'
    author = u'Leon Zhao'

    # 策略参数
    fixedSize = 1
    kUpper = 2
    kLower = 2

    maDays = 13
    atrDays = 20  # I may use the average of ATR to reduce the range
    initDays = 100  # original value is 10
    kExit = 0.5

    # 策略变量
    barList = []  # K线对象的列表

    atrAvg = 0
    maHigh = 0
    maLow = 0
    longEntry = 0
    shortEntry = 0
    longExit = 0
    shortExit = 0
    rsiconfig = 50
    rsilen = 21

    #exitTime = time(hour=15, minute=20) #will not cover position when day close

    longEntered = False
    shortEntered = False

    # 参数列表,保存了参数的名称
    paramList = [
        'name', 'className', 'author', 'vtSymbol', 'kUpper', 'kLower', 'maDays'
    ]

    # 变量列表,保存了变量的名称
    varList = ['inited', 'trading', 'pos', 'atrAvg', 'longEntry', 'shortEntry']

    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos', 'atrAvg', 'longEntry', 'shortEntry']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(KeltnerCommonStrategy, self).__init__(ctaEngine, setting)

        self.bg = BarGenerator(self.onBar,
                               onDayBar=self.ondayBar,
                               vtSymbol=self.vtSymbol)
        self.am = ArrayManager()
        self.barList = []
        # Read Parameters from Setting files
        if 'strParams' in setting:
            self.params = setting['strParams']
            if len(self.params) >= 3:
                for p in self.params:
                    if p[0] == 'unit':
                        self.fixedSize = p[1]
                    if p[0] == 'p1':
                        self.kUpper = p[1]
                    if p[0] == 'p2':
                        self.kLower = p[1]
                    if p[0] == 'p3':
                        self.maDays = p[1]
                    if p[0] == 'p4':
                        self.atrDays = p[1]
                    if p[0] == 'p5':
                        self.initDays = p[1]
                    if p[0] == 'p6':
                        self.rsilen = p[1]
                    if p[0] == 'p7':
                        self.rsiconfig = p[1]
        else:
            # 策略参数
            self.fixedSize = 1
            self.kUpper = 2
            self.kLower = 2

            self.maDays = 13
            self.atrDays = 20
            self.initDays = 55  # original value is 10
            self.rsiconfig = 50
            self.rsilen = 21
        #print(self.fixedSize,self.kUpper,self.kLower,self.maDays,self.initDays)
        self.atrAvg = 0
        self.maHigh = 0
        self.maLow = 0
        self.longEntry = 0
        self.shortEntry = 0
        self.longExit = 0
        self.shortExit = 0

        #exitTime = time(hour=15, minute=20) #will not cover position when day close

        self.longEntered = False
        self.shortEntered = False

        self.loginterval = 15
        self.logcountdown = 0

    #----------------------------------------------------------------------
    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 writeKeyValue(self):
        """Update long short entry price(必须由用户继承实现)"""
        #print("write key")
        if self.logcountdown > self.loginterval:
            self.logcountdown = 0
            outstr = "Symbol(" + self.vtSymbol + ")Long Entry:"
            outstr = outstr + str(round(self.longEntry,
                                        2)) + ", Short Entry:" + str(
                                            round(self.shortEntry, 2))
            outstr = outstr + ",Exit:" + str(round(self.emamean, 2))
            self.writeCtaLog(u'%s' % outstr)
        self.logcountdown += 1
        self.putEvent()

    #----------------------------------------------------------------------
    def onTick(self, tick):
        """收到行情TICK推送(必须由用户继承实现)"""
        #ignore data before real open
        if (tick.datetime.hour == 8 or tick.datetime.hour == 20):
            return
        self.bg.updateTick(tick)

    def keltner(self, n, dev, ret_array=False):
        """肯特纳通道"""
        mid = self.sma(n, ret_array)
        atr = self.atr(n, ret_array)

        up = mid + atr * dev
        down = mid - atr * dev

        return up, down

    def calcUnitNo(self, atr, fixSize):
        keltnerCap = 0.0
        defaultCap = 0.0
        unitNo = 0
        cust = []
        var_sizelist = CtaTemplate.vol_Size
        var_size = 0.0
        var_Symbol = ""
        if len(var_sizelist) == 0:
            return fixSize
        else:
            var_Symbol = var_Symbol.join(
                list(filter(lambda x: x.isalpha(), self.vtSymbol)))
            var_size = float(var_sizelist[var_Symbol][0])
            if var_size - 0 < 0.01:
                return fixSize

        var_temp = 0.0
        if len(CtaTemplate.cust_Setting) > 0:
            cust = CtaTemplate.cust_Setting
        for cs in cust:
            if cs["StrategyGroup"] == "Keltner" and cs["Status"] == 'True':
                keltnerCap = cs["CaptialAmt"]
                break
            if cs["StrategyGroup"] == "Default" and cs["Status"] == 'True':
                defaultCap = cs["CaptialAmt"]
        if keltnerCap > 0:
            self.capConfig = float(keltnerCap)
        elif defaultCap > 0:
            self.capConfig = float(defaultCap)
        else:
            self.capConfig = 0.0

        unitNo = 0
        if self.capConfig - 0 < 0.0001:
            unitNo = fixSize
        elif var_size - 0 < 0.001:
            unitNo = fixSize
        else:
            unitNo = int(self.capConfig * 0.0066 / (atr * var_size))
        if unitNo < 1:
            unitNo = 1
        return unitNo

    #---------calcuate range for the last several days
    def calcKPI(self):
        if self.am.count >= self.maDays:
            self.atrAvg = self.am.atr(self.atrDays, False)
            if self.atrAvg > 0:
                self.fixedSize = self.calcUnitNo(self.atrAvg, self.fixedSize)
            hval = self.am.highArray
            lval = self.am.lowArray
            cval = self.am.closeArray
            meanval = [(h + l + c) / 3 for h, l, c in zip(hval, lval, cval)]
            sidx = len(meanval) - self.maDays
            self.emamean = np.mean(meanval[sidx:])
            #self.emamean = self.am.ema(meanval, array=False)

            tlen = len(self.am.closeArray) - self.rsilen - 2
            rsi1 = talib.RSI(self.am.closeArray[tlen:], timeperiod=self.rsilen)
            self.rsival = rsi1[-1]

            self.longEntry = self.emamean + self.atrAvg * self.kUpper
            self.shortEntry = self.emamean - self.atrAvg * self.kLower
            self.longExit = self.emamean
            self.shortExit = self.emamean

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        if self.reduceCountdown() > 0:
            return
        # 撤销之前发出的尚未成交的委托(包括限价单和停止单)
        self.cancelAll()

        self.bg.updateBar(bar)

        barLength = 0
        barLength = max(self.atrDays, self.maDays) + 1
        if self.am.count < barLength:
            return
        # 计算指标数值
        self.barList.append(bar)

        if len(self.barList) <= 2:
            return
        else:
            self.barList.pop(0)
        lastBar = self.barList[-2]

        # 新的一天
        #for commodity trade at night 9 also need because some day night is canncel due to holiday
        if (lastBar.datetime.hour == 15 or lastBar.datetime.hour == 14) and (
            (bar.datetime.hour == 21 or bar.datetime.hour == 9)):
            #for commodity not trade at night:
            #if (lastBar.datetime.hour == 15 or lastBar.datetime.hour==14 and lastBar.datetime.minute==59) and ((bar.datetime.hour == 9)  ):
            # 如果已经初始化
            self.range = self.calcKPI()
            self.dayOpen = bar.open
            #self.longEntered = False
            #self.shortEntered = False
        else:
            pass

        # 尚未到收盘
        if self.maHigh < 1:
            self.calcKPI()
        if (self.longEntry < self.emamean) or (
                self.shortEntry > self.emamean) or (abs(self.rsival) > 100):
            #print(self.kUpper,self.kLower,self.range,"b",self.longEntry,"c",bar.open,bar.datetime)
            self.writeCtaLog(
                u'long Entry less than MA or vice vesa , or RSI wrong, need to check'
            )
            return

        if True:  # Trade Time, no matter when, just send signal
            #print("KK:", self.longEntry, self.shortEntry, self.rsival)
            if self.pos == 0:
                self.longEntered = False
                self.shortEntered = False
                if bar.close > self.longEntry and self.rsival >= self.rsiconfig:
                    #if not self.longEntered:
                    #self.buy(self.longEntry + 2, self.fixedSize)
                    self.buy(bar.close, self.fixedSize)
                elif bar.close < self.shortEntry and self.rsival <= self.rsiconfig:
                    #if not self.shortEntered:
                    #self.short(self.shortEntry - 2, self.fixedSize)
                    self.short(bar.close, self.fixedSize)
                else:
                    pass

            # 持有多头仓位
            elif self.pos > 0:
                self.longEntered = True
                self.shortEntered = False
                # 多头止损单
                if bar.close < self.longExit:
                    #self.sell(self.shortEntry -2 , self.fixedSize)
                    self.sell(bar.close, self.pos)
                    # 空头开仓单

            # 持有空头仓位
            elif self.pos < 0:
                self.shortEntered = True
                self.longEntered = False
                # 空头止损单
                if bar.close > self.shortExit:
                    #self.cover(self.longEntry + 2, self.fixedSize)
                    self.cover(bar.close, self.pos)

        # 收盘平仓 This will not execute
        else:
            if self.pos > 0:
                self.sell(bar.close * 0.99, abs(self.pos))
            elif self.pos < 0:
                self.cover(bar.close * 1.01, abs(self.pos))

        self.writeKeyValue()

        # 发出状态更新事件
        self.putEvent()

    #update day chart
    def ondayBar(self, dayBar):
        """收到日线推送(必须由用户继承实现)"""
        self.am.updateBar(dayBar)
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""

        pass

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        persisttrade(self.vtSymbol, self.className, trade)
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
class ZeroStrategy(CtaTemplate):
    """基于布林通道的交易策略"""
    className = 'ZeroStrategy'
    author = u'用Python的交易员'

    initDays = 4  # 初始化数据所用的天数
    fixedSize = 1  # 每次交易的数量

    # 参数列表,保存了参数的名称
    paramList = [
        'name', 'className', 'author', 'vtSymbol', 'initDays', 'fixedSize'
    ]

    # 变量列表,保存了变量的名称
    varList = ['inited', 'trading', 'pos']

    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(ZeroStrategy, self).__init__(ctaEngine, setting)

        self.bg = BarGenerator(self.onBar, 30, self.on30minBar)  # 创建K线合成器对象
        self.am = ArrayManager()

        #最小价差变动
        self.tickadd = 1

        #有无夜盘和 相关的时间
        self.yepan = True
        self.yepanhour = 23
        self.yepanminute = 00
        self.stopcount = 0
        #断网变量相关
        self.lastbardatetime = None
        self.didinited = False

        #仓位相关
        self.posdetail = None

        #订单相关
        self.shortOrder = None
        self.buyOrder = None
        self.sellOrder = None
        self.coverOrder = None

        #撤单后跟单相关
        self.genOrder = None

        #tick策略相关全局函数
        #交易那一分钟
        self.tradeMinute = False
        #order那一分钟
        self.orderMinute = False

    #----------------------------------------------------------------------
    def on30minBar(self, bar):
        """"""

    #----------------------------------------------------------------------
    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        self.writeCtaLog(u'%s策略初始化' % self.name)
        self.getPosDetail()

        # 载入历史数据,并采用回放计算的方式初始化策略数值
        initData = self.loadBar(self.initDays)
        for bar in initData:
            self.onBar(bar)
        self.didinited = True
        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 cancelVtOrder(self, order, yuanyin, fangxiang, price=None):
        self.writeCtaLog(yuanyin + 'cancle')
        self.cancelOrder(order)
        if fangxiang == 'buy':
            self.buyOrder = None
        elif fangxiang == 'short':
            self.shortOrder = None
        elif fangxiang == 'sell':
            self.sellOrder == None
        elif fangxiang == 'cover':
            self.coverOrder = None
        else:
            self.writeCtaLog('ohmyghoa')
        if price is not None:
            self.genOrder = price

    #----------------------------------------------------------------------
    def buyTickCelve(self, tick):
        am = self.am
        fangxiang = None
        price = None
        if tick.datetime.second > 51:
            if am.diff > 0 and am.macd < 0 and am.lastmacd > 0:
                fangxiang = duo
                price = tick.bidPrice1

            elif am.macd > 0 and am.lastmacd < 0:
                fangxiang = duoping
                price = tick.askPrice1
            self.chulikaipingcang(fangxiang, price)
            # 处理错误开仓(但市场方向正确的仓),在收阳时平掉

            if self.posdetail.longPos > 0 and am.macd > 0 and am.lastmacd > 0 and self.bg.bar.open > tick.lastPrice and not self.tradeMinute:
                fangxiang = duoping
                price = tick.askPrice1
                self.chulikaipingcang(fangxiang, price)

    #----------------------------------------------------------------------
    def shortTickCelve(self, tick):
        am = self.am
        fangxiang = None
        price = None
        if tick.datetime.second > 51:
            if am.diff < 0 and am.macd > 0 and am.lastmacd < 0:

                fangxiang = kong
                price = tick.askPrice1

            elif am.macd < 0 and am.lastmacd > 0:
                fangxiang = kongping
                price = tick.bidPrice1
            self.chulikaipingcang(fangxiang, price)
        #处理错误开仓(但市场方向正确的仓),在收阳时平掉
        if self.posdetail.shortPos > 0 and am.macd < 0 and am.lastmacd < 0 and self.bg.bar.open < tick.lastPrice and not self.tradeMinute:
            fangxiang = kongping
            price = tick.bidPrice1
            self.chulikaipingcang(fangxiang, price)

    #----------------------------------------------------------------------

    def onTick(self, tick):
        """收到行情TICK推送(必须由用户继承实现)"""
        self.bg.updateTick(tick)
        self.am.updateTick(tick)

        if not self.stopcount:
            self.buyTickCelve(tick)
            self.shortTickCelve(tick)
            if tick.datetime.second == 59:
                self.checkFalseSignal(tick)

    def checkPingcang(self, bar):
        if self.didinited:
            am = self.am
            fangxiang = None
            price = None
            if self.posdetail.longPos > 0 and self.sellOrder is not None and am.lastmacd > 0 and am.mj < 0:
                price = am.tick.bidPrice1

                self.cancelVtOrder(self.sellOrder, u'必须平多', 'sell', price)
            elif self.posdetail.shortPos > 0 and self.coverOrder is not None and am.lastmacd < 0 and am.mj > 0:
                price = am.tick.askPrice1
                self.cancelVtOrder(self.coverOrder, u'必须平空', 'cover', price)
        #----------------------------------------------------------------------
    def getPosDetail(self):
        self.posdetail = self.ctaEngine.mainEngine.getPositionDetail(
            self.vtSymbol)

    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""

        #检查是否有效的交易时间
        if self.notintradingTime(bar):
            print('not')
            runDataCleaning()
            return
        detail = self.posdetail
        # if  not self.didinited:
        # posdetial = self.posdetail
        #print( detail.longPos,'long and short ',detail.shortPos )

        if not self.lastbardatetime == bar.datetime:
            self.bg.updateBar(bar)
            self.am.updateBar(bar)

        am = self.am

        self.barCelve(bar)

        #tick策略数据还原
        self.tradeMinute = False
        self.orderMinute = False

        print('zhibiao', 'macd', am.macd, 'diff', am.diff, 'mj', am.mj, 'time',
              bar.datetime, 'end')
        #检查是否断网

        self.lastbardatetime = bar.datetime

        self.am.endBar()

    #----------------------------------------------------------------------
    def barCelve(self, bar):
        self.checkCancelOrder()
        self.checkIfConnecting(bar)
        self.checkPingcang(bar)

    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""

        #orderminute
        self.orderMinute = True

        #对相应订单编号进行管理
        if order.status == STATUS_NOTTRADED:
            self.reactOrder(order, order.vtOrderID)
        elif order.status == STATUS_ALLTRADED or order.status == STATUS_CANCELLED:
            self.reactOrder(order, None)
        elif order.status == STATUS_REJECTED:
            self.writeCtaLog(STATUS_REJECTED + order.offset + order.direction)
            print('time', self.am.tick.datetime, order.orderTime, order.price,
                  self.genOrder)

        #检查需不需要跟单
        if order.status == STATUS_CANCELLED and self.genOrder is not None:
            self.writeCtaLog('ongendan' + order.offset + order.direction)
            print(self.genOrder)
            if order.offset == OFFSET_OPEN and order.direction == DIRECTION_LONG:
                self.orderBuy(self.genOrder)
                self.genOrder = None
            elif order.offset == OFFSET_OPEN and order.direction == DIRECTION_SHORT:
                self.orderShort(self.genOrder)
                self.genOrder = None
            elif (order.offset == OFFSET_CLOSE or order.offset
                  == OFFSET_CLOSETODAY or order.offset == OFFSET_CLOSEYESTERDAY
                  ) and order.direction == DIRECTION_LONG:
                self.orderCover(self.genOrder)
                self.genOrder = None
            elif (order.offset == OFFSET_CLOSE or order.offset
                  == OFFSET_CLOSETODAY or order.offset == OFFSET_CLOSEYESTERDAY
                  ) and order.direction == DIRECTION_SHORT:
                self.orderSell(self.genOrder)
                self.genOrder = None
        print 'order', order.price, order.direction, order.offset, order.status, order.vtOrderID, order.orderTime, self.pos, self.am.tick.datetime

    #----------------------------------------------------------------------
    def reactOrder(self, order, vtOrderID):
        print 'react', order.direction, order.offset

        if (order.direction == DIRECTION_LONG and order.offset == OFFSET_OPEN):
            print 'enterlong'
            self.buyOrder = vtOrderID
        elif (
                order.direction == DIRECTION_SHORT and
            (order.offset == OFFSET_CLOSE or order.offset == OFFSET_CLOSETODAY
             or order.offset == OFFSET_CLOSEYESTERDAY)):
            print('entersell')
            self.sellOrder = vtOrderID
        elif (order.direction == DIRECTION_SHORT
              and order.offset == OFFSET_OPEN):
            print 'entershort'
            self.shortOrder = vtOrderID
        elif (
                order.direction == DIRECTION_LONG and
            (order.offset == OFFSET_CLOSE or order.offset == OFFSET_CLOSETODAY
             or order.offset == OFFSET_CLOSEYESTERDAY)):
            print('enter coveer')
            self.coverOrder = vtOrderID
        else:
            print('enteranother')

    def onTrade(self, trade):
        # 发出状态更新事件
        self.reactOrder(trade, None)

        #处理tick策略
        self.tradeMinute = True

        print 'trade', trade.price, trade.direction, trade.offset, trade.tradeTime

        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass

#----------------------------------------------------------------------

    '''仓位函数'''
    def chulikaipingcang(self, fangxiang, price):
        if self.didinited:
            if fangxiang == duo:
                if self.posdetail.longPos == 0:
                    print 'buybuy'
                    self.orderBuy(price, 1)

            elif fangxiang == kong:
                if self.posdetail.shortPos == 0:
                    self.orderShort(price, 1)

            elif fangxiang == duoping:
                if self.posdetail.longPos > 0:
                    self.orderSell(price, 1)
                if self.buyOrder is not None:
                    self.cancelVtOrder(self.buyOrder, u'平多时候', 'buy')

            elif fangxiang == kongping:
                if self.posdetail.shortPos > 0:
                    self.orderCover(price, 1)
                if self.shortOrder is not None:
                    self.cancelVtOrder(self.shortOrder, u'平空时候', 'short')

        #-------------------------------------------------------
        '''订单管理类'''

    def orderBuy(self, price, volume=1, stop=False):
        if self.buyOrder is None:
            print 'buyorder'
            self.buyOrder = 0
            self.buy(price, volume, stop)

    def orderSell(self, price, volume=1, stop=False):
        if self.sellOrder is None:
            self.sellOrder = 0
            self.sell(price, volume, stop)

    def orderShort(self, price, volume=1, stop=False):
        if self.shortOrder is None:
            self.shortOrder = 0
            self.short(price, volume, stop)

    def orderCover(self, price, volume=1, stop=False):
        if self.coverOrder is None:
            self.coverOrder = 0
            self.cover(price, volume, stop)

    # ----------------------------------------------------------------------
    '''断网判断及处理函数'''
    '''目前的逻辑是根据两个bar的时间间隔来判断是否断网,一个可能的风险当市场上两笔交易的间隔长于两分钟时,会错认为也是断网了,这个在不活跃品种也较容易出现。不过一般出现这种情况较少。'''

    def closeAllPosistion(self, price):
        '''出意外如断网时平仓'''
        self.cancelAll()
        print('--closeallpos--')
        if self.pos > 0:
            self.short(price - self.tickadd, abs(self.pos))
        elif self.pos < 0:
            self.cover(price + self.tickadd, abs(self.pos))

        # ----------------------------------------------------------------------

    # ----------------------------------------------------------------------
    def iscontinueTime(self, firstdatetime, seconddatetime):
        '''判断是否为连续的时间'''
        if (firstdatetime.hour == seconddatetime.hour and firstdatetime.minute + 1 == seconddatetime.minute) \
                or (
                firstdatetime.hour == seconddatetime.hour - 1 and firstdatetime.minute == 59 and seconddatetime.minute == 0):
            return True

    # ----------------------------------------------------------------------
    def isTradeContinueTime(self, firstdatetime, seconddatetime):
        '''判断是否为连续的交易时间'''
        if self.iscontinueTime(firstdatetime, seconddatetime):
            return True
        elif firstdatetime.hour == 10 and (
                firstdatetime.minute == 15 or firstdatetime.minute == 14
        ) and seconddatetime.hour == 10 and (seconddatetime.minute == 30
                                             or seconddatetime.minute == 31):
            return True
        elif firstdatetime.hour == 11 and (
                firstdatetime.minute == 29 or firstdatetime.minute == 30
        ) and seconddatetime.hour == 13 and (seconddatetime.minute == 30
                                             or seconddatetime.minute == 31
                                             or seconddatetime.minute == 29):
            return True
        elif self.yepan and (seconddatetime.hour == 9 or
                             (seconddatetime.hour == 8
                              and seconddatetime.minute == 59)) and (
                                  firstdatetime.hour == self.yepanhour or
                                  (firstdatetime.hour == self.yepanhour - 1
                                   and firstdatetime.minute == 59)):
            return True
        elif (firstdatetime.hour == 15 or
              (firstdatetime.hour == 14 and firstdatetime.minute == 59)) and (
                  (seconddatetime.hour == 9 and seconddatetime.minute == 0) or
                  (seconddatetime.hour == 8 and seconddatetime.minute == 59)):
            return True
        elif ((firstdatetime.hour == 14 and firstdatetime.minute == 59)
              or firstdatetime.hour == 15) and (
                  seconddatetime.hour == 21 or
                  (seconddatetime.hour == 20 and seconddatetime.minute == 59)):
            return True
        elif ((firstdatetime.hour == 23 and firstdatetime.minute == 59) and
              (seconddatetime.hour == 0 and seconddatetime.minute == 0)) or (
                  (firstdatetime.hour == 0 and firstdatetime.minute == 59) and
                  ((seconddatetime.hour == 9 and seconddatetime.minute == 0))):
            return True

        else:
            print('dus conne', firstdatetime, seconddatetime)
            return False

    # ----------------------------------------------------------------------
    def handleDisConnected(self, price):
        print('DISCONNECTED', self.lastbardatetime, self.am.datetime)
        self.reSetOrder()
        self.stopcount = 15

    def notintradingTime(self, bar):
        dt = bar.datetime.time()
        if ((MORNING_START <= dt < MORNING_REST)
                or (MORNING_RESTART <= dt < MORNING_END)
                or (AFTERNOON_START <= dt < AFTERNOON_END)
                or (dt >= NIGHT_START) or (dt < NIGHT_END)):
            return False
        else:
            return True

    def checkIfConnecting(self, bar):
        if self.lastbardatetime is None:
            self.lastbardatetime = bar.datetime
        elif self.lastbardatetime == bar.datetime:
            pass
        else:
            if not self.isTradeContinueTime(self.lastbardatetime,
                                            bar.datetime):
                # 断网了,需要处理断网状态
                self.handleDisConnected(bar.close)
            # 没有断网
            else:
                if self.stopcount > 0:
                    self.stopcount -= 1

    def checkCancelOrder(self):
        if self.orderMinute:
            print('orderminute', self.buyOrder, self.shortOrder,
                  self.sellOrder, self.coverOrder)
            if self.buyOrder:
                if self.am.macd > 0:
                    self.cancelVtOrder(self.buyOrder, u"没进入绿浪", 'buy')
            if self.shortOrder:
                if self.am.macd < 0:
                    self.cancelVtOrder(self.shortOrder, u"没进入红狼", 'short')
            if self.sellOrder:
                if self.am.macd < 0:
                    self.cancelVtOrder(self.sellOrder, u'没进入红浪', 'sell')
            if self.coverOrder:
                if self.am.macd > 0:
                    self.cancelVtOrder(self.coverOrder, u'没进入绿琅', 'cover')

    def checkFalseSignal(self, tick):
        if self.tradeMinute:
            if self.posdetail.longPos > 0:
                if self.am.macd > 0:
                    self.sellFok(tick.askPrice1, 1)
            elif self.posdetail.shortPos > 0:
                if self.am.macd < 0:
                    self.coverFok(tick.bidPrice1, 1)


#回测用

    def barkaicang(self, bar):
        am = self.am
        if not self.stopcount:
            fangxiang = None
            price = bar.close
            if am.diff > 0 and am.macd < 0 and am.lastmacd > 0:
                fangxiang = duo
            elif am.macd > 0 and am.lastmacd < 0:
                fangxiang = duoping
            elif am.diff < 0 and am.macd > 0 and am.lastmacd < 0:
                fangxiang = kong
            elif am.macd < 0 and am.lastmacd > 0:
                fangxiang = kongping
            self.chulikaipingcang(fangxiang, price)

    def reSetOrder(self):
        print '---------------------reset--------------'
        self.shortOrder = None
        self.coverOrder = None
        self.buyOrder = None
        self.sellOrder = None
Exemple #26
0
class TurtleTradingStrategy(CtaTemplate):
    """海龟交易策略"""
    className = 'TurtleTradingStrategy'
    author = u'用Python的交易员'

    # 策略参数
    entryWindow = 20                    # 入场通道窗口
    exitWindow = 7                     # 出场通道窗口
    atrWindow = 20                      # 计算ATR波动率的窗口
    initDays = 1                       # 初始化数据所用的天数
    fixedSize = 100                       # 每次交易的数量

    # 策略变量
    entryUp = 0                         # 入场通道上轨
    entryDown = 0                       # 入场通道下轨
    exitUp = 0                          # 出场通道上轨
    exitDown = 0                        # 出场通道下轨
    atrVolatility = 0                   # ATR波动率
    
    longEntry = 0                       # 多头入场价格
    shortEntry = 0                      # 空头入场价格
    longStop = 0                        # 多头止损价格
    shortStop = 0                       # 空头止损价格
    
    # 参数列表,保存了参数的名称
    paramList = ['name',
                 'className',
                 'author',
                 'vtSymbol',
                 'entryWindow',
                 'exitWindow',
                 'atrWindow',
                 'initDays',
                 'fixedSize']    

    # 变量列表,保存了变量的名称
    varList = ['inited',
               'trading',
               'pos',
               'entryUp',
               'entryDown',
               'exitUp',
               'exitDown',
               'longEntry',
               'shortEntry',
               'longStop',
               'shortStop']  
    
    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(TurtleTradingStrategy, self).__init__(ctaEngine, setting)
        
        self.bg = BarGenerator(self.onBar, 60, self.onSixtyBar)
        self.am = ArrayManager()
        
    #----------------------------------------------------------------------
    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.bg.updateTick(tick)

    #----------------------------------------------------------------------

    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        self.bg.updateBar(bar)

    def onSixtyBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        self.cancelAll()
    
        # 保存K线数据
        self.am.updateBar(bar)
        if not self.am.inited:
            return
        
        # 计算指标数值
        self.entryUp, self.entryDown = self.am.donchian(self.entryWindow)
        self.exitUp, self.exitDown = self.am.donchian(self.exitWindow)
        
        if not self.pos:
            self.atrVolatility = self.am.atr(self.atrWindow)
        
        # 判断是否要进行交易
        if self.pos == 0:
            self.longEntry = 0
            self.shortEntry = 0
            self.longStop = 0
            self.shortStop = 0
            
            self.sendBuyOrders(self.entryUp)
            self.sendShortOrders(self.entryDown)
    
        elif self.pos > 0:
            # 加仓逻辑
            self.sendBuyOrders(self.longEntry)
            
            # 止损逻辑
            sellPrice = max(self.longStop, self.exitDown)
            self.sell(sellPrice, abs(self.pos), True)
    
        elif self.pos < 0:
            # 加仓逻辑
            self.sendShortOrders(self.shortEntry)
            
            # 止损逻辑
            coverPrice = min(self.shortStop, self.exitUp)
            self.cover(coverPrice, abs(self.pos), True)
        
        # 同步数据到数据库
        self.saveSyncData()        
    
        # 发出状态更新事件
        self.putEvent()


    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        pass

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        """成交推送"""
        if trade.direction == DIRECTION_LONG:
            self.longEntry = trade.price
            self.longStop = self.longEntry - self.atrVolatility * 2
        else:
            self.shortEntry = trade.price
            self.shortStop = self.shortEntry + self.atrVolatility * 2
        
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
    
    #----------------------------------------------------------------------
    def sendBuyOrders(self, price):
        """发出一系列的买入停止单"""
        t = self.pos / self.fixedSize
        
        if t < 1:
            self.buy(price, self.fixedSize, True)

        if t < 2:
            self.buy(price + self.atrVolatility*0.5, self.fixedSize, True)
                
        if t < 3:
            self.buy(price + self.atrVolatility, self.fixedSize, True)

        if t < 4:
            self.buy(price + self.atrVolatility*1.5, self.fixedSize, True)    
    
    #----------------------------------------------------------------------
    def sendShortOrders(self, price):
        """"""
        t = self.pos / self.fixedSize
        
        if t > -1:
            self.short(price, self.fixedSize, True)
        
        if t > -2:
            self.short(price - self.atrVolatility*0.5, self.fixedSize, True)
    
        if t > -3:
            self.short(price - self.atrVolatility, self.fixedSize, True)
    
        if t > -4:
            self.short(price - self.atrVolatility*1.5, self.fixedSize, True)            
class TrailingStopSignal(CtaSignal):
    """跟随出场信号"""

    # ----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        super(TrailingStopSignal, self).__init__()
        self.slMultiplier = 5
        self.bg = BarGenerator(self.onBar, 15, self.on15Bar)
        self.signalPos = 100

        # 当前持仓
        self.holdPos = 0
        # 当前atr值
        self.atrValue = 0.0
        self.intraTradeHigh = 0.0
        self.intraTradeLow = 0.0
        self.longStop = 0.0
        self.shortStop = 0.0
        self.stopExit = 0.0

        # ------------------ ----------------------------------------------------

    def onTick(self, tick):
        """Tick更新"""
        self.bg.updateTick(tick)

    # ----------------------------------------------------------------------
    def onBar(self, bar):
        """K线更新"""
        self.bg.updateBar(bar)
        # print "@onBar"

    # ----------------------------------------------------------------------
    def on15Bar(self, bar):
        # print "@on15Bar"
        if self.holdPos > 0:
            self.intraTradeHigh = max(self.intraTradeHigh, bar.high)
            self.longStop = self.intraTradeHigh - self.atrValue * self.slMultiplier

            # print bar.datetime
            # print "atrValue: ", self.atrValue
            # print "holdPos: ", self.holdPos
            # print "longStop: ",self.longStop
            # print "close: ", bar.close

            if self.longStop > bar.close:
                self.setSignalPos(0)
                # print "tailingPos: ", self.getSignalPos()

        elif self.holdPos < 0:
            self.intraTradeLow = min(self.intraTradeLow, bar.low)
            self.shortStop = self.intraTradeLow + self.atrValue * self.slMultiplier

            # print bar.datetime
            # print "atrValue: ", self.atrValue
            # print "holdPos: ", self.holdPos
            # print "shortStop: ",self.shortStop
            # print "close: ", bar.close

            if self.shortStop < bar.close:
                self.setSignalPos(0)

        elif self.holdPos == 0:
            # 空仓时返回100
            self.setSignalPos(100)
Exemple #28
0
class KkStrategy(CtaTemplate):
    """基于King Keltner通道的交易策略"""
    className = 'KkStrategy'
    author = u'张老师'

    # 策略参数
    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']

    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos', 'intraTradeHigh', 'intraTradeLow']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(KkStrategy, self).__init__(ctaEngine, setting)

        self.bg = BarGenerator(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.bg.updateTick(tick)

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        self.bg.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.saveSyncData()

        # 发出状态更新事件
        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
Exemple #29
0
class Turtle01Strategy(CtaTemplate):
    """Turtle交易策略"""
    className = 'Turtle01Strategy'
    author = u'Leon Zhao'

    # 策略参数
    initDays = 35
    fixedSize = 2
    longDays = 20
    shortDays = 20
    longExitDays = 10
    shortExitDays = 10
    atrDays = 20
    exitAtr = 2

    # 策略变量
    barList = []                # K线对象的列表

    newTradeDay = False
    lastLongEntry = 0
    lastLongTime = 0
    lastShortEntry = 0
    lastShortTime = 0
    upperChannel = 0
    lowerChannel = 0
    longEntry = 0
    shortEntry = 0
    entryPrice = 0
    entryDirection = 0 
    entryUsage = 'Turtle'
    entryUnitNo = 0
    longExit = 0
    shortExit = 0
    longAtrExit = 0
    shortAtrExit = 0
    longChannelExit = 0
    shortChannelExit = 0
    atrValue = 0
    rangeLow = 0
    exitTime = time(hour=15, minute=20) #will not cover position when day close

    longEntered = False
    shortEntered = False

    # 参数列表,保存了参数的名称
    paramList = ['name',
                 'className',
                 'author',
                 'vtSymbol',
                 'longDays',
                 'shortDays']    

    # 变量列表,保存了变量的名称
    varList = ['inited',
               'trading',
               'pos',
               'longEntry',
               'shortEntry',
               'exitTime'] 
    
    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos','entryPrice','entryDirection','entryUsage','entryUnitNo']    

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(Turtle01Strategy, self).__init__(ctaEngine, setting) 
        
        self.bg = BarGenerator(self.onBar,onDayBar = self.ondayBar)
        self.am = ArrayManager(max(self.longDays,self.shortDays,self.atrDays)+1)
        self.barList = []

    #----------------------------------------------------------------------
    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)
        # No need to add calculation of the Turtle Channel on Start, it may not change over days.
        #self.calcPrepare()
        self.putEvent()

    def readLastTrade(self,):
        #read last trade data from database
        pass
    def calcPrepare(self):
        #calculate initials of the strategy
        barLength = 0 
        barLength = max(self.longDays,self.shortDays,self.atrDays) 
        if self.am.count < barLength + 1:
            return   
        #self.atrValue = talib.ATR(self.am.high, self.am.low, self.am.close,self.atrDays)[-1] 
        self.atrValue = self.am.atr(self.atrDays,False)
        # = atrLine[-1]
       
        self.upperChannel = talib.MAX(self.am.high,self.longDays)[-1]
        self.lowerChannel = talib.MIN(self.am.low,self.shortDays)[-1]
        self.longChannelExit = talib.MIN(self.am.low,self.longExitDays)[-1]
        self.shortChannelExit = talib.MAX(self.am.high,self.shortExitDays)[-1]

    def calcKPI(self):    
        if self.pos>0:
                self.longAtrExit = int(self.lastLongEntry - 2*self.atrValue)
                if self.longAtrExit > self.longChannelExit:
                    self.longExit = self.longAtrExit
                else:
                    self.longExit = self.longChannelExit
                                 
                if self.entryUnitNo == 1:
                    self.longEntry = int(self.lastLongEntry + self.atrValue)
                elif self.entryUnitNo == 2:
                    self.longEntry = int(self.lastLongEntry +0.5*self.atrValue)
                else:
                    self.longEntry = 0
        elif self.pos == 0:
                self.longEntry = self.upperChannel
                self.shortEntry = self.lowerChannel
        else:
            self.shortAtrExit = int(self.lastShortEntry + 2*self.atrValue)
            if self.shortAtrExit < self.shortChannelExit:
                self.shortExit = self.shortAtrExit
            else:
                self.shortExit = self.shortChannelExit
            if self.entryUnitNo == 1:
                self.shortEntry = int(self.lastShortEntry-self.atrValue)
            elif self.entryUnitNo == 2:
                self.shortEntry = int(self.lastShortEntry-0.5*self.atrValue)
            else:
                self.shortEntry = 0
             
          
    #----------------------------------------------------------------------
    def onStop(self):
        """停止策略(必须由用户继承实现)"""
        self.writeCtaLog(u'%s策略停止' %self.name)
        self.putEvent()

    #----------------------------------------------------------------------
    def onTick(self, tick):
        """收到行情TICK推送(必须由用户继承实现)"""
        self.bg.updateTick(tick)          
        
    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        # 撤销之前发出的尚未成交的委托(包括限价单和停止单)
        self.cancelAll()

        self.bg.updateBar(bar)
              
        barLength = 0 
        barLength = max(self.longDays,self.shortDays,self.atrDays) 

        if self.am.count < barLength + 1:
            return              
        # 计算指标数值
        self.barList.append(bar)
        
        if len(self.barList) <= 2:
            return
        else:
            self.barList.pop(0)
        lastBar = self.barList[-2]
        
        # 新的一天
        if (lastBar.datetime.hour == 15 or (lastBar.datetime.hour==14 and lastBar.datetime.minute==59)) and ((bar.datetime.hour == 21) or (bar.datetime.hour == 9)):
            # 如果已经初始化
            if not self.upperChannel :
                #do things:
                self.calcPrepare()
            else:
                pass
            
        if self.pos == 0:
            self.lastLongTime = 0
            self.lastShortTime = 0
            self.entryUnitNo = 0
        self.calcKPI()
        
        if self.pos > 0:
            #self.sell(self.longExit,self.fixedSize,stop)
            if  bar.close < self.longExit:
                self.sell(bar.close-2,self.pos)
            elif bar.close > self.longEntry and self.longEntry > 0 :
                self.buy(bar.close+2,self.fixedSize)
            else:
                pass
        elif self.pos == 0:
            #self.entryUnitNo = 0
            if bar.close > self.longEntry and self.longEntry > 0 :
                self.buy(bar.close+2,self.fixedSize)
            elif bar.close < self.shortEntry and self.shortEntry > 0:
                self.short(bar.close -2, self.fixedSize)
            else:
                pass
        else:
            if bar.close < self.shortEntry and self.shortEntry > 0 :
                self.short(bar.close-2,self.fixedSize)
            elif bar.close > self.shortExit:
                self.cover(bar.close+2,abs(self.pos))
            else:
                pass                        

        # 发出状态更新事件
        self.putEvent()
    #update day chart
    def ondayBar(self, dayBar):
        """收到日线推送(必须由用户继承实现)"""
        self.am.updateBar(dayBar)
        self.calcPrepare()
        # 发出状态更新事件
        self.putEvent() 
    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        #if order.status == STATUS_ALLTRADED and self.pos != 0:
            # How do I know the last trade is open or exit?
        #    self.entryUnitNo = self.entryUnitNo + 1

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        if trade.direction == DIRECTION_LONG and trade.offset == OFFSET_OPEN:
            self.entryUnitNo = self.entryUnitNo + 1
            self.lastLongEntry = trade.price
            self.entryPrice = trade.price
            self.entryDirection = DIRECTION_LONG            
        elif trade.direction == DIRECTION_SHORT and trade.offset == OFFSET_OPEN:
            self.entryUnitNo = self.entryUnitNo + 1
            self.lastShortEntry = trade.price 
            self.entryPrice = trade.price
            self.entryDirection = DIRECTION_SHORT                         
        elif (trade.offset == OFFSET_CLOSE or trade.offset == OFFSET_CLOSETODAY ):
            #print(self.pos)
            self.entryUnitNo = 0
            self.lastLongEntry = 0
            self.lastShortEntry = 0
            self.entryPrice = 0
            self.entryDirection = OFFSET_CLOSE            
        else:
            pass
        self.putEvent() 

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
class TripleMAStrategy04(CtaTemplate):
    """基于三均线的交易策略"""
    className = 'TripleMAStrategy04'
    author = 'Y.Raul'

    # 策略参数
    initDays = 10  # 初始化数据所用的天数
    addPos = True  # 加仓开关
    windowCheck = True #交易窗口开关
    openWindowSize = 5 #开盘观察窗口,单位分钟
    closeWindowSize = 10 #收盘平仓窗口,单位分钟
    minDiff = 1 #最小变动单位

    # 策略变量
    # 仓位设置
    stepPos = 1  # 每次交易的数量
    maxPos = 4  # 仓位上限
    addPosRatio = 3
    # 均线设置
    maWindow1 = 10
    maWindow2 = 20
    maWindow3 = 120
    maWindow4 = 5
    atrWindow = 30  # ATR窗口数
    
    # 出场设置
    exitOnTrailingStop = 2  # Trailing Stop 距离
    exitOnLossStop = 3 # Loss Stop 距离
    
    # 价格相关变量
    intraTradeHigh = 0  # 持仓期内的最高点
    intraTradeLow = 0  # 持仓期内的最低点
    longStop = 0  # 多头止损
    shortStop = 0  # 空头止损
    longEntry = 0  # 多头开仓
    shortEntry = 0
    avgEntryPrice = 0
    
    # 指标相关变量
    # ma次新值
    ma10 = 0
    ma20 = 0
    ma30 = 0
    # ma最新值
    ma11 = 0
    ma21 = 0
    ma31 = 0
    atrValue = 0  # ATR指标数值

    orderList = []  # 保存委托代码的列表

    # 参数列表,保存了参数的名称
    paramList = ['name',
                 'className',
                 'author',
                 'vtSymbol',
                 'maWindow1',
                 'maWindow2',
                 'maWindow3',
                 'maWindow4'
                 'initDays',
                 'addPos',
                 'stepPos',
                 'maxPos',
                 'exitOnTrailingStop',
                 'exitOnLossStop',
                 ]

    # 变量列表,保存了变量的名称
    varList = ['inited',
               'trading',
               'pos',
               'ma10',
               'ma11',
               'ma20',
               'ma21',
               'ma30',
               'ma31',
               'atrValue',
               'avgPrice']
    # 同步列表
    syncList = ['pos']

    # ----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(TripleMAStrategy04, self).__init__(ctaEngine, setting)
        self.EntryPriceList = []
        self.bm = BarGenerator(self.onBar, 5, self.onFiveBar)
        self.am = ArrayManager(size= self.maWindow3 + 30)
    # ----------------------------------------------------------------------
    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.curDateTime = tick.datetime
        # 计算交易时间和平仓时间
        if self.windowCheck == True:
            self.__timeWindow(tick.datetime)
        else:
            self.tradeWindow = True

        self.bm.updateTick(tick)

    # ----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        # 更新策略执行的时间(用于回测时记录发生的时间)
        # 回测数据传送的bar.datetime,为bar的结束时间
        self.curDateTime = bar.datetime
        # 计算交易时间和平仓时间
        if self.windowCheck == True:
            self.__timeWindow(bar.datetime)
        else:
            self.tradeWindow = True

        self.bm.updateBar(bar)

    # ----------------------------------------------------------------------
    def onFiveBar(self, bar):
        """收到5分钟K线"""
        # 保存K线数据
        self.am.updateBar(bar)
        if not self.am.inited:
            return
        # print bar.datetime

        # 撤销之前发出的尚未成交的委托(包括限价单和停止单)
        self.cancelAll()

        import talib
        # 计算指标数值
        ma3Array = self.am.sma(self.maWindow3, True)
        self.ma30 = round(ma3Array[-2])
        self.ma31 = round(ma3Array[-1])
        ma3_ma5 = round(talib.SMA(ma3Array, self.maWindow4)[-1])

        ma1Array = self.am.sma(self.maWindow1, True)
        self.ma10 = round(ma1Array[-2])
        self.ma11 = round(ma1Array[-1])
        ma1_ma5 = talib.SMA(ma1Array, self.maWindow4)[-1]

        ma2Array = self.am.sma(self.maWindow2, True)
        self.ma20 = round(ma2Array[-2])
        self.ma21 = round(ma2Array[-1])

        self.atrValue = round(self.am.atr(self.atrWindow))

        # 判断是否要进行交易
        # 当前无仓位,发送OCO开仓委托
        if self.pos == 0 :
            self.intraTradeHigh = bar.high
            self.intraTradeLow = bar.low
            if self.tradeWindow:
                # 开多, bar.close > MA120,MA10 > MA120,MA10 上穿MA20,MA10、MA120向上
                if bar.close > self.ma31 and self.ma11 > self.ma31 \
                        and self.ma10 < self.ma20 and self.ma11 > self.ma21\
                        and self.ma31 > ma3_ma5 and self.ma11 > ma1_ma5:

                    self.longEntry = bar.close
                    self.buy(self.longEntry, self.stepPos, True)

                    # lastEntryPrice = self.longEntry
                    self.LossStopPrice = round(self.longEntry * (100.0 -self.exitOnLossStop)/100)
                    self.EntryPriceList.append(self.longEntry)

                    # 记录log
                    log = "\n Trading: {0}\n".format(self.trading)+\
                        "{0} Buy : bar.close: {1};\n".format(bar.datetime, bar.close) + \
                          " ma10:{0}; ma11:{1}; ma20:{2}; ma21:{3}; ma30:{4};ma31:{5}\n".format(self.ma10,self.ma11,self.ma20,self.ma21,self.ma30,self.ma31) + \
                        "ma1_ma5:{0}; ma3_ma5:{1}\n".format(ma1_ma5,ma3_ma5)+\
                        "LossStopPrice:{0}\n".format(self.LossStopPrice)
                    self.writeCtaLog(log)

                # 开空, bar.close < MA120,MA10 < MA120,MA10 下穿MA20, MA10,MA120向下
                elif bar.close < self.ma31 and self.ma11 < self.ma31 \
                        and self.ma10 > self.ma20 and self.ma11 < self.ma21\
                        and self.ma31 < ma3_ma5 and self.ma11 < ma1_ma5:

                    self.shortEntry = bar.close
                    self.short(self.shortEntry, self.stepPos, True)
                    # lastEntryPrice = self.shortEntry
                    self.LossStopPrice = round(self.shortEntry * (100.0  + self.exitOnLossStop)/100)
                    self.EntryPriceList.append(self.shortEntry)

                    # 记录log
                    log = "\n Trading: {0}\n".format(self.trading)+\
                        "{0} Short : bar.close: {1};\n".format(bar.datetime, bar.close) + \
                          " ma10:{0}; ma11:{1}; ma20:{2}; ma21:{3}; ma30:{4};ma31:{5}\n".format(self.ma10, self.ma11,
                                                                                                self.ma20, self.ma21,
                                                                                                self.ma30, self.ma31) + \
                          "ma1_ma5:{0}; ma3_ma5:{1}\n".format(ma1_ma5, ma3_ma5) + \
                          "LossStopPrice:{0}\n".format(self.LossStopPrice)
                    self.writeCtaLog(log)
            # return
        else:
            if self.tradeWindow:
                # Trailing Stop 跟随止损
                if self.exitOnTrailingStop:
                    # 持有多头仓位
                    if self.pos > 0 and self.tradeWindow:

                        self.intraTradeHigh = max(self.intraTradeHigh, bar.high)
                        self.intraTradeLow = bar.low
                        self.longStop = round(self.intraTradeHigh - self.atrValue * self.exitOnTrailingStop)

                        if bar.close < self.longStop:
                            self.sell(bar.close, abs(self.pos), True)

                            # 记录log
                            log = "\n{0} Sell(Trailing Stop) : bar.close: {1};\n".format(bar.datetime, bar.close) + \
                                "intraTradeHigh:{0}; atrValue:{1}; dev: {2}\n".format(self.intraTradeHigh,self.atrValue,self.exitOnTrailingStop)+\
                                  "LongStop:{0}\n".format(self.longStop)
                            self.writeCtaLog(log)
                            self.putEvent()

                            self.EntryPriceList = []
                            return
                    # 持有空头仓位
                    if self.pos < 0 and self.tradeWindow:

                        self.intraTradeHigh = bar.high
                        self.intraTradeLow = min(self.intraTradeLow, bar.low)
                        self.shortStop = round(self.intraTradeLow + self.atrValue * self.exitOnTrailingStop)

                        if bar.close > self.shortStop:
                            self.cover(bar.close, abs(self.pos), True)
                            # 记录log
                            log = "\n{0} Cover(Trailing Stop) : bar.close: {1};\n".format(bar.datetime, bar.close) + \
                                  "intraTradeLow:{0}; atrValue:{1}; dev: {2}\n".format(self.intraTradeLow, self.atrValue,
                                                                                        self.exitOnTrailingStop) + \
                                  "LongStop:{0}\n".format(self.longStop)
                            self.writeCtaLog(log)
                            self.putEvent()

                            self.EntryPriceList = []
                            return

                # Loss Stop 固定止损
                if self.exitOnLossStop:
                        # 持有多头仓位
                    if self.pos > 0 and bar.close < self.LossStopPrice:
                        # 记录log
                        log = "\n{0} Sell(Stop Loss) : bar.close: {1};\n".format(bar.datetime, bar.close) + \
                              "LossStopPrice:{0}\n".format(self.LossStopPrice) + \
                            "Ratio:{0}%\n".format((1 - bar.close/self.LossStopPrice)*100)
                        self.writeCtaLog(log)

                        self.sell(bar.close, abs(self.pos), True)
                        self.putEvent()

                        self.EntryPriceList = []
                        return
                        # 持有空头仓位
                    if self.pos < 0 and bar.close > self.LossStopPrice:
                        # 记录log
                        log = "\n{0} Cover(Stop Loss) : bar.close: {1};\n".format(bar.datetime, bar.close) + \
                              "LossStopPrice:{0}\n".format(self.LossStopPrice) +\
                        "Ratio:{0}%\n".format((1 - bar.close / self.LossStopPrice) * 100)
                        self.writeCtaLog(log)

                        self.cover(bar.close, abs(self.pos), True)
                        self.putEvent()

                        self.EntryPriceList = []
                        return

                # 加仓
                if self.addPos and (self.maxPos - abs(self.pos) > 0):
                    print self.pos, (self.maxPos - abs(self.pos) )
                    print self.EntryPriceList

                    lastEntryPrice = self.EntryPriceList[-1]
                    # 固定百分比加仓
                    addPosOnPips= round(lastEntryPrice* self.addPosRatio/100)

                    self.writeCtaLog(u'\n 加仓判断:{0},当前仓位:{1}'.format(bar.datetime, self.pos))
                    # 加多仓
                    if self.pos > 0 \
                            and bar.close >= lastEntryPrice + addPosOnPips* self.minDiff:
                        # 记录log
                        self.writeCtaLog(u'\n {0},加仓多单{1}手,价格:{2}'.format(bar.datetime, self.stepPos, bar.close))
                        self.buy(bar.close, self.stepPos, True)

                        # 更新开仓价格
                        lastEntryPrice = bar.close
                        self.EntryPriceList.append(lastEntryPrice)
                        self.avgEntryPrice = sum(self.EntryPriceList)/len(self.EntryPriceList)

                        # 更新固定止损价
                        self.LossStopPrice = round( self.avgEntryPrice* (100.0 - self.exitOnLossStop) / 100)
                        self.writeCtaLog(u'\n 更新固定止损价:{0},最新仓位:{1}'.format(self.LossStopPrice,self.pos))

                        return

                    # 加空仓
                    if self.pos < 0 \
                            and bar.close <= (lastEntryPrice + addPosOnPips*self.minDiff):

                        self.writeCtaLog(u'{0},加仓空单{1}手,价格:{2}'.format(bar.datetime, self.stepPos, bar.close))
                        self.short(bar.close, self.stepPos, True)

                        # 更新开仓价格
                        lastEntryPrice = bar.close
                        self.EntryPriceList.append(lastEntryPrice)
                        self.avgEntryPrice = (sum(self.EntryPriceList)) / len(self.EntryPriceList)

                        # 更新固定止损价
                        self.LossStopPrice = round(self.avgEntryPrice * (100.0 + self.exitOnLossStop) / 100)
                        self.writeCtaLog(u'\n 更新固定止损价:{0},最新仓位:{1}'.format(self.LossStopPrice, self.pos))
                        return

        # 执行收盘前平仓检查
        # self.__dailyCloseCheck(bar)
        # 发出状态更新事件
        self.putEvent()

        # ----------------------------------------------------------------------

    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        log = u'\n OnOrder()更新,orderID:{0},{1},totalVol:{2},tradedVol:{3},offset:{4},price:{5},direction:{6},status:{7},orderTime: {7}'\
                         .format(order.orderID, order.vtSymbol, order.totalVolume,order.tradedVolume,
                                 order.offset, order.price, order.direction, order.status, order.orderTime)
        self.writeCtaLog(log)
        self.putEvent()
    # ----------------------------------------------------------------------
    def onTrade(self, trade):

        log = u'\n OnTrade()更新,orderID:{0},{1},Vol:{2},price:{3},direction:{4},tradeTime:{5}' \
            .format(trade.orderID, trade.vtSymbol, trade.volume,trade.price, trade.direction,trade.tradeTime)
        self.writeCtaLog(log)
        # 发出状态更新事件
        self.putEvent()

    # ----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        log = u'\n OnStopOrder()停止单更新,stopOrderID:{0},Vol:{1},price:{2},direction:{3},status:{4}' \
            .format(so.stopOrderID, so.volume,so.price, so.direction,so.status)
        self.writeCtaLog(log)

    def __timeWindow(self, dt):
        """交易与平仓窗口"""

        # 螺纹钢交易窗口 避开早盘和夜盘的前5分钟,防止隔夜跳空。
        # 日内平仓窗口
        self.closeWindow = False
        # 交易窗口
        self.tradeWindow = False
        # 开盘窗口
        self.openWindow = False

        # 开市期头5分钟波动较大
        if (dt.hour == 9 or dt.hour == 21) and dt.minute < self.openWindowSize:
            self.openWindow = False
            return

        # 日盘
        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 < 60 - self.closeWindowSize:
                self.tradeWindow = True
                return
            else:
                self.closeWindow = True
                return

        # 夜盘

        if dt.hour == 21 and dt.minute >= 0:
            self.tradeWindow = True
            return

        if dt.hour == 22 and dt.minute < 60 - self.closeWindowSize:
            self.tradeWindow = True
            return
        else:
            self.closeWindow = True
            return

    def __dailyCloseCheck(self, bar):
        """每天收盘前检查,如果是亏损单,则平掉"""

        if self.pos == 0 :
            return False

        if not self.closeWindow:
            return False

        # 撤销未成交的订单
        self.cancelAll()
        log = u'{0},收盘前{1}分钟,撤单及平仓'.format(bar.datetime,self.closeWindowSize)
        self.writeCtaLog(log)
        self.avgEntryPrice = (sum(self.EntryPriceList)) / len(self.EntryPriceList)
        # 记录log
        log = "\n{0} __dailyCloseCheck : bar.close: {1};\n".format(bar.datetime, bar.close) + \
              "avgPrice:{0}\n".format(self.avgEntryPrice)+\
            "pos:{0}\n".format(self.pos)

        self.writeCtaLog(log)

        # 强制平仓
        if self.pos > 0 and bar.close < self.avgEntryPrice:
            self.writeCtaLog(u'强制日内平亏损多仓')

            # 降低两个滑点
            self.sell(bar.close-2*self.minDiff, abs(self.pos),True )
            # 记录log
            log = "\n{0} Sell(Force) : bar.close: {1};\n".format(bar.datetime, bar.close) + \
                  "entryPrice:{0}\n".format(bar.close - 2 * self.minDiff)
            self.writeCtaLog(log)

            return True

        if self.pos < 0 and bar.close > self.avgEntryPrice:
            self.writeCtaLog(u'强制日内平亏损空仓')

            self.cover(bar.close+2*self.minDiff, abs(self.pos),True )
            # 记录log
            log = "\n{0} Cover(Force) : bar.close: {1};\n".format(bar.datetime, bar.close) + \
                  "forcePrice:{0}\n".format(bar.close - 2 * self.minDiff)
            self.writeCtaLog(log)
            return True

        return True
class tempStrategy(CtaTemplate):
    """双指数均线策略Demo"""
    className = 'DoubleMaStrategy'
    author = u'用Python的交易员'

    # 策略参数
    fastWindow = 12  # 快速均线参数
    slowWindow = 26  # 慢速均线参数
    initDays = 0  # 初始化数据所用的天数

    # 策略变量
    fastMa0 = EMPTY_FLOAT  # 当前最新的快速EMA
    fastMa1 = EMPTY_FLOAT  # 上一根的快速EMA

    slowMa0 = EMPTY_FLOAT
    slowMa1 = EMPTY_FLOAT
    huice = False
    # 参数列表,保存了参数的名称
    paramList = [
        'name', 'className', 'author', 'vtSymbol', 'fastWindow', 'slowWindow'
    ]

    # 变量列表,保存了变量的名称
    varList = [
        'inited', 'trading', 'pos', 'fastMa0', 'fastMa1', 'slowMa0', 'slowMa1'
    ]

    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(tempStrategy, self).__init__(ctaEngine, setting)
        self.bg = BarGenerator(self.onBar)
        self.am = ArrayManager()
        self.lastzhibiao = zhibiao(0, 0, 0)
        self.celve0 = zerocelve()
        # self.celve1 = ceshi()
        self.tickCelvezu = [self.celve0]
        self.barCelvezu = [self.celve0]

        self.tickadd = 1

        #断网恢复变量
        self.stopcount = None

        #交易时间和监控联网状态变量
        self.yepan = False
        self.yepanhour = None
        self.yepanminute = None
        self.lastbardatetime = None

        self.tradetime = None

        #控制开仓和平仓稳定变量
        self.tradecount = 0

        self.tradingcelve = [self.celve0]

        # 注意策略类中的可变对象属性(通常是list和dict等),在策略初始化时需要重新创建,
        # 否则会出现多个策略实例之间数据共享的情况,有可能导致潜在的策略逻辑错误风险,
        # 策略类中的这些可变对象属性可以选择不写,全都放在__init__下面,写主要是为了阅读
        # 策略时方便(更多是个编程习惯的选择)

    #----------------------------------------------------------------------
    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略初始化')

        initData = self.loadBar(self.initDays)
        for bar in initData:
            self.onBar(bar)
        self.am.inited = True
        self.putEvent()

    #----------------------------------------------------------------------
    def onStart(self):
        """启动策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略启动')
        self.putEvent()

    #----------------------------------------------------------------------
    def closeAllPosistion(self, price):
        print('--closeallpos--')
        if self.pos > 0:
            self.short(price - self.tickadd, abs(self.pos))
        elif self.pos < 0:
            self.cover(price + self.tickadd, abs(self.pos))

        # ----------------------------------------------------------------------
    def datetimePlusMinute(self, datelatime, minute):
        newdatetime = datetime.now()
        if datelatime.minute + minute < 60:
            newdatetime.minute = datelatime.minute + minute
        else:
            newdatetime.hour = datelatime.hour + 1
            newdatetime.minute = datelatime.minute + minute - 60
        return newdatetime

    # ----------------------------------------------------------------------
    def iscontinueTime(self, firstdatetime, seconddatetime):
        if (firstdatetime.hour == seconddatetime.hour and firstdatetime.minute + 1 == seconddatetime.minute) \
                or (
                firstdatetime.hour == seconddatetime.hour - 1 and firstdatetime.minute == 59 and seconddatetime.minute == 0):
            return True

    # ----------------------------------------------------------------------
    def isTradeContinueTime(self, firstdatetime, seconddatetime):
        if self.iscontinueTime(firstdatetime, seconddatetime):
            return True
        elif firstdatetime.hour == 10 and (
                firstdatetime.minute == 15 or firstdatetime.minute == 14
        ) and seconddatetime.hour == 10 and seconddatetime.minute == 30:
            return True
        elif firstdatetime.hour == 11 and (
                firstdatetime.minute == 29 or firstdatetime.minute == 30
        ) and seconddatetime.hour == 13 and seconddatetime.minute == 30:
            return True
        elif self.yepan:
            if firstdatetime.hour == self.yepanhour and (
                    firstdatetime.minute == self.yepanminute
                    or firstdatetime.minute == self.yepanminute - 1
            ) and seconddatetime.hour == 9 and seconddatetime.miute == 0:
                return True
        else:
            return False

    # ----------------------------------------------------------------------

    def tickcelve(self, zhibiao, price, tick):
        for celve in self.tickCelvezu:
            xinhao = celve.celveOntick(zhibiao, self.lastzhibiao)
            if xinhao == 100:
                print(price, 'kaicangduo', tick.datetime)
            if xinhao == 50:
                print(price, 'pingcang', tick.datetime)
            if xinhao == 200:
                print(price, 'kongcang', tick.datetime)
            if xinhao == 250:
                print(price, 'pingkongcang', tick.datetime)
            self.chulikaipingcang(xinhao, price)
            # ----------------------------------------------------------------------

    def barcelve(self, zhibiao, price):
        for celve in self.barCelvezu:
            xinhao = celve.celveOnbar(zhibiao, self.lastzhibiao)
            if xinhao == 100:
                print('kaicangduo,bar')
            if xinhao == 50:
                print('pingcang,bar')
            self.chulikaipingcang(xinhao, price)

    # ----------------------------------------------------------------------

    def chulikaipingcang(self, celve, price):
        # if celve == 100:
        #     self.buy(price,1)
        selfpos = 0
        if celve != 0 and celve is not None:
            print('nowposis', self.pos, 'celveis', celve, 'andpriceis', price)
        if self.pos == 0 and celve == 100:
            if self.pos == 0:
                # self.weituopos = 1
                self.buy(price + 100, 1)
                # 如果有空头持仓,则先平空,再做多
            elif self.pos < selfpos:
                # self.weituopos = 1
                self.cover(price, 1)
                self.buy(price, 1)
        elif self.pos == 1 and celve == 50:
            if self.pos > selfpos:
                # self.weituopos = 0
                self.sell(price - 1, 1)
        elif self.pos == 0 and celve == 200:
            if self.pos == selfpos:
                # self.weituopos = -1
                print('iamkonging')
                self.short(price - 1, 1)
            elif self.pos > selfpos:
                self.sell(price, 1)
                self.short(price, 1)
                # self.weituopos = -1
        elif self.pos == -1 and celve == 250:
            # self.weituopos += 1
            self.cover(price + 100, 1)
        # ----------------------------------------------------------------------

    def onStop(self):
        """停止策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略停止')
        self.putEvent()

    #----------------------------------------------------------------------
    def onTick(self, tick):
        """收到行情TICK推送(必须由用户继承实现)"""
        self.bg.updateTick(tick)
        zhibiao = self.am.updateTick(tick)
        if not self.tradecount:
            self.tickcelve(zhibiao, tick.lastPrice, tick)
        elif tick.datetime.second > 55:
            print('in tradecount', tick.datetime)
            self.tickcelve(zhibiao, tick.lastPrice, tick)

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        if bar.datetime.hour == 14 and bar.datetime.minute == 59:
            self.closeAllPosistion(bar.close)
        bartime = bar.datetime

        # 处理bar上的刚开仓
        self.handleTradeCount()

        if self.lastbardatetime is None:
            self.lastbardatetime = bar.datetime
        else:
            if not self.isTradeContinueTime(self.lastbardatetime,
                                            bar.datetime):
                #断网了,需要处理断网状态
                self.handleDisConnected(bar.close)
            #没有断网
            else:
                if self.stopcount > 0:
                    self.stopcount -= 1

        am = self.am
        am.updateBar(bar)
        self.bg.updateBar(bar)
        # if not am.inited:
        #     print('retr')
        # return
        # 计算快慢均线
        self.celve0.nowtime = bar.datetime
        diff, dea, macd = am.diff, am.dea, am.macd
        jisuan = zhibiao(diff, dea, macd)
        self.barcelve(jisuan, bar.close)

        # 金叉和死叉的条件是互斥
        # 所有的委托均以K线收盘价委托(这里有一个实盘中无法成交的风险,考虑添加对模拟市价单类型的支持)

        self.lastzhibiao = am.endBar()
        # print self.lastzhibiao.diff,self.lastzhibiao.dea
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def handleTradeCount(self):
        if self.tradecount > 0:
            self.tradecount -= 1

    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        # 对于无需做细粒度委托控制的策略,可以忽略onOrder
        print 'order', order.price, order.direction, order.offset, order.orderTime
        pass

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        """收到成交推送(必须由用户继承实现)"""
        # 对于无需做细粒度委托控制的策略,可以忽略onOrder\
        if trade.direction == u'多' and trade.offset == u'开仓':
            #self.sell(trade.price - 4, 1, stop=True)
            self.tradecount = 5
            print('kaiduo')
        if trade.direction == u'空' and trade.offset == u'开仓':
            #self.cover(trade.price + 4, 1, stop=True)
            self.tradecount = 5
            print('kaikong')

        if trade.direction == u'多' and trade.offset != u'开仓':
            self.cancelAll()
            self.celve0.cangwei += trade.volume
            print('pingkong')
        if trade.direction == u'空' and trade.offset != u'开仓':
            self.cancelAll()
            self.celve0.cangwei -= trade.volume
            print('pingduo')

        print 'trade', trade.price, trade.direction, trade.offset, trade.tradeTime
        pass

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass

    def handleDisConnected(self, price):
        print('DISCONNECTED')
        self.closeAllPosistion(price)
        self.stopcount = 15
Exemple #32
0
class TestPriceStrategy(CtaTemplate):
    """Turtle交易策略"""
    className = 'TestPriceStrategy'
    author = u'Leon Zhao'

    # 策略参数

    fixedSize = 1
    longDays = 20
    shortDays = 20
    longExitDays = 10
    shortExitDays = 10
    initDays = 35
    atrDays = 20
    exitAtr = 2

    # 策略变量
    barList = []  # K线对象的列表

    newTradeDay = False
    lastLongEntry = 0
    lastLongTime = 0
    lastShortEntry = 0
    lastShortTime = 0
    upperChannel = 0
    lowerChannel = 0
    longEntry = 0
    shortEntry = 0
    entryPrice = 0
    entryDirection = 0
    entryUsage = 'Turtle'
    entryUnitNo = 0
    longExit = 0
    shortExit = 0
    longAtrExit = 0
    shortAtrExit = 0
    longChannelExit = 0
    shortChannelExit = 0
    atrValue = 0
    entryAtr = 0
    rangeLow = 0
    exitTime = time(hour=15,
                    minute=20)  #will not cover position when day close

    longEntered = False
    shortEntered = False

    capConfig = 0.0
    onTradeCnt = 0
    previousTrade = 0
    bookTime = datetime.now()

    # 参数列表,保存了参数的名称
    paramList = [
        'name', 'className', 'author', 'vtSymbol', 'longDays', 'shortDays'
    ]

    # 变量列表,保存了变量的名称
    varList = [
        'inited', 'trading', 'pos', 'longEntry', 'shortEntry', 'exitTime',
        'upperChannel', 'lowerChannel'
    ]

    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = [
        'pos', 'entryPrice', 'entryDirection', 'entryUsage', 'entryUnitNo',
        'lastLongEntry', 'lastShortEntry', 'entryAtr'
    ]

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(TestPriceStrategy, self).__init__(ctaEngine, setting)

        self.bg = BarGenerator(self.onBar,
                               onDayBar=self.ondayBar,
                               vtSymbol=self.vtSymbol)
        self.am = ArrayManager(
            max(self.longDays, self.shortDays, self.atrDays) + 1)
        self.barList = []
        if 'strParams' in setting:
            self.params = setting['strParams']
            if len(self.params) >= 3:
                for p in self.params:
                    if p[0] == 'unit':
                        self.fixedSize = p[1]
                    if p[0] == 'p1':
                        self.longDays = p[1]
                    if p[0] == 'p2':
                        self.shortDays = p[1]
                    if p[0] == 'p3':
                        self.longExitDays = p[1]
                    if p[0] == 'p4':
                        self.shortExitDays = p[1]
                    if p[0] == 'p5':
                        self.initDays = p[1]
        else:
            # 策略参数
            self.fixedSize = 1
            self.longDays = 20
            self.shortDays = 20
            self.longExitDays = 10
            self.shortExitDays = 10
            self.initDays = 35

        #print("ma debug:",self.fixedSize,self.longDays,self.shortDays,self.longExitDays,self.shortExitDays,self.initDays)
        # Use class variant should be OK, however, to be save just instance them.
        self.newTradeDay = False
        self.lastLongEntry = 0
        self.lastLongTime = 0
        self.lastShortEntry = 0
        self.lastShortTime = 0
        self.upperChannel = 0
        self.lowerChannel = 0
        self.longEntry = 0
        self.shortEntry = 0
        self.entryPrice = 0
        self.entryDirection = 0
        self.entryUsage = 'Turtle'
        self.entryUnitNo = 0
        self.longExit = 0
        self.shortExit = 0
        self.longAtrExit = 0
        self.shortAtrExit = 0
        self.longChannelExit = 0
        self.shortChannelExit = 0
        self.atrValue = 0
        self.entryAtr = 0
        self.rangeLow = 0
        self.exitTime = time(
            hour=15, minute=20)  #will not cover position when day close

        self.longEntered = False
        self.shortEntered = False

        self.capConfig = 0.0
        self.onTradeCnt = 0
        self.bookTime = datetime.now()
        self.buyCnt = 0

    #----------------------------------------------------------------------
    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)
        # No need to add calculation of the Turtle Channel on Start, it may not change over days.
        #self.calcPrepare()
        self.readLastTrade()
        self.putEvent()

    def readLastTrade(self):
        #read last trade data from database
        #In fact no need after I persist those two values.
        if self.pos > 0:
            self.lastLongEntry = self.entryPrice
            self.lastShortEntry = 0
        elif self.pos < 0:
            self.lastShortEntry = self.entryPrice
            self.lastLongEntry = 0
        pass

    def calcUnitNo(self, atr, fixSize):
        turtleCap = 0.0
        defaultCap = 0.0
        unitNo = 0
        cust = []
        var_sizelist = CtaTemplate.vol_Size
        var_size = 0.0
        var_Symbol = ""
        if len(var_sizelist) == 0:
            return fixSize
        else:
            var_Symbol = var_Symbol.join(
                list(filter(lambda x: x.isalpha(), self.vtSymbol)))
            var_size = float(var_sizelist[var_Symbol][0])
            if var_size - 0 < 0.01:
                return fixSize

        var_temp = 0.0
        if len(CtaTemplate.cust_Setting) > 0:
            cust = CtaTemplate.cust_Setting
        for cs in cust:
            if cs["StrategyGroup"] == "Turtle" and cs["Status"] == 'True':
                turtleCap = cs["CaptialAmt"]
                break
            if cs["StrategyGroup"] == "Default" and cs["Status"] == 'True':
                defaultCap = cs["CaptialAmt"]
        if turtleCap > 0:
            self.capConfig = float(turtleCap)
        elif defaultCap > 0:
            self.capConfig = float(defaultCap)
        else:
            self.capConfig = 0.0

        unitNo = 0
        if self.capConfig - 0 < 0.0001:
            unitNo = fixSize
        elif var_size - 0 < 0.001:
            unitNo = fixSize
        else:
            unitNo = int(self.capConfig * 0.005 / (atr * var_size))

        if unitNo < 1:
            unitNo = 1
        return unitNo

    def calcPrepare(self):
        #calculate initials of the strategy
        barLength = 0
        barLength = max(self.longDays, self.shortDays, self.atrDays)
        if self.am.count < barLength + 1:
            return
        #self.atrValue = talib.ATR(self.am.high, self.am.low, self.am.close,self.atrDays)[-1]
        self.atrValue = self.am.atr(self.atrDays, False)
        # = atrLine[-1]
        if self.atrValue > 0:
            self.fixedSize = self.calcUnitNo(self.atrValue, self.fixedSize)
            #call method to calc unit
        self.upperChannel = talib.MAX(self.am.high, self.longDays)[-1]
        self.lowerChannel = talib.MIN(self.am.low, self.shortDays)[-1]
        self.longChannelExit = talib.MIN(self.am.low, self.longExitDays)[-1]
        self.shortChannelExit = talib.MAX(self.am.high, self.shortExitDays)[-1]

    def calcKPI(self):
        if self.pos > 0:
            self.longAtrExit = int(self.lastLongEntry - 2 * self.entryAtr)
            if self.longAtrExit > self.longChannelExit:
                self.longExit = self.longAtrExit
            else:
                self.longExit = self.longChannelExit

            if self.entryUnitNo == 1:
                self.longEntry = int(self.lastLongEntry + self.entryAtr)
            elif self.entryUnitNo == 2:
                self.longEntry = int(self.lastLongEntry + 0.5 * self.entryAtr)
            else:
                self.longEntry = 0
        elif self.pos == 0:
            self.longEntry = self.upperChannel
            self.shortEntry = self.lowerChannel
        else:
            self.shortAtrExit = int(self.lastShortEntry + 2 * self.entryAtr)
            if self.shortAtrExit < self.shortChannelExit:
                self.shortExit = self.shortAtrExit
            else:
                self.shortExit = self.shortChannelExit
            if self.entryUnitNo == 1:
                self.shortEntry = int(self.lastShortEntry - self.entryAtr)
            elif self.entryUnitNo == 2:
                self.shortEntry = int(self.lastShortEntry -
                                      0.5 * self.entryAtr)
            else:
                self.shortEntry = 0

    #----------------------------------------------------------------------
    def onStop(self):
        """停止策略(必须由用户继承实现)"""
        self.writeCtaLog(u'%s策略停止' % self.name)
        self.putEvent()

    #----------------------------------------------------------------------
    def onTick(self, tick):
        """收到行情TICK推送(必须由用户继承实现)"""
        self.bg.updateTick(tick)

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        # 撤销之前发出的尚未成交的委托(包括限价单和停止单)
        #self.cancelAll()

        self.bg.updateBar(bar)
        print(self.buyCnt)
        self.fixedSize = 11
        if self.buyCnt == 1135:
            self.onTradeCnt = 0
            sendPrice = float(bar.close)
            self.short(sendPrice - 2, 11)

        if self.buyCnt == 1137:
            self.onTradeCnt = 0
            sendPrice = float(bar.close)
            self.short(sendPrice - 20, 11)
        self.buyCnt += 1
        return
        barLength = 0
        barLength = max(self.longDays, self.shortDays, self.atrDays)

        if self.am.count < barLength + 1:
            return
        # 计算指标数值
        self.barList.append(bar)

        if len(self.barList) <= 2:
            return
        else:
            self.barList.pop(0)
        lastBar = self.barList[-2]

        # 新的一天
        if (lastBar.datetime.hour == 15 or lastBar.datetime.hour == 14) and (
            (bar.datetime.hour == 21) or (bar.datetime.hour == 9)):
            # 如果已经初始化
            if not self.upperChannel:
                #do things:
                self.calcPrepare()
            else:
                pass

        if self.pos == 0:
            self.lastLongTime = 0
            self.lastShortTime = 0
            self.entryUnitNo = 0
            self.entryAtr = self.atrValue
        self.calcKPI()

        if self.pos > 0:
            #self.sell(self.longExit,self.fixedSize,stop)
            if bar.close < self.longExit:
                self.sell(bar.close - 2, abs(self.pos))
            elif bar.close > self.longEntry and self.longEntry > 0:
                self.buy(bar.close + 1, self.fixedSize)
                self.bookTime = datetime.now()
                self.onTradeCnt = 0
            else:
                pass
        elif self.pos == 0:
            #self.entryUnitNo = 0
            if bar.close > self.longEntry and self.longEntry > 0:
                self.buy(bar.close + 1, self.fixedSize)
                self.bookTime = datetime.now()
                self.onTradeCnt = 0
            elif bar.close < self.shortEntry and self.shortEntry > 0:
                self.short(bar.close - 1, self.fixedSize)
                self.bookTime = datetime.now()
                self.onTradeCnt = 0
            else:
                pass
        else:
            if bar.close < self.shortEntry and self.shortEntry > 0:
                self.short(bar.close - 1, self.fixedSize)
                self.bookTime = datetime.now()
                self.onTradeCnt = 0
            elif bar.close > self.shortExit:
                self.cover(bar.close + 1, abs(self.pos))
            else:
                pass

        # 发出状态更新事件
        self.putEvent()

    #update day chart
    def ondayBar(self, dayBar):
        """收到日线推送(必须由用户继承实现)"""
        self.am.updateBar(dayBar)
        self.calcPrepare()
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        #if order.status == STATUS_ALLTRADED and self.pos != 0:
        # How do I know the last trade is open or exit?
        #    self.entryUnitNo = self.entryUnitNo + 1

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        if trade.direction == DIRECTION_LONG and trade.offset == OFFSET_OPEN:
            if (trade.volume + self.onTradeCnt) == self.fixedSize:
                self.entryUnitNo = self.entryUnitNo + 1
            else:
                self.onTradeCnt = trade.volume
                self.writeCtaLog(u'%s: 部分成交, 进场次数未累加,注意!' % self.name)

            self.lastLongEntry = trade.price
            self.entryPrice = trade.price
            self.entryDirection = DIRECTION_LONG
            self.entryAtr = self.atrValue
        elif trade.direction == DIRECTION_SHORT and trade.offset == OFFSET_OPEN:
            if (trade.volume + self.onTradeCnt) == self.fixedSize:
                self.entryUnitNo = self.entryUnitNo + 1
            else:
                self.onTradeCnt = trade.volume + self.onTradeCnt
                self.writeCtaLog(u'%s: 部分成交, 进场次数未累加,注意!' % self.name)
            self.lastShortEntry = trade.price
            self.entryPrice = trade.price
            self.entryDirection = DIRECTION_SHORT
            self.entryAtr = self.atrValue
        elif (trade.offset == OFFSET_CLOSE
              or trade.offset == OFFSET_CLOSETODAY):
            #print(self.pos)
            self.entryUnitNo = 0
            self.lastLongEntry = 0
            self.lastShortEntry = 0
            self.entryPrice = 0
            self.entryDirection = OFFSET_CLOSE
        else:
            pass
        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Exemple #33
0
class MultiTimeframeStrategy(CtaTemplate):
    """跨时间周期交易策略"""
    className = 'MultiTimeframeStrategy'
    author = u'用Python的交易员'

    # 策略参数
    rsiSignal = 20  # RSI信号阈值
    rsiWindow = 14  # RSI窗口
    fastWindow = 5  # 快速均线窗口
    slowWindow = 20  # 慢速均线窗口

    initDays = 10  # 初始化数据所用的天数
    fixedSize = 1  # 每次交易的数量

    # 策略变量
    rsiValue = 0  # RSI指标的数值
    rsiLong = 0  # RSI买开阈值
    rsiShort = 0  # RSI卖开阈值
    fastMa = 0  # 5分钟快速均线
    slowMa = 0  # 5分钟慢速均线
    maTrend = 0  # 均线趋势,多头1,空头-1

    # 参数列表,保存了参数的名称
    paramList = [
        'name', 'className', 'author', 'vtSymbol', 'rsiSignal', 'rsiWindow',
        'fastWindow', 'slowWindow'
    ]

    # 变量列表,保存了变量的名称
    varList = [
        'inited', 'trading', 'pos', 'rsiValue', 'rsiLong', 'rsiShort',
        'fastMa', 'slowMa', 'maTrend'
    ]

    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(MultiTimeframeStrategy, self).__init__(ctaEngine, setting)

        self.rsiLong = 50 + self.rsiSignal
        self.rsiShort = 50 - self.rsiSignal

        # 创建K线合成器对象
        self.bg5 = BarGenerator(self.onBar, 5, self.on5MinBar)
        self.am5 = ArrayManager()

        self.bg15 = BarGenerator(self.onBar, 15, self.on15MinBar)
        self.am15 = ArrayManager()

    #----------------------------------------------------------------------
    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推送(必须由用户继承实现)"""
        # 只需要要在一个BM中合成1分钟K线
        self.bg5.updateTick(tick)

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        # 基于15分钟判断趋势过滤,因此先更新
        self.bg15.updateBar(bar)

        # 基于5分钟判断
        self.bg5.updateBar(bar)

    #----------------------------------------------------------------------
    def on5MinBar(self, bar):
        """5分钟K线"""
        self.cancelAll()

        # 保存K线数据
        self.am5.updateBar(bar)
        if not self.am5.inited:
            return

        # 如果15分钟数据尚未初始化完毕,则直接返回
        if not self.maTrend:
            return

        # 计算指标数值
        self.rsiValue = self.am5.rsi(self.rsiWindow)

        # 判断是否要进行交易

        # 当前无仓位
        if self.pos == 0:
            if self.maTrend > 0 and self.rsiValue >= self.rsiLong:
                self.buy(bar.close + 5, self.fixedSize)

            elif self.maTrend < 0 and self.rsiValue <= self.rsiShort:
                self.short(bar.close - 5, self.fixedSize)

        # 持有多头仓位
        elif self.pos > 0:
            if self.maTrend < 0 or self.rsiValue < 50:
                self.sell(bar.close - 5, abs(self.pos))

        # 持有空头仓位
        elif self.pos < 0:
            if self.maTrend > 0 or self.rsiValue > 50:
                self.cover(bar.close + 5, abs(self.pos))

        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def on15MinBar(self, bar):
        """15分钟K线推送"""
        self.am15.updateBar(bar)

        if not self.am15.inited:
            return

        # 计算均线并判断趋势
        self.fastMa = self.am15.sma(self.fastWindow)
        self.slowMa = self.am15.sma(self.slowWindow)

        if self.fastMa > self.slowMa:
            self.maTrend = 1
        else:
            self.maTrend = -1

    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        pass

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        # 发出状态更新事件
        self.putEvent()

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Exemple #34
0
class MaPosStrategy(TargetPosTemplate):
    """双指数均线策略Demo"""
    className = 'MaPosStrategy'
    author = u'用Python的交易员'
    
    # 策略参数
    fastWindow = 10     # 快速均线参数
    slowWindow = 60     # 慢速均线参数
    initDays = 10       # 初始化数据所用的天数
    
    # 策略变量
    fastMa0 = EMPTY_FLOAT   # 当前最新的快速EMA
    fastMa1 = EMPTY_FLOAT   # 上一根的快速EMA
    
    slowMa0 = EMPTY_FLOAT
    slowMa1 = EMPTY_FLOAT
    
    curCapital = 0      #当前可用现金
    capital = 0         #初始资金
    # 参数列表,保存了参数的名称
    paramList = ['name',
                 'className',
                 'author',
                 'vtSymbol',
                 'fastWindow',
                 'slowWindow']    
    
    # 变量列表,保存了变量的名称
    varList = ['inited',
               'trading',
               'pos',
               'fastMa0',
               'fastMa1',
               'slowMa0',
               'slowMa1']  
    
    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(MaPosStrategy, self).__init__(ctaEngine, setting)
        
        self.bg = BarGenerator(self.onBar, 5, self.onFiveBar)     # 创建K线合成器对象
        self.am = ArrayManager()
        # 注意策略类中的可变对象属性(通常是list和dict等),在策略初始化时需要重新创建,
        # 否则会出现多个策略实例之间数据共享的情况,有可能导致潜在的策略逻辑错误风险,
        # 策略类中的这些可变对象属性可以选择不写,全都放在__init__下面,写主要是为了阅读
        # 策略时方便(更多是个编程习惯的选择)
        
    #----------------------------------------------------------------------
    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略初始化')
        
        # initData = self.loadBar(self.initDays)
        # for bar in initData:
        #     self.onBar(bar)
        
        self.putEvent()
        
    #----------------------------------------------------------------------
    def onStart(self):
        """启动策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略启动')
        self.putEvent()
    
    #----------------------------------------------------------------------
    def onStop(self):
        """停止策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略停止')
        self.putEvent()
        
    #----------------------------------------------------------------------
    def onTick(self, tick):
        """收到行情TICK推送(必须由用户继承实现)"""
        super(MaPosStrategy, self).onTick(tick)

        self.bg.updateTick(tick)
        
    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        super(MaPosStrategy, self).onBar(bar)
        self.bg.updateBar(bar)

        pass
    
    
    def onFiveBar(self, bar):
        am = self.am        
        am.updateBar(bar)
        if not am.inited:
            return
        
        # 计算快慢均线
        fastMa = am.sma(self.fastWindow, array=True)
        self.fastMa0 = fastMa[-1]
        self.fastMa1 = fastMa[-2]
        
        slowMa = am.sma(self.slowWindow, array=True)
        self.slowMa0 = slowMa[-1]
        self.slowMa1 = slowMa[-2]

        # 判断买卖
        # crossOver = self.fastMa0>self.slowMa0 and self.fastMa1<self.slowMa1     # 金叉上穿
        # crossBelow = self.fastMa0<self.slowMa0 and self.fastMa1>self.slowMa1    # 死叉下穿
         # 判断买卖
        crossOver = self.fastMa0>self.slowMa0 and self.pos <= 0      # 金叉上穿
        crossBelow = self.fastMa0<self.slowMa0 and self.pos >= 0     # 死叉下穿
        
        # 金叉和死叉的条件是互斥
        # 所有的委托均以K线收盘价委托(这里有一个实盘中无法成交的风险,考虑添加对模拟市价单类型的支持)
        maxPos = max(int(self.curCapital / self.marginRatio /1.1 / bar.close),0)
        if maxPos < 20 :
            maxPos = 0

        if self.pos == 0:
            if crossOver:
                self.setTargetPos(maxPos)
            elif crossBelow:
                self.setTargetPos(-maxPos)
    
        # 持有多头仓位
        elif self.pos > 0:
            if crossOver:
                self.buy(bar.close,maxPos)
            elif crossBelow:
                self.setTargetPos(0)
    
        # 持有空头仓位
        elif self.pos < 0:
            if crossOver:
                self.setTargetPos(0)
            elif crossBelow:
                self.short(bar.close,maxPos)
        # 发出状态更新事件
        self.putEvent()
    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        super(MaPosStrategy, self).onOrder(order)
        from vnpy.trader.vtConstant import DIRECTION_LONG, DIRECTION_SHORT, OFFSET_OPEN, OFFSET_CLOSE, PRICETYPE_LIMITPRICE

        # 对于无需做细粒度委托控制的策略,可以忽略onOrder
        pass
    
    #----------------------------------------------------------------------
    def onTrade(self, trade):
        """收到成交推送(必须由用户继承实现)"""
        super(MaPosStrategy, self).onTrade(trade)
        pass
    
    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass