Ejemplo n.º 1
0
 def __init__(self, ctaEngine, setting):
     """Constructor"""
     super(AtrRsiStrategy, self).__init__(ctaEngine, setting)
     
     # 创建K线合成器对象
     self.bm = BarManager(self.onBar)
     self.am = ArrayManager()
Ejemplo n.º 2
0
 def __init__(self, ctaEngine, setting):
     """Constructor"""
     super(BollChannelStrategy, self).__init__(ctaEngine, setting)
     
     self.bm = BarManager(self.onBar, 15, self.onXminBar)        # 创建K线合成器对象
     self.bm30 = BarManager(self.onBar, 30, self.on30minBar)
     self.am = ArrayManager()
Ejemplo n.º 3
0
class DualThrustStrategyZR5(CtaTemplate):
    """DualThrust策略"""
    className = "DualThrustStrategyZR5"
    autor = "张英杰"

    # 策略参数
    initDays = 30  # 数据初始化天数
    X1 = 1.3
    X2 = 1.5

    fixedSize = 1  # 每次交易数量

    open_time = datetime.time(hour=9, minute=15, second=0)  # 开仓开始时间
    close_time = datetime.time(hour=15, minute=0, second=0)  # 开仓结束时间

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

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

    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(DualThrustStrategyZR5, self).__init__(ctaEngine, setting)

        # 创建bar管理器(K线合成对象),用于合成bar和处理自定义周期的bar回调函数
        self.bm = BarManager(onBar=self.onBar,
                             xmin=5,
                             onXminBar=self.onFifteenBar)
        # 创建k线序列管理工具
        self.am = ArrayManager2(size=300)
        self.dam = DailyArrayManager()

        # 创建变量
        # self.NN = None  # 昨天离今天的k线个数,即目前为今天的第几根bar,文华需要,nvpy不需要
        self.HH1 = None  # 昨天所有bar的收盘最高价
        self.LL1 = None  # 昨天所有bar的收盘价最低价
        self.CC1 = None  # 昨天收盘价

        self.HH2 = None  # 前天所有bar最高收盘价
        self.LL2 = None  # 前天所有bar最低收盘价
        self.CC2 = None  # 前天收盘价

        self.RANGE0 = None  # 这两天的波幅
        self.RANGE1 = None  #

        self.YJS = None  # 昨天的结算价
        self.DTC = None  # 根据昨天计算价判断今天是否会有跌停和涨停的风险

        self.OO1 = None  # 今天的开盘价
        self.MN1 = None  # 中轴价  偏向于趋势

        self.UBUY = None  # 追买中轴线
        self.DSELL = None  # 追卖中轴线

        self.USELL = None  # 卖出中轴线
        self.DBUY = None  # 做多中轴线

        self.USELL1 = None  # 卖出中轴线
        self.DBUY1 = None  # 做多中轴线

        self.DGKX = np.zeros(68 * 3)
        self.DGKX_count = 0
        self.SIZEK = None

        self.ZS = None
        self.KK = None

        self.now_date = None  # 当前日期
        self.pre_date = None  # 上个交易日日期
        self.now_time = None  # 当前时间

        self.last_trade_price = None  # 最后成交价格

        self.intraTradeHigh = None  # 持有期内最高价
        self.intraTradeLow = None  # 持有期内最低价

        self.handle = None  # 要操作的动作

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

        # 载入历史数据,并采用回放计算的方式初始化策略数值
        initData = self.loadBar(days=self.initDays)
        # 预处理初始化的bar
        for bar in initData:
            self.onBar(bar)

        # 发出策略状态变化事件
        self.putEvent()

    def onStart(self):
        '''启动策略(必须由用户继承实现)'''
        self.writeCtaLog("%s策略启动" % self.name)

        # 发出策略状态变化事件
        self.putEvent()  # 目前的结论是回测时候该方法为pass,实盘通常用于通知界面更新

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

        # 发出策略状态变化事件
        self.putEvent()

    def onTick(self, tick):
        '''收到TICK推送,必须由用户继承实现'''
        # 更新tick,合成k线
        self.bm.updateTick(tick)

    def onBar(self, bar):
        """收到bar推送(必须由用户继承实现)"""
        self.bm.updateBar(
            bar)  # 一分钟一个bar,执行周期大于1分钟的策略在自定义的执行方法里,到时间了由bm.updataBar回调执行

    def onFifteenBar(self, bar):
        """收到5分钟bar推送"""
        # 保存K线数据
        am = self.am
        am.updateBar(bar)

        # 保存日K数据
        dam = self.dam
        dam.updateBar(bar)

        self.now_time = bar.datetime.time()
        # 初始化
        if self.now_date is None:
            self.now_date = bar.date
            return
        # 日期改变
        elif self.now_date != bar.date:
            self.pre_date = self.now_date
            self.now_date = bar.date

            # 计算变量
            # 计算昨天、前天所有bar最高、最低收盘价,昨天结算价
            self.HH2 = self.HH1
            self.LL2 = self.LL1
            self.CC2 = self.CC1

            self.HH1 = am.close[-2]
            self.LL1 = am.close[-2]
            self.CC1 = am.close[-2]

            i = -3
            while am.date[i] == self.pre_date:
                if am.close[i] > self.HH1:
                    self.HH1 = am.close[i]
                if am.close[i] < self.LL1:
                    self.LL1 = am.close[i]
                i -= 1

            # 计算这两天的波幅
            if self.HH1 is not None and self.HH2 is not None:
                self.RANGE0 = (((self.HH1 - self.LL1) * 0.65 +
                                (self.HH2 - self.LL2) * 0.35) /
                               am.sma(68 * 2, array=True)[-2]) * 100
                self.RANGE1 = 6 if self.RANGE0 > 6 else self.RANGE0

            # 昨天的结算价
            tmp_sum = 0.
            volume_sum = 0.
            for i in range(-2, -2 - 15, -1):
                tmp_sum += self.am.close[i] * self.am.volume[i]
                volume_sum += self.am.volume[i]

            self.YJS = tmp_sum / volume_sum
            # 获取今日开盘价
            self.OO1 = bar.open

        # 数据足以支持计算DGKX
        if am.count >= 68 * 2:
            self.DGKX[0:self.DGKX.size - 1] = self.DGKX[1:self.DGKX.size]
            if abs(bar.high - bar.low) / bar.close * 10000 < 4:
                self.DGKX[-1] = talib.SMA(abs(am.close - am.open), 68 * 2)[-1]
            else:
                self.DGKX[-1] = abs(bar.close - bar.open)
            self.DGKX_count += 1

            # 数据足以支持计算SIZEK
            if self.DGKX_count >= 68 * 3:
                self.SIZEK = talib.SMA(self.DGKX, 68 * 3)[-1] / talib.SMA(
                    self.am.close, 68 * 3)[-1] * 1000
                self.ZS = (self.SIZEK**0.5) * 2
                self.KK = abs(bar.close - bar.open) / bar.open < 0.006

        # 如果k线还没有初始化完成,就不执行
        if not am.inited:
            return
        # 如果日k线还没有初始化完成,就不执行
        if not dam.inited:
            return
        #
        # if bar.date == "20171215":
        #     print(1)

        # 根据昨日计算价判断是否有涨停和跌停风险
        self.DTC = bar.close > self.YJS * (
            1 - 0.085) and bar.close < self.YJS * (1 + 0.085)

        self.MN1 = (self.OO1 +
                    (self.HH1 + self.LL1 + self.CC1) / 3) / 2  # 中轴价,偏向于趋势

        self.UBUY = self.MN1 * (1 + self.X1 * self.RANGE1 / 100)  # 追买中轴线
        self.DSELL = self.MN1 * (1 - self.X2 * self.RANGE1 / 100)  # 追买中轴线

        self.USELL = self.MN1 * (1 + 1.3 * self.RANGE1 / 100)  # 卖出中轴线
        self.DBUY = self.MN1 * (1 - 1.6 * self.RANGE1 / 100)  # 做多中轴线

        self.USELL1 = self.USELL * (1 + 0.2 * self.RANGE1 / 100)  # 卖出中轴线
        self.DBUY1 = self.DBUY * (1 - 0.2 * self.RANGE1 / 100)  # 做多中轴线

        # 开仓时间
        if self.pos == 0:
            # 到目前为止的最高、最低收盘价
            self.intraTradeHigh = bar.close
            self.intraTradeLow = bar.close
            if self.now_time >= self.open_time and self.now_time <= self.close_time:
                # 金叉开仓
                if self.am.close[-1] > self.UBUY and self.am.close[
                        -2] <= self.UBUY and self.am.close[
                            -3] < self.UBUY and self.KK:
                    self.handle = "买开"
                    # self.cancelAll()
                    # self.buy(price=bar.close+0.01, volume=self.fixedSize)

                # 死叉做空
                elif self.am.close[-1] < self.DSELL and self.am.close[
                        -2] >= self.DSELL and self.am.close[
                            -3] > self.DSELL and self.KK:
                    self.handle = "卖开"
                    # self.cancelAll()
                    # self.short(price=bar.close-0.01, volume=self.fixedSize)

                if bar.datetime.time == datetime.time(hour=11, minute=29):
                    if self.handle == "买开":
                        self.handle = "下bar买开"
                    elif self.handle == "卖开":
                        self.handle = "下bar卖开"

                if self.handle == "买开":
                    self.cancelAll()
                    self.buy(price=bar.close + 0.01, volume=self.fixedSize)
                    self.handle = None
                elif self.handle == "卖开":
                    self.cancelAll()
                    self.short(price=bar.close - 0.01, volume=self.fixedSize)
                    self.handle = None

        elif self.pos > 0:
            self.intraTradeHigh = max(self.intraTradeHigh, bar.close)
            self.intraTradeLow = min(self.intraTradeLow, bar.close)
            # is_sell = False

            if self.intraTradeHigh > self.last_trade_price * (
                    1 + self.ZS / 1000 *
                    3) and bar.close - self.last_trade_price <= (
                        self.intraTradeHigh - self.last_trade_price) * 0.4:
                self.handle = "卖平"
            if self.intraTradeHigh > self.last_trade_price * (
                    1 + self.ZS / 1000 *
                    6) and bar.close - self.last_trade_price <= (
                        self.intraTradeHigh - self.last_trade_price) * 0.5:
                self.handle = "卖平"

            yuzhi = self.last_trade_price * (1 - self.ZS / 1000)  # 阈值缓存
            if self.am.close[-1] < yuzhi and self.am.close[-2] >= yuzhi:
                self.handle = "卖平"
            yuzhi = self.last_trade_price * (1 + 10 * self.ZS / 1000)
            if self.am.close[-1] > yuzhi and self.am.close[-2] <= yuzhi:
                self.handle = "卖平"

            if bar.datetime.time == datetime.time(hour=11, minute=29):
                if self.handle == "卖平":
                    self.handle = "下bar卖平"

            if self.handle == "卖平":
                self.cancelAll()
                self.sell(price=bar.close - 0.01, volume=self.fixedSize)
                self.handle = None

        elif self.pos < 0:
            self.intraTradeHigh = max(self.intraTradeHigh, bar.close)
            self.intraTradeLow = min(self.intraTradeLow, bar.close)
            is_cover = False

            if self.intraTradeLow < self.last_trade_price * (
                    1 - self.ZS / 1000 *
                    3) and self.last_trade_price - bar.close <= (
                        self.last_trade_price - self.intraTradeLow) * 0.5:
                is_cover = True
            if self.intraTradeLow < self.last_trade_price * (
                    1 - self.ZS / 1000 *
                    6) and self.last_trade_price - bar.close <= (
                        self.last_trade_price - self.intraTradeLow) * 0.7:
                is_cover = True

            yuzhi = self.last_trade_price * (1 + self.ZS / 1000)
            if self.am.close[-1] > yuzhi and self.am.close[-2] <= yuzhi:
                is_cover = True
            yuzhi = self.last_trade_price * (1 - 10 * self.ZS / 1000)
            if self.am.close[-1] < yuzhi and self.am.close[-2] >= yuzhi:
                is_cover = True
            if is_cover:
                self.cancelAll()
                self.cover(price=bar.close + 0.01, volume=self.fixedSize)

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

    def onTrade(self, trade):
        """收到交易发生事件推送"""
        self.last_trade_price = trade.price
        print("发生交易")
        print(trade.__dict__)
        print("\n")
        self.putEvent()

    def onStopOrder(self, so):
        """收到停止单事件推送"""
        self.putEvent()

    def closeAllPosition(self, bar):
        self.cancelAll()
        if self.pos > 0:
            self.sell(price=bar.close - 0.01, volume=self.fixedSize)
        elif self.pos < 0:
            self.cover(price=bar.close + 0.01, volume=self.fixedSize)
Ejemplo n.º 4
0
 def __init__(self, ctaEngine, setting):
     """Constructor"""
     super(DoubleMaStrategy, self).__init__(ctaEngine, setting)
     
     self.bm = BarManager(self.onBar)
     self.am = ArrayManager()
Ejemplo n.º 5
0
class DoubleMaStrategy(CtaTemplate):
    """双指数均线策略Demo"""
    className = 'DoubleMaStrategy'
    author = u'用Python的交易员'
    
    # 策略参数
    fastWindow = 10     # 快速均线参数
    slowWindow = 60     # 慢速均线参数
    initDays = 10       # 初始化数据所用的天数
    
    # 策略变量
    fastMa0 = EMPTY_FLOAT   # 当前最新的快速EMA
    fastMa1 = EMPTY_FLOAT   # 上一根的快速EMA
    
    slowMa0 = EMPTY_FLOAT
    slowMa1 = EMPTY_FLOAT
    
    # 参数列表,保存了参数的名称
    paramList = ['name',
                 'className',
                 'author',
                 'vtSymbol',
                 'fastWindow',
                 'slowWindow']    
    
    # 变量列表,保存了变量的名称
    varList = ['inited',
               'trading',
               'pos',
               'fastMa0',
               'fastMa1',
               'slowMa0',
               'slowMa1']  
    
    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos']

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(DoubleMaStrategy, self).__init__(ctaEngine, setting)
        
        self.bm = BarManager(self.onBar)
        self.am = ArrayManager()
        
        # 注意策略类中的可变对象属性(通常是list和dict等),在策略初始化时需要重新创建,
        # 否则会出现多个策略实例之间数据共享的情况,有可能导致潜在的策略逻辑错误风险,
        # 策略类中的这些可变对象属性可以选择不写,全都放在__init__下面,写主要是为了阅读
        # 策略时方便(更多是个编程习惯的选择)
        
    #----------------------------------------------------------------------
    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略初始化')
        
        initData = self.loadBar(self.initDays)
        for bar in initData:
            self.onBar(bar)
        
        self.putEvent()
        
    #----------------------------------------------------------------------
    def onStart(self):
        """启动策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略启动')
        self.putEvent()
    
    #----------------------------------------------------------------------
    def onStop(self):
        """停止策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双EMA演示策略停止')
        self.putEvent()
        
    #----------------------------------------------------------------------
    def onTick(self, tick):
        """收到行情TICK推送(必须由用户继承实现)"""
        self.bm.updateTick(tick)
        
    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        am = self.am        
        am.updateBar(bar)
        if not am.inited:
            return
        
        # 计算快慢均线
        fastMa = am.sma(self.fastWindow, array=True)
        self.fastMa0 = fastMa[-1]
        self.fastMa1 = fastMa[-2]
        
        slowMa = am.sma(self.slowWindow, array=True)
        self.slowMa0 = slowMa[-1]
        self.slowMa1 = slowMa[-2]

        # 判断买卖
        crossOver = self.fastMa0>self.slowMa0 and self.fastMa1<self.slowMa1     # 金叉上穿
        crossBelow = self.fastMa0<self.slowMa0 and self.fastMa1>self.slowMa1    # 死叉下穿
        
        # 金叉和死叉的条件是互斥
        # 所有的委托均以K线收盘价委托(这里有一个实盘中无法成交的风险,考虑添加对模拟市价单类型的支持)
        if crossOver:
            # 如果金叉时手头没有持仓,则直接做多
            if self.pos == 0:
                self.buy(bar.close, 1)
            # 如果有空头持仓,则先平空,再做多
            elif self.pos < 0:
                self.cover(bar.close, 1)
                self.buy(bar.close, 1)
        # 死叉和金叉相反
        elif crossBelow:
            if self.pos == 0:
                self.short(bar.close, 1)
            elif self.pos > 0:
                self.sell(bar.close, 1)
                self.short(bar.close, 1)
                
        # 发出状态更新事件
        self.putEvent()
        
    #----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        # 对于无需做细粒度委托控制的策略,可以忽略onOrder
        pass
    
    #----------------------------------------------------------------------
    def onTrade(self, trade):
        """收到成交推送(必须由用户继承实现)"""
        # 对于无需做细粒度委托控制的策略,可以忽略onOrder
        pass
    
    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass    
Ejemplo n.º 6
0
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(DoubleMaStrategy, self).__init__(ctaEngine, setting)

        self.bm = BarManager(self.onBar)
        self.am = ArrayManager()
Ejemplo n.º 7
0
class DualThrustStrategy(CtaTemplate):
    """DualThrust交易策略"""
    className = 'DualThrustStrategy'
    author = u'用Python的交易员'

    # 策略参数
    fixedSize = 100
    k1 = 0.4
    k2 = 0.6

    initDays = 10

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

    dayOpen = 0
    dayHigh = 0
    dayLow = 0
    
    range = 0
    longEntry = 0
    shortEntry = 0
    exitTime = time(hour=14, minute=55)

    longEntered = False
    shortEntered = False

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

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

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(DualThrustStrategy, self).__init__(ctaEngine, setting) 
        
        self.bm = BarManager(self.onBar)
        self.barList = []

    #----------------------------------------------------------------------
    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        self.writeCtaLog(u'%s策略初始化' %self.name)
    
        # 载入历史数据,并采用回放计算的方式初始化策略数值
        initData = self.loadBar(self.initDays)
        for bar in initData:
            self.onBar(bar)

        self.putEvent()

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

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

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

        # 计算指标数值
        self.barList.append(bar)
        
        if len(self.barList) <= 2:
            return
        else:
            self.barList.pop(0)
        lastBar = self.barList[-2]
        
        # 新的一天
        if lastBar.datetime.date() != bar.datetime.date():
            # 如果已经初始化
            if self.dayHigh:
                self.range = self.dayHigh - self.dayLow
                self.longEntry = bar.open + self.k1 * self.range
                self.shortEntry = bar.open - self.k2 * self.range           
                
            self.dayOpen = bar.open
            self.dayHigh = bar.high
            self.dayLow = bar.low

            self.longEntered = False
            self.shortEntered = False
        else:
            self.dayHigh = max(self.dayHigh, bar.high)
            self.dayLow = min(self.dayLow, bar.low)

        # 尚未到收盘
        if not self.range:
            return

        if bar.datetime.time() < self.exitTime:
            if self.pos == 0:
                if bar.close > self.dayOpen:
                    if not self.longEntered:
                        self.buy(self.longEntry, self.fixedSize, stop=True)
                else:
                    if not self.shortEntered:
                        self.short(self.shortEntry, self.fixedSize, stop=True)
    
            # 持有多头仓位
            elif self.pos > 0:
                self.longEntered = True

                # 多头止损单
                self.sell(self.shortEntry, self.fixedSize, stop=True)
                
                # 空头开仓单
                if not self.shortEntered:
                    self.short(self.shortEntry, self.fixedSize, stop=True)
                
            # 持有空头仓位
            elif self.pos < 0:
                self.shortEntered = True

                # 空头止损单
                self.cover(self.longEntry, self.fixedSize, stop=True)
                
                # 多头开仓单
                if not self.longEntered:
                    self.buy(self.longEntry, self.fixedSize, stop=True)
            
        # 收盘平仓
        else:
            if self.pos > 0:
                self.sell(bar.close * 0.99, abs(self.pos))
            elif self.pos < 0:
                self.cover(bar.close * 1.01, abs(self.pos))
 
        # 发出状态更新事件
        self.putEvent()

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

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

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Ejemplo n.º 8
0
class AppleStartStrategy2(CtaTemplate):
    """苹果期货新上市策略"""
    className = 'AppleStartStrategy2'
    author = '中融致信投资技术部'

    # 策略参数
    # 3900成交价格
    initDays = 1 # 数据初始化天数
    open_pos_time = datetime.time(hour=9, minute=1, second=0)    # 开仓时间
    stop_open_pos_time = datetime.time(hour=14, minute=54, second=0) # 停止开仓时间
    close_pos_time = datetime.time(hour=14, minute=58, second=0) # 清仓时间
    fixedSize = 1  # 每次交易的数量

    # faxing_price = 7800.00  # 苹果发行价格
    # faxing_price = 3801.00  # 螺纹结算价格
    open_slip = 0
    close_slip = 0


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

        self.bm = BarManager(self.onBar)  # 创建K线合成器对象
        self.am = ArrayManager(size=100)

        self.pre_zhongxin = None  # 上一个bar的重心
        # self.zhangting_price = round(self.faxing_price * 1.1, 2)  # 涨停价
        # self.dieting_price = round(self.faxing_price * 0.9, 2)    # 跌停价

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

        # 载入历史数据,并采用回放计算的方式初始化策略数值
        initData = self.loadBar(self.initDays)
        for bar in initData:
            self.onBar(bar)

        self.putEvent()

    #----------------------------------------------------------------------
    def onStart(self):
        """启动策略(必须由用户继承实现)"""
        self.writeCtaLog('%s策略启动' %self.name)
        self.putEvent()

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

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

    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        # 保存K线数据
        am = self.am
        am.updateBar(bar)
        # 如果k先还没有初始化完成,就不执行
        if not am.inited:
            return

        # 先撤销之前没有成交的单子
        self.cancelAll()

        # 获取当前时间
        time_now = bar.datetime.time()

        # 收集计算数据
        zhongxin = (bar.open + bar.high + bar.low + bar.close) / 4  # 重心
        # 第一个bar先略过
        if self.pre_zhongxin is None:
            self.pre_zhongxin = zhongxin
            return

        # 开仓时间
        if time_now >= self.open_pos_time and time_now < self.stop_open_pos_time:
            # 判断该做空还是做多
            trend = 0  # 趋势,-1 空, 0 无趋势, 1 多
            if zhongxin > self.pre_zhongxin and bar.close > zhongxin:
                trend = 1
            elif zhongxin < self.pre_zhongxin and bar.close < zhongxin:
                trend = -1

            if self.pos == 0:
                # 空仓趋势多头直接开多
                if trend == 1:
                    # self.buy(price=bar.close+self.open_slip, volume=self.fixedSize)
                    self.short(price=bar.close - self.open_slip, volume=self.fixedSize)
                # 空仓趋势空头直接开空
                elif trend == -1:
                    # self.short(price=bar.close-self.open_slip, volume=self.fixedSize)
                    self.buy(price=bar.close + self.open_slip, volume=self.fixedSize)

            # 持有多投仓位
            elif self.pos > 0:
                # 趋势反转,反手做空
                # if trend == -1:
                #     self.sell(price=bar.close-self.close_slip, volume=self.fixedSize)
                #     self.short(price=bar.close-self.open_slip, volume=self.fixedSize)
                if trend == 1:
                    self.sell(price=bar.close-self.close_slip, volume=self.fixedSize)
                    self.short(price=bar.close-self.open_slip, volume=self.fixedSize)

            # 持有空头仓位
            elif self.pos < 0:
                # 趋势反转,反手做多
                # if trend == 1:
                if trend == -1:
                    self.cover(price=bar.close+self.close_slip, volume=self.fixedSize)
                    self.buy(price=bar.close+self.open_slip, volume=self.fixedSize)

        # 尾盘强制平仓
        if time_now >= self.close_pos_time:
            if self.pos != 0:
                self.closeAllPosition(bar)

        # 为下一个bar数据做准备
        self.pre_zhongxin = zhongxin




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

    def onTrade(self, trade):
        """收到交易发生事件推送"""
        pass

    def onStopOrder(self, so):
        """收到停止单事件推送"""
        self.putEvent()

    def closeAllPosition(self, bar):
        """平掉所有仓位"""
        self.cancelAll()
        if self.pos > 0:
            self.sell(price=bar.close-self.close_slip, volume=self.fixedSize)
        elif self.pos < 0:
            self.cover(price=bar.close+self.close_slip, volume=self.fixedSize)
Ejemplo n.º 9
0
class AtrRsiStrategy(CtaTemplate):
    """结合ATR和RSI指标的一个分钟线交易策略"""
    className = 'AtrRsiStrategy'
    author = '用Python的交易员'

    # 策略参数
    atrLength = 22  # 计算ATR指标的窗口数
    atrMaLength = 10  # 计算ATR均线的窗口数
    rsiLength = 5  # 计算RSI的窗口数
    rsiEntry = 16  # RSI的开仓信号
    trailingPercent = 0.8  # 百分比移动止损
    initDays = 10  # 初始化数据所用的天数
    fixedSize = 1  # 每次交易的数量

    # 策略变量
    atrValue = 0  # 最新的ATR指标数值
    atrMa = 0  # ATR移动平均的数值
    rsiValue = 0  # RSI指标的数值
    rsiBuy = 0  # RSI买开阈值
    rsiSell = 0  # RSI卖开阈值
    intraTradeHigh = 0  # 移动止损用的持仓期内最高价
    intraTradeLow = 0  # 移动止损用的持仓期内最低价

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

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

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

        # 创建K线合成器对象
        self.bm = BarManager(self.onBar)
        self.am = ArrayManager()

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

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

        # 初始化RSI入场阈值
        self.rsiBuy = 50 + self.rsiEntry
        self.rsiSell = 50 - self.rsiEntry

        # 载入历史数据,并采用回放计算的方式初始化策略数值
        initData = self.loadBar(self.initDays)
        for bar in initData:
            self.onBar(bar)

        self.putEvent()

    #----------------------------------------------------------------------
    def onStart(self):
        """启动策略(必须由用户继承实现)"""
        self.writeCtaLog('%s策略启动' % self.name)
        self.putEvent()

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

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

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

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

        # 计算指标数值
        atrArray = am.atr(self.atrLength, array=True)  # atr指标
        self.atrValue = atrArray[-1]
        self.atrMa = atrArray[-self.atrMaLength:].mean()

        self.rsiValue = am.rsi(self.rsiLength)

        # 判断是否要进行交易

        # 当前无仓位
        if self.pos == 0:
            self.intraTradeHigh = bar.high
            self.intraTradeLow = bar.low

            # ATR数值上穿其移动平均线,说明行情短期内波动加大
            # 即处于趋势的概率较大,适合CTA开仓
            if self.atrValue > self.atrMa:
                # 使用RSI指标的趋势行情时,会在超买超卖区钝化特征,作为开仓信号
                if self.rsiValue > self.rsiBuy:
                    # 这里为了保证成交,选择超价5个整指数点下单
                    self.buy(bar.close + 5, self.fixedSize)

                elif self.rsiValue < self.rsiSell:
                    self.short(bar.close - 5, self.fixedSize)

        # 持有多头仓位
        elif self.pos > 0:
            # 计算多头持有期内的最高价,以及重置最低价
            self.intraTradeHigh = max(self.intraTradeHigh, bar.high)
            self.intraTradeLow = bar.low

            # 计算多头移动止损
            longStop = self.intraTradeHigh * (1 - self.trailingPercent / 100)

            # 发出本地止损委托,并且把委托号记录下来,用于后续撤单
            self.sell(longStop, abs(self.pos), stop=True)

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

            shortStop = self.intraTradeLow * (1 + self.trailingPercent / 100)
            self.cover(shortStop, abs(self.pos), stop=True)

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

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

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

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

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

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

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

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

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(BollChannelStrategy, self).__init__(ctaEngine, setting)
        
        self.bm = BarManager(self.onBar, 15, self.onXminBar)        # 创建K线合成器对象
        self.bm30 = BarManager(self.onBar, 30, self.on30minBar)
        self.am = ArrayManager()
        
    #----------------------------------------------------------------------
    def on30minBar(self, bar):
        """"""
        
        
    #----------------------------------------------------------------------
    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        self.writeCtaLog(u'%s策略初始化' %self.name)
        
        # 载入历史数据,并采用回放计算的方式初始化策略数值
        initData = self.loadBar(self.initDays)
        for bar in initData:
            self.onBar(bar)

        self.putEvent()

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

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

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

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

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

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

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Ejemplo n.º 11
0
class BarMStrategy(CtaTemplate):
    """多周期策略"""
    className = 'BarMStrategy'
    author = u'toriphy'

    # 策略参数
    kkLength = 15  # 计算通道中值的窗口数
    kkDevUp = 2.2  # 计算通道宽度的偏差 取2.1或者2.2比较好
    kkDevDown = 1.9  # 初始值1.9
    trailingPrcnt = 1.1  # 移动止损, 初始值1.2
    thresholdRatio = 0.15  # 持仓量指标阈值
    initDays = 10  # 初始化数据所用的天数,注意这个值是天数而不是bar的个数
    fixedSize = 1  # 每次交易的数量
    barBin = 5  # 五分钟线 短周期
    barLongBin = 15  # 十五分钟线,长周期

    shortMAperiod = 6
    longMAperiod = 12

    bufferSize = 100  # 需要缓存的数据的大小 65
    longCycleBufferSize = 30  # 长周期需要缓存的数据大小 20
    bufferCount = 0  # 目前已经缓存了的数据的计数
    longCycleBufferCount = 0  # 长周期目前已经缓存了的数据的计数

    longCycleTradingFlag = 0  # 长周期交易信号

    atrValue = 0  # 最新的ATR指标数值
    kkMid = 0  # KK通道中轨
    kkUp = 0  # KK通道上轨
    kkDown = 0  # KK通道下轨
    openRatioModi = 0  # 开仓指标调整
    intraTradeHigh = 0  # 持仓期内的最高点
    intraTradeLow = 0  # 持仓期内的最低点
    longStop = 0  # 多头的移动止损点位
    shortStop = 0  # 空头的移动止损点位

    openRatioModiArray = np.zeros(bufferSize)
    longCycleLLTArrayShort = np.zeros(longCycleBufferSize)  # 短周期部分 ,alpha

    # 其他不相关的
    buyOrderID = None  # OCO委托买入开仓的委托号
    shortOrderID = None  # OCO委托卖出开仓的委托号
    orderList = []  # 保存委托代码的列表

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

    # 变量列表,保存了变量的名称
    varList = [
        'inited', 'trading', 'pos', 'kkMid', 'kkUp', 'kkDown',
        'barOpenRatioModi', 'longStop', 'shortStop', 'longCycleTradingFlag'
    ]

    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos', 'longStop', 'shortStop']  # 持仓数据和trailing stop 是一定要保存的

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

        # 创建K线合成器对象
        self.bm = BarManager(self.onBar)  # 1分钟线(因为要调取1分钟线的持仓量和成交量信息)
        self.am = ArrayManager()

        self.bm5 = BarManager(self.onBar, self.barBin, self.on5MinBar)
        self.am5 = ArrayManager()

        self.bm15 = BarManager(self.onBar, self.barLongBin, self.on15MinBar)
        self.am15 = ArrayManager(size=self.longCycleBufferSize)

    # ----------------------------------------------------------------------
    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推送(必须由用户继承实现)"""
        # 基于15分钟判断趋势过滤,因此先更新
        self.am.updateBar(bar)
        self.vArray1min = self.am.volume[-5:]
        self.oArray1min = self.am.openInterest[-6:]

        self.bm15.updateBar(bar)

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

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

        # 保存K线数据

        self.am5.updateBar(bar)

        barOpenRatioModi = ((np.sqrt(self.vArray1min) / np.sqrt(self.vArray1min).sum()) * ((self.oArray1min[1:] - \
                            self.oArray1min[:-1]) / self.vArray1min)).mean()

        self.openRatioModiArray[0:self.bufferSize -
                                1] = self.openRatioModiArray[1:self.bufferSize]
        self.openRatioModiArray[-1] = barOpenRatioModi  # 开仓比例

        self.bufferCount += 1

        if self.bufferCount < self.bufferSize:
            return

        # 计算指标数值
        self.atrValue = talib.ATR(self.am5.high, self.am5.low, self.am5.close,
                                  self.kkLength)[-1]
        self.kkMid = talib.MA(self.am5.close, self.kkLength)[-1]
        self.kkUp = self.kkMid + self.atrValue * self.kkDevUp
        self.kkDown = self.kkMid - self.atrValue * self.kkDevDown

        self.openRatioModi = self.openRatioModiArray[-1]  # 开仓量指标

        conditionKKBuy = self.am5.close[-1] > self.kkUp
        conditionKKSell = self.am5.close[-1] < self.kkDown

        conditionOpenRatioModiBuy = self.openRatioModi > 0.022
        conditionOpenRatioModiSell = self.openRatioModi > 0.026  # 最好0.026

        # 当前无仓位,
        if self.pos == 0:
            self.intraTradeHigh = bar.high
            self.intraTradeLow = bar.low
            if conditionKKBuy and conditionOpenRatioModiBuy and self.longCycleTradingFlag == 1:
                self.buy(bar.close + 5, self.fixedSize)
            elif conditionKKSell and conditionOpenRatioModiSell and self.longCycleTradingFlag == -1:
                self.short(bar.close - 5, self.fixedSize)

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

            self.longStop = self.intraTradeHigh * (1 -
                                                   self.trailingPrcnt / 100)
            orderID = self.sell(self.longStop, abs(self.pos), stop=True)
            self.writeCtaLog(u'多头止损价格:' + str(self.longStop))
            self.orderList.append(orderID)

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

            self.shortStop = self.intraTradeLow * (1 +
                                                   self.trailingPrcnt / 100)
            orderID = self.cover(self.shortStop, abs(self.pos), stop=True)

            self.writeCtaLog(u'空头头止损价格:' + str(self.shortStop))
            self.orderList.append(orderID)

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

    # ----------------------------------------------------------------------
    def on15MinBar(self, bar):
        """15分钟K线推送"""
        #print 'cycletime:', bar.datetime, self.longCycleTradingFlag
        self.am15.updateBar(bar)

        alpha = 0.3  # 5分钟线取0.3最佳
        alphatilde = 2 / (12 + 1)

        LLTShort = (alpha - (alpha ** 2) / 4) * self.am15.close[-1] + (alpha ** 2) / 2 * \
                   self.am15.close[-2] - \
                   (alpha - 3 * alpha ** 2 / 4) * self.am15.close[-3] + 2 * (1 - alpha) * \
                   self.longCycleLLTArrayShort[-1] - (1 - alpha ** 2) * self.longCycleLLTArrayShort[-2]

        self.longCycleLLTArrayShort[0:self.longCycleBufferSize -
                                    1] = self.longCycleLLTArrayShort[
                                        1:self.longCycleBufferSize]
        self.longCycleLLTArrayShort[-1] = LLTShort

        #print self.am15.close[-10:],"\n","LLT:", LLTShort

        self.longCycleBufferCount += 1
        if self.longCycleBufferCount < self.longCycleBufferSize:
            return

        longCycleMAlong = talib.MA(self.am15.close, self.longMAperiod)
        longCycleMAshort = talib.MA(self.am15.close, self.shortMAperiod)

        maLongCondition = longCycleMAshort[-1] > longCycleMAlong[-1]
        lltLongCondition = self.longCycleLLTArrayShort[
            -1] > self.longCycleLLTArrayShort[-2]
        lltShortCondition = self.longCycleLLTArrayShort[
            -1] < self.longCycleLLTArrayShort[-2]
        if maLongCondition:
            self.longCycleTradingFlag = 1
        elif lltShortCondition:
            self.longCycleTradingFlag = -1
        else:
            self.longCycleTradingFlag = 0

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

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

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

    # ----------------------------------------------------------------------
    def sendOcoOrder(self, buyPrice, shortPrice, volume):
        """
        发送OCO委托

        OCO(One Cancel Other)委托:
        1. 主要用于实现区间突破入场
        2. 包含两个方向相反的停止单
        3. 一个方向的停止单成交后会立即撤消另一个方向的
        """
        # 发送双边的停止单委托,并记录委托号
        self.buyOrderID = self.buy(buyPrice, volume, True)
        self.shortOrderID = self.short(shortPrice, volume, True)

        # 将委托号记录到列表中
        self.orderList.append(self.buyOrderID)
        self.orderList.append(self.shortOrderID)
Ejemplo n.º 12
0
class AtrRsiStrategy(CtaTemplate):
    """结合ATR和RSI指标的一个分钟线交易策略"""
    className = 'AtrRsiStrategy'
    author = u'用Python的交易员'

    # 策略参数
    atrLength = 22          # 计算ATR指标的窗口数   
    atrMaLength = 10        # 计算ATR均线的窗口数
    rsiLength = 5           # 计算RSI的窗口数
    rsiEntry = 16           # RSI的开仓信号
    trailingPercent = 0.8   # 百分比移动止损
    initDays = 10           # 初始化数据所用的天数
    fixedSize = 1           # 每次交易的数量

    # 策略变量
    atrValue = 0                        # 最新的ATR指标数值
    atrMa = 0                           # ATR移动平均的数值
    rsiValue = 0                        # RSI指标的数值
    rsiBuy = 0                          # RSI买开阈值
    rsiSell = 0                         # RSI卖开阈值
    intraTradeHigh = 0                  # 移动止损用的持仓期内最高价
    intraTradeLow = 0                   # 移动止损用的持仓期内最低价

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

    # 变量列表,保存了变量的名称
    varList = ['inited',
               'trading',
               'pos',
               'atrValue',
               'atrMa',
               'rsiValue',
               'rsiBuy',
               'rsiSell']  
    
    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos',
                'intraTradeHigh',
                'intraTradeLow']

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

    #----------------------------------------------------------------------
    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        self.writeCtaLog(u'%s策略初始化' %self.name)
    
        # 初始化RSI入场阈值
        self.rsiBuy = 50 + self.rsiEntry
        self.rsiSell = 50 - self.rsiEntry

        # 载入历史数据,并采用回放计算的方式初始化策略数值
        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.cancelAll()

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

        # 计算指标数值
        atrArray = am.atr(self.atrLength, array=True)
        self.atrValue = atrArray[-1]
        self.atrMa = atrArray[-self.atrMaLength:].mean()
        
        self.rsiValue = am.rsi(self.rsiLength)

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

            # ATR数值上穿其移动平均线,说明行情短期内波动加大
            # 即处于趋势的概率较大,适合CTA开仓
            if self.atrValue > self.atrMa:
                # 使用RSI指标的趋势行情时,会在超买超卖区钝化特征,作为开仓信号
                if self.rsiValue > self.rsiBuy:
                    # 这里为了保证成交,选择超价5个整指数点下单
                    self.buy(bar.close+5, self.fixedSize)

                elif self.rsiValue < self.rsiSell:
                    self.short(bar.close-5, self.fixedSize)

        # 持有多头仓位
        elif self.pos > 0:
            # 计算多头持有期内的最高价,以及重置最低价
            self.intraTradeHigh = max(self.intraTradeHigh, bar.high)
            self.intraTradeLow = bar.low
            
            # 计算多头移动止损
            longStop = self.intraTradeHigh * (1-self.trailingPercent/100)

            # 发出本地止损委托
            self.sell(longStop, abs(self.pos), stop=True)
            
        # 持有空头仓位
        elif self.pos < 0:
            self.intraTradeLow = min(self.intraTradeLow, bar.low)
            self.intraTradeHigh = bar.high

            shortStop = self.intraTradeLow * (1+self.trailingPercent/100)
            self.cover(shortStop, abs(self.pos), stop=True)

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

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

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

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

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Ejemplo n.º 13
0
class LastGoldStrategy(CtaTemplate):
    """基于King Keltner通道的交易策略"""
    className = 'LastGoldStrategy'
    author = '中融致信投资技术部'

    # 策略参数
    initDays = 10  # 数据初始化天数

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

        self.bm = BarManager(self.onBar)  # 创建K线合成器对象
        # self.am = ArrayManager2(size=120)

        self.fixedSize = 1  # 每次交易的数量
        self.night_open_price = None  # 夜盘开盘价 (21:00)
        self.night_mid_price = None  # 盘中参考价(22:30)

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

        # 载入历史数据,并采用回放计算的方式初始化策略数值
        # initData = self.loadBar(self.initDays)
        # for bar in initData:
        #     self.onBar(bar)

        self.putEvent()

    #----------------------------------------------------------------------
    def onStart(self):
        """启动策略(必须由用户继承实现)"""
        self.writeCtaLog('%s策略启动' % self.name)
        self.putEvent()

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

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

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        # 保存K线数据
        # am = self.am
        # am.updateBar(bar)
        # 如果k先还没有初始化完成,就不执行
        # if not am.inited:
        #     return
        # 获取当前时间
        time_now = bar.datetime.time()
        # 21:00:00 记住开盘价
        if time_now == datetime.time(hour=21, minute=0, second=0):
            self.night_open_price = bar.open
        # 记住22:30:00的价格
        elif time_now == datetime.time(hour=22, minute=30, second=0):
            self.night_mid_price = bar.open

        # 没有加载到比较数据,直接返回
        if self.night_open_price is None or self.night_mid_price is None:
            return

        # 22:58分开仓
        if time_now == datetime.time(hour=22, minute=58, second=0):
            if self.pos == 0:
                # 趋势: 1向上, -1向下,0无趋势
                trend_l = 0  # 长趋势
                trend_s = 0  # 短趋势
                if bar.close - self.night_mid_price > bar.close * 0.005:
                    trend_s = 1
                if bar.close - self.night_open_price > bar.close * 0.005:
                    trend_l = 1
                if bar.close - self.night_mid_price < 0 - bar.close * 0.005:
                    trend_s = -1
                if bar.close - self.night_open_price < 0 - bar.close * 0.005:
                    trend_l = -1

                # 有其中一个趋势或者趋势共振
                if trend_s + trend_l >= 1:
                    self.buy(price=bar.close + 0.0, volume=self.fixedSize)

                elif trend_s + trend_l <= -1:
                    self.short(price=bar.close - 0.0, volume=self.fixedSize)

        # 9:05平仓所有
        elif time_now == datetime.time(hour=9, minute=4, second=0):
            self.closeAllPosition(bar)

        # 如果没有开仓成功则撤单
        elif time_now == datetime.time(hour=23, minute=28, second=0):
            self.cancelAll()

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

    def onTrade(self, trade):
        """收到交易发生事件推送"""
        pass

    def onStopOrder(self, so):
        """收到停止单事件推送"""
        self.putEvent()

    def closeAllPosition(self, bar):
        """平掉所有仓位"""
        self.cancelAll()
        if self.pos > 0:
            self.sell(price=bar.close - 3.0, volume=self.fixedSize)
        elif self.pos < 0:
            self.cover(price=bar.close + 3.0, volume=self.fixedSize)
Ejemplo n.º 14
0
class RBreakStrategy(CtaTemplate):
    """改进型RBreak策略"""
    className = "RBreakStrategy"
    autor = "张英杰"

    # 策略参数
    initDays = 10  # 数据初始化天数
    N2 = 8.5
    N3 = 5.0
    N4 = 6.0
    N5 = 7.5
    N6 = 4.5
    fixedSize = 1  # 每次交易数量

    # 策略变量
    intraTradeHigh = 0.0  # 移动止损用的持仓期内最高价
    intraTradeLow = 0.0  # 移动止损用的持仓期内最低价
    open_price = None  # 最新开仓价格
    order_list = []  # 下单列表

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

                 ]

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

               ]

    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(RBreakStrategy, self).__init__(ctaEngine, setting)

        # 创建bar管理器(K线合成对象),用于合成bar和处理自定义周期的bar回调函数
        self.bm = BarManager(onBar=self.onBar, xmin=5, onXminBar=self.onFifteenBar)
        # 创建k线序列管理工具
        self.am = ArrayManager2()
        self.dam = DailyArrayManager()

        # 策略变量
        self.date = None      # 日期
        self.pre_date = None  # 上个交易日日期
        # 基础数据获取
        self.HH1 = 0.  # 上个交易日收盘bar最高价
        self.LL1 = 0.  # 上个交易日收盘bar最低价
        self.CC1 = 0.  # 上个交易日收盘价
        self.HH2 = 0.  # 前个交易日收盘bar最高价
        self.LL2 = 0.  # 前个交易日收盘bar最低价

        self.C1 = 0.  # 当日开盘价
        self.MN1 = 0.  # MN1=当日开盘价/2 + (昨日最高+昨日最低+昨日收盘)/6
        self.RANGE1 = 0.  # RANGE1 = (昨日最高-昨日最低)*0.65 + (前日最高-前日最低)*0.35
        self.SIZECK1 = 0.  # SIZECK1 = (当前BAR收盘价 - 当前BAR开盘价)的绝对值/当前BAR收盘价   < 0.5%  振幅不超过0.5%
        self.SIZECK2 = 0.
        #
        self.U2 = 0.  # 追买中轴线
        self.U3 = 0.  # 追买止损线
        self.U4 = 0.  # 卖出止损线
        self.U5 = 0.  # 卖出中轴线
        self.U6 = 0.  # 突破做空

        self.D6 = 0.  # 突破做多
        self.D5 = 0.  # 做多中轴线
        self.D4 = 0.  # 做多止损线
        self.D3 = 0.  # 追卖止损线
        self.D2 = 0.  # 追卖中轴线

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

        # 载入历史数据,并采用回放计算的方式初始化策略数值
        initData = self.loadBar(days=self.initDays)
        # 预处理初始化的bar
        for bar in initData:
            self.onBar(bar)

        # 发出策略状态变化事件
        self.putEvent()

    def onStart(self):
        '''启动策略(必须由用户继承实现)'''
        self.writeCtaLog("%s策略启动" % self.name)

        # 发出策略状态变化事件
        self.putEvent()  # 目前的结论是回测时候该方法为pass,实盘通常用于通知界面更新

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

        # 发出策略状态变化事件
        self.putEvent()

    def onTick(self, tick):
        '''收到TICK推送,必须由用户继承实现'''
        # 更新tick,合成k线
        self.bm.updateTick(tick)

    def onBar(self, bar):
        """收到bar推送(必须由用户继承实现)"""
        self.bm.updateBar(bar)  # 一分钟一个bar,执行周期大于1分钟的策略在自定义的执行方法里,到时间了由bm.updataBar回调执行

    def onFifteenBar(self, bar):
        '''收到15分钟K线推送的回调函数'''

        if bar.date == "20171222":
            print(111)

        # 保存K线数据
        am = self.am
        am.updateBar(bar)

        # 保存日K数据
        dam = self.dam
        dam.updateBar(bar)

        # 日期更换
        # 第一天
        if self.date is None:
            self.date = bar.date
        # 更换日期
        elif self.date != bar.date:
            self.pre_date = self.date
            self.date = bar.date

            self.CC1 = dam.close[-2]  # 上个交易日收盘价
            self.HH2 = self.HH1  # 前个交易日收盘bar最高价
            self.LL2 = self.LL1  # 前个交易日收盘bar最低价

            self.HH1 = am.close[-2]  # 重置昨日每个bar收盘最高价
            self.LL1 = am.close[-2]  # 重置昨日每个bar收盘最低价

            for i in range(-3, -100, -1):
                if str(am.date[i]) != self.pre_date:
                    break
                # 基础数据计算

                self.HH1 = max(am.close[i], self.HH1)  # 上个交易日收盘bar最高价
                self.LL1 = min(am.close[i], self.LL1)  # 上个交易日收盘bar最低价

            self.C1 = dam.open[-1]  # 当日开盘价
            self.MN1 = self.C1 / 2 + (self.HH1 + self.LL1 + self.CC1) / 6  # MN1=当日开票价/2 + (昨日最高+昨日最低+昨日收盘)/6
            self.RANGE1 = (self.HH1 - self.LL1) * 0.65 + (self.HH2 - self.LL2) * 0.35  # RANGE1 = (昨日最高-昨日最低)*0.65 + (前日最高-前日最低)*0.35

            # 参数计算
            self.U2 = self.MN1 + self.RANGE1 * self.N2 / 10  # 追买中轴线
            self.U3 = self.MN1 + self.RANGE1 * self.N3 / 10  # 追买止损线
            self.U4 = self.MN1 + self.RANGE1 * self.N4 / 10  # 卖出止损线
            self.U5 = self.MN1 + self.RANGE1 * self.N5 / 10  # 卖出中轴线
            self.U6 = self.MN1 + self.RANGE1 * self.N6 / 10  # 突破做空

            self.D6 = self.MN1 - self.RANGE1 * self.N6 / 10  # 突破做多
            self.D5 = self.MN1 - self.RANGE1 * self.N5 / 10  # 做多中轴线
            self.D4 = self.MN1 - self.RANGE1 * self.N4 / 10  # 做多止损线
            self.D3 = self.MN1 - self.RANGE1 * self.N3 / 10  # 追卖止损线
            self.D2 = self.MN1 - self.RANGE1 * self.N2 / 10  # 追卖中轴线

        # 如果k线还没有初始化完成,就不执行
        if not am.inited:
            return
        # 如果日k线还没有初始化完成,就不执行
        if not dam.inited:
            return

        # 当前bar上下开仓的振幅是否符合条件
        self.SIZECK1 = abs(bar.close - bar.open) / bar.close < 5 / 1000  # SIZECK1 = (当前BAR收盘价 - 当前BAR开盘价)的绝对值/当前BAR收盘价   < 0.5%  振幅不超过0.5%
        self.SIZECK2 = abs(bar.close - bar.open) / bar.close < 5 / 1000



        # 交易决策
        # 1.观察区突破开仓
        time_now = bar.datetime.time()
        time_0915 = time_now.replace(hour=9, minute=15, second=0)

        time_1429 = time_now.replace(hour=14, minute=29, second=0)
        time_1500 = time_now.replace(hour=15, minute=0, second=0)
        time_last = time_now.replace(hour=15, minute=14, second=0)

        # 空仓
        if self.pos == 0:
            # 持有期内最高最低价
            self.intraTradeHigh = bar.close
            self.intraTradeLow = bar.close
            # self.open_price = None

            # 9:15 -- 14:29 之间
            if time_now >= time_0915 and time_now <= time_1429:
                # 价格下穿U6,股价前30个BAR(不包括当前)的收盘最高值大于U5,当前BAR振幅小于0.5%,开空头
                if am.close[-1] < self.U6 and am.close[-2] >= self.U6 and am.close[-3] > self.U6 and am.close[-31: -1].max() > self.U5 and self.SIZECK2:
                    self.cancelAll()
                    self.short(price=bar.close - 0.01, volume=self.fixedSize)
                    # self.open_price = bar.close
                # 价格上穿D6,最近30个BAR收盘价(不包括当前)的最小值小于D5,当前BAR振幅小于0.5%,开多头
                if am.close[-1] > self.D6 and am.close[-2] <= self.D6 and am.close[-3] < self.D6 and am.close[-31: -1].min() < self.D5 and self.SIZECK1:
                    self.cancelAll()
                    self.buy(price=bar.close + 0.01, volume=self.fixedSize)
                    self.open_price = bar.close

            # 时间在9:50和14:29之间 TIME>0915 && TIME<1500
            if time_now >= time_0915 and time_now <= time_1500:
                # && CROSSUP(C,U2) && SIZECK1,BK 突破开仓
                if am.close[-1] > self.U2 and am.close[-2] <= self.U2 and am.close[-3] < self.U2 and self.SIZECK1:
                    self.cancelAll()
                    self.buy(price=bar.close + 0.01, volume=self.fixedSize)
                    # self.open_price = bar.close
                # CROSSDOWN(C,D2) && SIZECK2,SK;
                elif am.close[-1] < self.D2 and am.close[-2] >= self.D2 and am.close[-3] > self.D2 and self.SIZECK2:
                    self.cancelAll()
                    self.short(price=bar.close - 0.01, volume=self.fixedSize)
                    # self.open_price = bar.close


        # 持有多头:
        elif self.pos > 0:
            self.intraTradeHigh = max(self.intraTradeHigh, bar.close)
            self.intraTradeLow = min(self.intraTradeLow, bar.close)

            #  价格上穿U6,止盈
            if am.close[-1] > self.U6 and am.close[-2] <= self.U6:
                self.cancelAll()
                self.sell(price=bar.close - 0.01, volume=self.fixedSize)
            # 价格下穿D4,止损
            elif am.close[-1] < self.D4 and am.close[-2] >= self.U6:
                self.cancelAll()
                self.sell(price=bar.close - 0.01, volume=self.fixedSize)
            # 价格下穿U3,平仓
            elif am.close[-1] < self.U3 and am.close[-2] >= self.U3:
                self.cancelAll()
                self.sell(price=bar.close - 0.01, volume=self.fixedSize)
            # 上一次买入到现在(不含当前bar)的最高价 > 买入价格 * (1 + 0.002), 并且 (当前收盘价 - 成本)<= (到目前为止收盘最高价 - 成本)* 0.5

            elif self.intraTradeHigh > self.open_price * (1 + 0.002) and (am.close[-1] - self.open_price) <= (
                self.intraTradeHigh - self.open_price) * 0.5:
                self.cancelAll()
                self.sell(price=bar.close - 0.01, volume=self.fixedSize)
            # 价格下穿 开仓价格 * (1 - 0.9/1000) 止损
            elif am.close[-1] < self.open_price * (1 - 0.9 / 1000) and am.close[-2] >= self.open_price * (
                1 - 0.9 / 1000):
                self.cancelAll()
                self.sell(price=bar.close - 0.01, volume=self.fixedSize)


        # 持有空头;
        elif self.pos < 0:
            self.intraTradeHigh = max(self.intraTradeHigh, bar.close)
            self.intraTradeLow = min(self.intraTradeLow, bar.close)

            # 价格下穿D6,平掉空头,止盈
            if am.close[-1] < self.D6 and am.close[-2] >= self.D6:
                self.cancelAll()
                self.cover(price=bar.close + 0.01, volume=self.fixedSize)
            # 价格上穿U4,平掉空头(止损)
            elif am.close[-1] > self.U4 and am.close[-2] <= self.U4:
                self.cancelAll()
                self.cover(price=bar.close + 0.01, volume=self.fixedSize)
            # 价格上穿D3,平仓
            elif am.close[-1] > self.D3 and am.close[-2] <= self.D3:
                self.cancelAll()
                self.cover(price=bar.close + 0.01, volume=self.fixedSize)
            # 上一次买入到现在(不含当前bar)的最低价 < 买入价格 * (1 + 0.002), 并且 (成本 - 当前收盘价)<= (成本 - 到目前为止收盘最低价)* 0.5  止盈
            elif self.intraTradeLow < self.open_price * (1 - 0.002) and self.open_price - bar.close <= (
                self.open_price - self.intraTradeLow) * 0.5:
                self.cancelAll()
                self.cover(price=bar.close + 0.01, volume=self.fixedSize)
            # 价格上 开仓价格 * (1 + 0.9 / 1000) 止损
            elif am.close[-1] > self.open_price * (1 + 0.9 / 1000) and am.close[-2] <= self.open_price * (
                1 + 0.9 / 1000):
                self.cancelAll()
                self.cover(price=bar.close + 0.01, volume=self.fixedSize)

        # 当天收盘则平仓所有
        if time_now >= time_last and bar.datetime.weekday() == 5 - 1:
            self.closeAllPosition(bar)

        self.putEvent()

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

    def onTrade(self, trade):
        """收到交易发生事件推送"""
        if trade.offset == "平仓":
            self.open_price = None

        if trade.offset == "开仓":
            self.open_price = trade.price

        self.putEvent()

    def onStopOrder(self, so):
        """收到停止单事件推送"""
        self.putEvent()

    def closeAllPosition(self, bar):
        self.cancelAll()
        if self.pos > 0:
            self.sell(price=bar.close - 0.01, volume=self.fixedSize)
        elif self.pos < 0:
            self.cover(price=bar.close + 0.01, volume=self.fixedSize)
Ejemplo n.º 15
0
class BollChannelStrategy(CtaTemplate):
    """基于布林通道的交易策略"""
    className = 'BollChannelStrategy'
    author = u'用Python的交易员'

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

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

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

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

    #----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(BollChannelStrategy, self).__init__(ctaEngine, setting)
        
        self.bm = BarManager(self.onBar, 15, self.onXminBar)        # 创建K线合成器对象
        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 onXminBar(self, bar):
        """收到X分钟K线"""
        # 全撤之前发出的委托
        self.cancelAll()
    
        # 保存K线数据
        am = self.am
        
        am.updateBar(bar)
        
        if not am.inited:
            return
        
        # 计算指标数值
        self.bollUp, self.bollDown = am.boll(self.bollWindow, self.bollDev)
        self.cciValue = am.cci(self.cciWindow)
        self.atrValue = am.atr(self.atrWindow)
        
        # 判断是否要进行交易
    
        # 当前无仓位,发送开仓委托
        if self.pos == 0:
            self.intraTradeHigh = bar.high
            self.intraTradeLow = bar.low            
            
            if self.cciValue > 0:
                self.buy(self.bollUp, self.fixedSize, True)
                
            elif self.cciValue < 0:
                self.short(self.bollDown, self.fixedSize, True)
    
        # 持有多头仓位
        elif self.pos > 0:
            self.intraTradeHigh = max(self.intraTradeHigh, bar.high)
            self.intraTradeLow = bar.low
            self.longStop = self.intraTradeHigh - self.atrValue * self.slMultiplier
            
            self.sell(self.longStop, abs(self.pos), True)
    
        # 持有空头仓位
        elif self.pos < 0:
            self.intraTradeHigh = bar.high
            self.intraTradeLow = min(self.intraTradeLow, bar.low)
            self.shortStop = self.intraTradeLow + self.atrValue * self.slMultiplier
            
            self.cover(self.shortStop, abs(self.pos), True)
    
        # 发出状态更新事件
        self.putEvent()        

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

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

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Ejemplo n.º 16
0
 def __init__(self, ctaEngine, setting):
     """Constructor"""
     super(BollChannelStrategy, self).__init__(ctaEngine, setting)
     
     self.bm = BarManager(self.onBar, 15, self.onXminBar)        # 创建K线合成器对象
     self.am = ArrayManager()
Ejemplo n.º 17
0
    def loadSetting(self):
        """加载配置"""
        with open(self.settingFilePath) as f:
            drSetting = json.load(f)

            # 如果working设为False则不启动行情记录功能
            working = drSetting['working']
            if not working:
                return

            # Tick记录配置
            if 'tick' in drSetting:
                l = drSetting['tick']

                for setting in l:
                    symbol = setting[0]
                    gateway = setting[1]
                    vtSymbol = symbol

                    req = VtSubscribeReq()
                    req.symbol = setting[0]

                    # 针对LTS和IB接口,订阅行情需要交易所代码
                    if len(setting) >= 3:
                        req.exchange = setting[2]
                        vtSymbol = '.'.join([symbol, req.exchange])

                    # 针对IB接口,订阅行情需要货币和产品类型
                    if len(setting) >= 5:
                        req.currency = setting[3]
                        req.productClass = setting[4]

                    self.mainEngine.subscribe(req, gateway)

                    #tick = VtTickData()           # 该tick实例可以用于缓存部分数据(目前未使用)
                    #self.tickDict[vtSymbol] = tick
                    self.tickSymbolSet.add(vtSymbol)

                    # 保存到配置字典中
                    if vtSymbol not in self.settingDict:
                        d = {
                            'symbol': symbol,
                            'gateway': gateway,
                            'tick': True
                        }
                        self.settingDict[vtSymbol] = d
                    else:
                        d = self.settingDict[vtSymbol]
                        d['tick'] = True

            # 分钟线记录配置
            if 'bar' in drSetting:
                l = drSetting['bar']

                for setting in l:
                    symbol = setting[0]
                    gateway = setting[1]
                    vtSymbol = symbol

                    req = VtSubscribeReq()
                    req.symbol = symbol

                    if len(setting) >= 3:
                        req.exchange = setting[2]
                        vtSymbol = '.'.join([symbol, req.exchange])

                    if len(setting) >= 5:
                        req.currency = setting[3]
                        req.productClass = setting[4]

                    self.mainEngine.subscribe(req, gateway)

                    # 保存到配置字典中
                    if vtSymbol not in self.settingDict:
                        d = {'symbol': symbol, 'gateway': gateway, 'bar': True}
                        self.settingDict[vtSymbol] = d
                    else:
                        d = self.settingDict[vtSymbol]
                        d['bar'] = True

                    # 创建BarManager对象
                    self.bmDict[vtSymbol] = BarManager(self.onBar)

            # 主力合约记录配置
            if 'active' in drSetting:
                d = drSetting['active']
                self.activeSymbolDict = {
                    vtSymbol: activeSymbol
                    for activeSymbol, vtSymbol in d.items()
                }
Ejemplo n.º 18
0
class tick_strategy(CtaTemplate):
    """结合ATR和RSI指标的一个分钟线交易策略"""
    className = 'CN'
    author = u'张安翔'
    buyOrderIDList = []  # 委托买入开仓的委托号
    shortOrderIDList = []  # 委托卖出开仓的委托号
    orderList = []  # 保存委托代码的列表

    # 参数列表,保存了参数的名称
    paramList = [
        'name', 'className', 'author', 'vtSymbol', 'maxHold', 'maxWin',
        'minLose', 'mutiple', 'volume', 'init_asset', 'minEnterPrice',
        'MaxTolerate'
    ]

    # 变量列表,保存了变量的名称
    varList = [
        'LongSignalSpread', 'ShortSignalSpread', 'pos', 'atrValue', 'atrMa',
        'rsiValue', 'rsiBuy', 'rsiSell'
    ]

    def __init__(self, ctaEngine, setting):

        # 策略参数
        self.contract_size = 100
        self.MaxTolerate = 0
        self.maxHold = 0
        self.Ticks = 4  #追单数量
        self.stopping = False
        self.stoppingdt = None  # 止损后最小开仓时间
        self.stoppPeriods = 15  # 止损后15分钟不能开仓
        self.ShortSignalSpread = None
        self.LongSignalSpread = None
        self.short_enter_price = None
        self.short_exit_price = None
        self.long_enter_price = None
        self.long_exit_price = None
        self.maxHold = 0
        self.maxWin = 0
        self.minLose = 0
        self.mutiple = 0
        self.minEnterPrice = 0
        self.volume = 0
        self.init_asset = 0
        """Constructor"""
        super(tick_strategy, self).__init__(ctaEngine, setting)

        # 策略变量
        self.bm = BarManager(self.onBar, 1)  # 创建K线合成器对象
        self.am = ArrayManager()

        # # time.sleep(5)
        # ct = VtContractData()
        # ct.gatewayName = "ONETOKEN"
        # ct.symbol = 'huobip/btc.usdt'
        # ct.exchange = 'huobip'
        # ct.vtSymbol = 'huobip/btc.usdt'
        # self.ctaEngine.mainEngine.dataEngine.contractDict['huobip/btc.usdt'] = ct
        # self.ctaEngine.mainEngine.dataEngine.saveContracts()
        # ctaEngine.subscribe(req, 'ONETOKEN')

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

        # 载入历史数据,并采用回放计算的方式初始化策略数值

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

    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)
        dt = tick.datetime
        # TODO: 计算spread
        preSpread = self.spread
        self.spread = new_spread  # 更近spread
        spread = self.spread

        price = tick.lastPrice
        if self.long_enter:  # 判断信号
            if self.LongSignalSpread + self.MaxTolerate > spread:
                self.buyOrderIDList.append(self.buy(price, 1))  # 开多
                self.count = 0
                self.maxdt = dt + datetime.timedelta(
                    minutes=self.maxHold)  # 只持仓到那个时间点
                self.minExitdt = dt + datetime.timedelta(
                    minutes=0.5)  # TODO:半分钟,or不要?
            else:
                if self.count == self.Ticks:
                    self.qidan(price, dt, spread, direction='long')
                    self.count = 0

                else:
                    self.count += 1

        elif self.short_enter:
            if self.ShortSignalSpread - self.MaxTolerate < spread:
                self.shortOrderIDList.append(self.short(price, 1))  # 卖空
                self.count = 0
                self.maxdt = dt + datetime.timedelta(minutes=self.maxHold)
                self.minExitdt = dt + datetime.timedelta(minutes=0.5)  # TODO

            else:  # 经过几个tick后还未达到想要的价格,就弃单
                if self.count == self.Ticks:
                    self.qidan(price, dt, spread, direction='short')
                    self.count = 0

                else:
                    self.count += 1

        elif self.short_exit:
            if self.count == self.Ticks:
                self.buyOrderIDList.append(self.cover(price, 1))  # 平空
                self.count = 0
                if self.stopwinning or self.stopLosing:
                    self.stopping = True
                    self.stoppingdt = dt + datetime.timedelta(
                        minutes=self.stoppPeriods)
                    self.maxdt = None
                    self.minExitdt = None

                else:
                    self.maxdt = None
                    self.minExitdt = None
                    self.minEnterdt = dt + datetime.timedelta(minutes=0.5)

            else:
                self.count += 1

        elif self.long_exit:
            if self.count == self.Ticks:
                self.shortOrderIDList.append(self.sell(price, 1))  # 平多
                self.count = 0
                if self.stopwinning or self.stopLosing:
                    self.stopping = True
                    self.stoppingdt = dt + datetime.timedelta(
                        minutes=self.stoppPeriods)
                    self.maxdt = None
                    self.minExitdt = None

                else:
                    self.maxdt = None
                    self.minExitdt = None
                    self.minEnterdt = dt + datetime.timedelta(minutes=0.5)
            else:
                self.count += 1

        self.ResetSignal()
        dtAbove = datetime.datetime.combine(dt.date(),
                                            datetime.time(dt.hour, dt.minute))
        try:
            # TODO: 需要计算Std,std是一小时1min_bar的收盘价的std
            std = self.cal_std()
        except:
            std = np.nan

        # 开空仓信号
        if not self.stopping:
            if self.pos == 0:
                if dt > self.minEnterdt:  # 如果满足最小进场时间
                    if preSpread:
                        if ((spread - preSpread) > self.minEnterPrice
                            ) or (spread - preSpread) > +self.mutiple * std:
                            self.short_enter = True
                            self.ShortSignalSpread = spread

                        elif ((preSpread - spread) > self.minEnterPrice
                              ) or (preSpread - spread) > self.mutiple * std:
                            self.long_enter = True
                            self.LongSignalSpread = spread
                        else:
                            pass

            if self.pos == -1:
                if dt > self.minExitdt:  # 如果满足最小进场时间
                    if dt >= self.maxdt:  # 如果超过最大持仓时间
                        self.short_exit = True
                        self.ShortSignalSpread = spread

                    else:
                        if (self.short_enter_price -
                                spread) > self.maxWin:  # 止盈
                            self.short_exit = True
                            self.stopwinning = True
                            self.ShortSignalSpread = spread

                        elif (spread -
                              self.short_enter_price) > self.minLose:  # 止损
                            self.short_exit = True
                            self.stopLosing = True
                            self.ShortSignalSpread = spread
                        else:
                            pass

            if self.pos == 1:  # 若有仓位
                if dt > self.minExitdt:  # 若符合最小进场时间
                    if dt >= self.maxdt:  # 若超过最大持仓周期
                        self.long_exit = True
                        self.LongSignalSpread = spread

                    else:
                        if (spread -
                                self.long_enter_price) > self.maxWin:  # 止盈
                            self.long_exit = True
                            self.stopwinning = True
                            self.LongSignalSpread = spread

                        elif (self.long_enter_price -
                              spread) > self.minLose:  # 止损
                            self.long_exit = True
                            self.stopLosing = True
                            self.LongSignalSpread = spread

                        else:
                            pass
        else:
            if dt >= self.stoppingdt:
                self.stopping = False
                self.stoppingdt = None

    def updateTick(self, event):
        print('-' * 30, 'strategy_updateTick', '-' * 30)

    def onBar(self, bar):
        self.bm.updateBar(bar)

    '''交易后的账户余额或保证金'''

    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        # print(order)
        # self.writeCtaLog(u'委托变化推送: %s' % order)
        # pass

    def onTrade(self, trade):
        if self.pos != 0:
            # 多头开仓成交后,撤消空头委托
            if self.pos > 0:
                for shortOrderID in self.shortOrderIDList:
                    self.cancelOrder(shortOrderID)
            # 反之同样
            elif self.pos < 0:
                for buyOrderID in self.buyOrderIDList:
                    self.cancelOrder(buyOrderID)

            # 移除委托号
            for orderID in (self.buyOrderIDList + self.shortOrderIDList):
                if orderID in self.orderList:
                    self.orderList.remove(orderID)

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

    def ResetSignal(self):
        self.long_enter = False
        self.long_exit = False
        self.short_enter = False
        self.short_exit = False
        self.stopwinning = False
        self.stopLosing = False

    def cal_std(self):
        pass

    def getPos(self):
        """获取cn仓位"""
        # 0:空仓,1:做多,-1:做空 老版本的,已废除
        # fileName = 'CTA_setting.json'
        # try:
        #     f = file(fileName)
        # except IOError:
        #     print('读取param参数配置出错,请检查')
        # # 解析json文件-----------------------------------------------------
        # mysetting = json.load(f)
        # if self.pair == 'sc_wti':
        #     cnvtSymbol = str(mysetting[0]['vtSymbol'])
        #     usvtSymbol = str(mysetting[1]['vtSymbol']).split('.')[0]
        # elif self.pair == 'brent_sc':
        #     cnvtSymbol = str(mysetting[3]['vtSymbol'])
        #     usvtSymbol = str(mysetting[2]['vtSymbol']).split('.')[0]
        # reqID = self.api.getTrades({'instrument': usvtSymbol})
        # cnPosObj = self.banzhuan_query_position(cnvtSymbol)
        cnPosObj = self.banzhuan_query_position()  # 已改为不传参数,待测试是否有效
        # print '-------------------------昨仓今仓-------------------------\nlongYd:', cnPosObj.longYd, '\nlongTd:', cnPosObj.longTd, '\nshortYd:', cnPosObj.shortYd, '\nshortTd:', cnPosObj.shortTd
        # self.longYd = cnPosObj.longYd   # vtEngine.py 633行。昨仓今仓分别获取。
        # self.longTd = cnPosObj.longTd
        # self.shortYd = cnPosObj.shortYd
        # self.shortTd = cnPosObj.shortTd
        self.r.set('cnpositionlongYd', cnPosObj.longYd)
        self.r.set('cnpositionlongTd', cnPosObj.longTd)
        self.r.set('cnpositionshortYd', cnPosObj.shortYd)
        self.r.set('cnpositionshortTd', cnPosObj.shortTd)
Ejemplo n.º 19
0
class DualThrustStrategy(CtaTemplate):
    """DualThrust交易策略"""
    className = 'DualThrustStrategy'
    author = u'用Python的交易员'

    # 策略参数
    fixedSize = 100
    k1 = 0.4
    k2 = 0.6

    initDays = 10

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

    dayOpen = 0
    dayHigh = 0
    dayLow = 0

    range = 0
    longEntry = 0
    shortEntry = 0
    exitTime = time(hour=14, minute=55)

    longEntered = False
    shortEntered = False

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

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

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

        self.bm = BarManager(self.onBar)
        self.barList = []

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

        # 载入历史数据,并采用回放计算的方式初始化策略数值
        initData = self.loadBar(self.initDays)
        for bar in initData:
            self.onBar(bar)

        self.putEvent()

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

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

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

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

        # 计算指标数值
        self.barList.append(bar)

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

        # 新的一天
        if lastBar.datetime.date() != bar.datetime.date():
            # 如果已经初始化
            if self.dayHigh:
                self.range = self.dayHigh - self.dayLow
                self.longEntry = bar.open + self.k1 * self.range
                self.shortEntry = bar.open - self.k2 * self.range

            self.dayOpen = bar.open
            self.dayHigh = bar.high
            self.dayLow = bar.low

            self.longEntered = False
            self.shortEntered = False
        else:
            self.dayHigh = max(self.dayHigh, bar.high)
            self.dayLow = min(self.dayLow, bar.low)

        # 尚未到收盘
        if not self.range:
            return

        if bar.datetime.time() < self.exitTime:
            if self.pos == 0:
                if bar.close > self.dayOpen:
                    if not self.longEntered:
                        self.buy(self.longEntry, self.fixedSize, stop=True)
                else:
                    if not self.shortEntered:
                        self.short(self.shortEntry, self.fixedSize, stop=True)

            # 持有多头仓位
            elif self.pos > 0:
                self.longEntered = True

                # 多头止损单
                self.sell(self.shortEntry, self.fixedSize, stop=True)

                # 空头开仓单
                if not self.shortEntered:
                    self.short(self.shortEntry, self.fixedSize, stop=True)

            # 持有空头仓位
            elif self.pos < 0:
                self.shortEntered = True

                # 空头止损单
                self.cover(self.longEntry, self.fixedSize, stop=True)

                # 多头开仓单
                if not self.longEntered:
                    self.buy(self.longEntry, self.fixedSize, stop=True)

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

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

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

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

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Ejemplo n.º 20
0
class KkStrategyTest(CtaTemplate):
    """基于King Keltner通道的交易策略"""
    className = 'KkStrategyTest'
    author = u'用Python的交易员'

    # 策略参数
    kkLength = 11  # 计算通道中值的窗口数
    kkDev = 1.6  # 计算通道宽度的偏差
    trailingPrcnt = 0.8  # 移动止损
    initDays = 10  # 初始化数据所用的天数
    fixedSize = 1  # 每次交易的数量

    # 策略变量
    kkUp = 0  # KK通道上轨
    kkDown = 0  # KK通道下轨
    intraTradeHigh = 0  # 持仓期内的最高点
    intraTradeLow = 0  # 持仓期内的最低点

    buyOrderIDList = []  # OCO委托买入开仓的委托号
    shortOrderIDList = []  # OCO委托卖出开仓的委托号
    orderList = []  # 保存委托代码的列表

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

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

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

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

        self.bm = BarManager(self.onBar, 5, self.onFiveBar)  # 创建K线合成器对象
        self.am = ArrayManager()

        self.buyOrderIDList = []
        self.shortOrderIDList = []
        self.orderList = []

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

        # 载入历史数据,并采用回放计算的方式初始化策略数值
        initData = self.loadBar(self.initDays)
        for bar in initData:
            self.onBar(bar)

        self.putEvent()

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

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

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

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

    #----------------------------------------------------------------------
    def onFiveBar(self, bar):
        """收到5分钟K线"""
        # 撤销之前发出的尚未成交的委托(包括限价单和停止单)
        for orderID in self.orderList:
            self.cancelOrder(orderID)
        self.orderList = []

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

        # 计算指标数值
        self.kkUp, self.kkDown = am.keltner(self.kkLength, self.kkDev)

        # 判断是否要进行交易

        # 当前无仓位,发送OCO开仓委托
        if self.pos == 0:
            self.intraTradeHigh = bar.high
            self.intraTradeLow = bar.low
            self.sendOcoOrder(self.kkUp, self.kkDown, self.fixedSize)

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

            l = self.sell(self.intraTradeHigh * (1 - self.trailingPrcnt / 100),
                          abs(self.pos), True)
            self.orderList.extend(l)

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

            l = self.cover(self.intraTradeLow * (1 + self.trailingPrcnt / 100),
                           abs(self.pos), True)
            self.orderList.extend(l)

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

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

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

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        if self.pos != 0:
            # 多头开仓成交后,撤消空头委托
            if self.pos > 0:
                for shortOrderID in self.shortOrderIDList:
                    self.cancelOrder(shortOrderID)
            # 反之同样
            elif self.pos < 0:
                for buyOrderID in self.buyOrderIDList:
                    self.cancelOrder(buyOrderID)

            # 移除委托号
            for orderID in (self.buyOrderIDList + self.shortOrderIDList):
                if orderID in self.orderList:
                    self.orderList.remove(orderID)

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

    #----------------------------------------------------------------------
    def sendOcoOrder(self, buyPrice, shortPrice, volume):
        """
        发送OCO委托
        
        OCO(One Cancel Other)委托:
        1. 主要用于实现区间突破入场
        2. 包含两个方向相反的停止单
        3. 一个方向的停止单成交后会立即撤消另一个方向的
        """
        # 发送双边的停止单委托,并记录委托号
        self.buyOrderIDList = self.buy(buyPrice, volume, True)
        self.shortOrderIDList = self.short(shortPrice, volume, True)

        # 将委托号记录到列表中
        self.orderList.extend(self.buyOrderIDList)
        self.orderList.extend(self.shortOrderIDList)

    #----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass
Ejemplo n.º 21
0
    def __init__(self, ctaEngine, setting):
        """Constructor"""
        super(DualThrustStrategy, self).__init__(ctaEngine, setting)

        self.bm = BarManager(self.onBar)
        self.barList = []
Ejemplo n.º 22
0
 def __init__(self, ctaEngine, setting):
     """Constructor"""
     super(DualThrustStrategy, self).__init__(ctaEngine, setting) 
     
     self.bm = BarManager(self.onBar)
     self.barList = []
Ejemplo n.º 23
0
class DoubleMaStrategy(CtaTemplate):
    """双指数均线策略Demo"""
    className = 'DoubleMaStrategy'
    author = u'用Python的交易员'

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

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

    slowMa0 = EMPTY_FLOAT
    slowMa1 = EMPTY_FLOAT

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

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

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

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

        self.bm = BarManager(self.onBar)
        self.am = ArrayManager()

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

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

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

        self.putEvent()

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

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

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

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        am = self.am
        am.updateBar(bar)
        if not am.inited:
            return

        # 计算快慢均线
        fastMa = am.sma(self.fastWindow, array=True)
        self.fastMa0 = fastMa[-1]
        self.fastMa1 = fastMa[-2]

        slowMa = am.sma(self.slowWindow, array=True)
        self.slowMa0 = slowMa[-1]
        self.slowMa1 = slowMa[-2]

        # 判断买卖
        crossOver = self.fastMa0 > self.slowMa0 and self.fastMa1 < self.slowMa1  # 金叉上穿
        crossBelow = self.fastMa0 < self.slowMa0 and self.fastMa1 > self.slowMa1  # 死叉下穿

        # 金叉和死叉的条件是互斥
        # 所有的委托均以K线收盘价委托(这里有一个实盘中无法成交的风险,考虑添加对模拟市价单类型的支持)
        if crossOver:
            # 如果金叉时手头没有持仓,则直接做多
            if self.pos == 0:
                self.buy(bar.close, 1)
            # 如果有空头持仓,则先平空,再做多
            elif self.pos < 0:
                self.cover(bar.close, 1)
                self.buy(bar.close, 1)
        # 死叉和金叉相反
        elif crossBelow:
            if self.pos == 0:
                self.short(bar.close, 1)
            elif self.pos > 0:
                self.sell(bar.close, 1)
                self.short(bar.close, 1)

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

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

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

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