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)
Example #2
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)
Example #3
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
Example #4
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
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 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
Example #7
0
class TestStrategy(CtaTemplate):
    """Test策略"""
    className = 'TestStrategy'
    author = u'ZC'

    # 策略参数
    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(TestStrategy, self).__init__(ctaEngine, setting)

        self.bg = BarGenerator(self.onBar, 5, self.onFiveBar)
        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 onFiveBar(self, bar):
        """收到5分钟K线"""
        print("onFiveBar-----------------------------------------------")
        # 撤销之前发出的尚未成交的委托(包括限价单和停止单)
        self.cancelAll()

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

        # 计算指标数值
        self.entryUp, self.entryDown = self.am.donchian(self.entryWindow)
        print(
            f"self.entryUp = {self.entryUp} self.entryDown = {self.entryDown}")
        ma = self.am.sma(self.exitWindow)
        self.exitUp = ma
        self.exitDown = ma
        print(self.pos)

        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)
Example #8
0
class BollingerBotStrategy(CtaTemplate):
    """基于布林通道的交易策略"""
    className = 'BollingerBotStrategy'
    author = u'ForwardCapital'

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

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

    maFilter = 0  # 均线过滤
    maFilter1 = 0  # 上一期均线

    intraTradeHigh = 0  # 持仓期内的最高点
    longEntry = 0  # 多头开仓
    longExit = 0  # 多头平仓

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

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

    # 变量列表,保存了变量的名称
    varList = [
        'inited', 'trading', 'pos', 'bollMid', 'bollStd', 'entryUp', 'exitUp',
        'intraTradeHigh', 'longEntry', 'longExit'
    ]

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

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

        self.bm = MyBarGenerator(self.onBar, 15, self.onFiveBar)
        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.bm.updateTick(tick)

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

    #----------------------------------------------------------------------
    def orderIDConvert(self, orderList):
        if not orderList:
            return []
        else:
            return orderList[0]

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

        # 撤销之前发出的尚未成交的委托(包括限价单和停止单)
        print u'onFiveBar↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓,datetime:%s' % bar.datetime
        # 计算指标数值
        self.bollMid = self.am.sma(self.bollWindow)
        self.bollStd = self.am.std(self.bollWindow)
        self.entryUp = self.bollMid + self.bollStd * self.entryDev
        self.exitUp = self.bollMid + self.bollStd * self.exitDev

        maArray = self.am.sma(self.maWindow, True)
        self.maFilter = maArray[-1]
        self.maFilter1 = maArray[-2]

        # 判断是否要进行交易
        if not self.buyOrderID:
            if self.pos == 0:
                self.intraTradeHigh = bar.high
                # 下开仓单
                if bar.close > self.maFilter and self.maFilter > self.maFilter1:
                    self.longEntry = self.entryUp
                    self.buyOrderID = self.buy(self.longEntry, self.fixedSize,
                                               True)
                    self.buyOrderID = self.orderIDConvert(self.buyOrderID)
                    print 'order None!!!buyOrderID is : %s ' % self.buyOrderID
                    self.orderList.append(self.buyOrderID)
                    # 下平仓单
                    self.longExit = self.intraTradeHigh * (
                        1 - self.trailingPrcnt / 100)
                    self.longExit = min(self.longExit, self.exitUp)

                    self.sellOrderID = self.sell(self.longExit, abs(self.pos),
                                                 True)
                    self.sellOrderID = self.orderIDConvert(self.sellOrderID)
                    print 'order None!!!ellOrderID is : %s ' % self.sellOrderID
                    self.orderList.append(self.sellOrderID)
            elif self.pos > 0:
                self.intraTradeHigh = max(self.intraTradeHigh, bar.high)
                # 下平仓单
                self.longExit = self.intraTradeHigh * (
                    1 - self.trailingPrcnt / 100)
                self.longExit = min(self.longExit, self.exitUp)

                self.sellOrderID = self.sell(self.longExit, abs(self.pos),
                                             True)
                self.sellOrderID = self.orderIDConvert(self.sellOrderID)
                print 'order None!!!sellOrderID is : %s ' % self.sellOrderID
                self.orderList.append(self.sellOrderID)

        else:
            if self.buyOrderID in self.orderList:
                self.intraTradeHigh = bar.high
                self.cancelAll()
                # 下开仓单
                if bar.close > self.maFilter and self.maFilter > self.maFilter1:
                    self.longEntry = self.entryUp
                    self.buyOrderID = self.buy(self.longEntry, self.fixedSize,
                                               True)
                    print 'buyOrderID is : %s ' % self.buyOrderID
                    self.buyOrderID = self.orderIDConvert(self.buyOrderID)
                    self.orderList.append(self.buyOrderID)
                    # 下平仓单
                    self.longExit = self.intraTradeHigh * (
                        1 - self.trailingPrcnt / 100)
                    self.longExit = min(self.longExit, self.exitUp)

                    self.sellOrderID = self.sell(self.longExit, abs(self.pos),
                                                 True)
                    self.sellOrderID = self.orderIDConvert(self.sellOrderID)
                    print 'sellOrderID is : %s ' % self.sellOrderID
                    self.orderList.append(self.sellOrderID)
            else:
                if self.sellOrderID in self.orderList:
                    self.intraTradeHigh = max(self.intraTradeHigh, bar.high)
                    self.cancelOrder(self.sellOrderID)
                    # 下平仓单
                    self.longExit = self.intraTradeHigh * (
                        1 - self.trailingPrcnt / 100)
                    self.longExit = min(self.longExit, self.exitUp)

                    self.sellOrderID = self.sell(self.longExit, abs(self.pos),
                                                 True)
                    self.sellOrderID = self.orderIDConvert(self.sellOrderID)
                    print 'sellOrderID is : %s ' % self.sellOrderID
                    self.orderList.append(self.sellOrderID)
                else:
                    self.intraTradeHigh = bar.high
                    # 下开仓单
                    if bar.close > self.maFilter and self.maFilter > self.maFilter1:
                        self.longEntry = self.entryUp
                        self.buyOrderID = self.buy(self.longEntry,
                                                   self.fixedSize, True)
                        self.buyOrderID = self.orderIDConvert(self.buyOrderID)
                        print 'buyOrderID is : %s ' % self.buyOrderID
                        self.orderList.append(self.buyOrderID)
                        # 下平仓单
                        self.longExit = self.intraTradeHigh * (
                            1 - self.trailingPrcnt / 100)
                        self.longExit = min(self.longExit, self.exitUp)

                        self.sellOrderID = self.sell(self.longExit,
                                                     abs(self.pos), True)
                        self.sellOrderID = self.orderIDConvert(
                            self.sellOrderID)
                        print 'sellOrderID is : %s ' % self.sellOrderID
                        self.orderList.append(self.sellOrderID)

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

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

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

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        print u'StopOrder回报,stopOrderID:%s, status:%s' % (so.stopOrderID,
                                                          so.status)
        if so.status == STOPORDER_CANCELLED or so.status == STOPORDER_TRIGGERED:
            self.orderList.remove(so.stopOrderID)
        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
Example #10
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
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()