vnpy,BollChannel布林线轨道策略分析


最近一致在用BollChannel轨道策略,也是VNPY原包提供的模版策略,修改了也不少,这里面就随便分析。BollChannel策略是很精巧的逻辑。基于15分钟K线轮询,利用阻止单跟随15分钟间的市场变动。

class BollChannelStrategy(CtaTemplate):

    """基于布林通道的交易策略"""

在VNPY中,每个策略都是一个类,继承CtaTemplate,这样也就继承了被实盘engine和回测engine调用启用的这样一套使用接口。

    className = 'BollChannelStrategy'

    author = u'用Python的交易员'

这两个参数是作为信息,体现在实盘运行界面中,可以看到和白色框中,是策略参数;下面黄色框中,是系统按市场盘面信息

和策略参数计算出的策略变量。
bb

    bollWindow = 22                     #布林通道窗口数

    bollDev = 3.1                       #布林通道的偏差

    cciWindow = 20                      # CCI窗口数

    atrWindow = 25                      # ATR窗口数

    slMultiplier = 5.0                  #计算止损距离的乘数

    initDays = 10                       #初始化数据所用的天数

    fixedSize = 1                       #每次交易的数量

    barMins = 15

   这些是策略参数,其中bollWindow和bollDev是用来计算布林线轨道信息,主要是上轨和下轨数值;

cciWindow是用来计算CCI Vaule,Commodity Channel lndex中文顺势指标,这个指标具体搜索,这边用来判断市场多空。

atrWindos是用来计算atrValue,atr是Average true range,意为平均真实波动幅度,计算具体搜索,这里用来计算波动幅度,为平仓作为标准

slMultiplier是一个计算止损的乘数。

initDays是定义初始的天数,虽然是15分钟k线,理论需要需要前几天数据用来计算策略变量。

fixedSize是每笔下单手数

barMins分析周期,用默认用15分钟k线。

这些参数都有默认值



    #策略变量

    bollUp = 0                          #布林通道上轨

    bollDown = 0                        #布林通道下轨

    cciValue = 0                        # CCI指标数值

    atrValue = 0                        # ATR指标数值

    

    intraTradeHigh = 0                  #持仓期内的最高点

    intraTradeLow = 0                   #持仓期内的最低点

    longStop = 0                        #多头止损

    shortStop = 0                       #空头止损

这些变量是系统计算,会在GUI界面中体现。

    #参数列表,保存了参数的名称

    paramList = ['name',

                 'className',

                 'author',

                 'vtSymbol',

                 'bollWindow',

                 'bollDev',

                 'cciWindow',

                 'atrWindow',

                 'slMultiplier',

                 'initDays',

                 'fixedSize',

                 'barMins']

用list承载参数,这个可以在回测用dict结构读取,比如{'bollWindow':15,'bollDev':3.4000000000000004,'slMultiplier':5.0,'cciWindow':20,'atrWindow':25, 'barMins':15}

实盘engine是读取CTA_setting.json文件中的,同一个策略的结构都是一样。

    #变量列表,保存了变量的名称

    varList = ['inited',

               'trading',

               'pos',

               'bollUp',

               'bollDown',

               'cciValue',

               'atrValue',

               'intraTradeHigh',

               'intraTradeLow',

               'longStop',

               'shortStop']  

    这个没什么好说,理论也是可以导入作为测试初始数据,但是没有测试过。

    #同步列表,保存了需要保存到数据库的变量名称

    syncList = ['pos',

                'intraTradeHigh',

                'intraTradeLow']    

后面同步方法时候,会把这几个数据写入数据库。其实会发现,保持的数据并不多,写入Mongodb的VnTrader_Log_Db。

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

    def __init__(self, ctaEngine, setting):

        """Constructor"""

        super(BollChannelStrategy, self).__init__(ctaEngine, setting)

        

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

        self.bg30 = BarGenerator(self.onBar, 28, self.on30minBar)

        self.am = ArrayManager()

对象初始化函数__init__,也是继承CtaTemplate,其中setting参数就是前面说的策略参数dict,导入后会更新策略对象参数。这里系统主要是通过实盘engine和回测engine来使用策略对象。

然后是定义k线合成器,是class BarGenerator实现,生成按照barMins,这里是15分钟来生成,当到barMins时候,系统会调用onXminBar的函数,这里也定义28分钟的K线,不过后面的方法是空的。

最后是实现class ArrayManager,这个类是K线序列管理工具,负责K线合并和指标计算。


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

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

这个是策略初始化时候操作,回测engine,和实盘engine都会调用,就是你看到绿色框中按钮,如果实盘按下,会调用这个函数;主要是按照初始化天数载入历史数据,这里的initData是一个包含bar信息的list,一般通过tushare能够获得就是1分钟bar。

然后回跑,这里会调用k线合成器里面的updateBar函数,计算出策略变量的值。最近把更新信息显示在前台。

最后和事件引擎相关;具体可以看看GitHub里面介绍。我的理解是把这个函数对应的事件放入事务队列,通知GUI更新,

bb

Bar的数据像如下,是dict结构,volume是交易量,exchange是交易所,symbol是品种,其他就是最高点最低点,和开盘价已经收盘价格。这个是在mongoDB里面VnTrader_1Min_Db的,没有品种就是一个collection。

{

   "_id":ObjectId("5acb43ccf1ed36627c163b1d"),

   "volume":1796.0,

   "gatewayName":"",

   "exchange":"SHFE",

   "symbol":"rb1810",

   "datetime":ISODate("2018-01-02T09:01:00.000+0000"),

   "high":3612.0,

   "rawData":null,

   "time":"090100",

   "date":"20180102",

   "close":3611.0,

   "openInterest":NumberInt(0),

   "open":3609.0,

   "vtSymbol":"rb1810.SHFE",

   "low":3606.0

}

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

    def onStart(self):

        """启动策略(必须由用户继承实现)"""

        self.writeCtaLog(u'%s策略启动' %self.name)

        self.putEvent()

然后是启动策略,系统会通知前台GUI更新。

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

    def onStop(self):

        """停止策略(必须由用户继承实现)"""

        self.writeCtaLog(u'%s策略停止' %self.name)

        self.putEvent()

然后是启动策略,系统会通知前台GUI更新。

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

    def onTick(self, tick):

        """收到行情TICK推送(必须由用户继承实现)""" 

        self.bg.updateTick(tick)

然后是收到tick,会调BarGenerator K线合成器的方法,根据tick数据合成一分钟bar,tick数据是报价和成交数据,updateTick函数会算出最近一分钟的最高价最低价,开盘和收盘价,还有成交量等bar需要数据。现在一般历史数据都是基于一分钟bar。国内期货交易商现在只提供一级的买卖报价信息,不像股票交易所提供5买入卖出高低5级别。基本做高频交易的路子就给封死了

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

    def onBar(self, bar):

        """收到Bar推送(必须由用户继承实现)"""

        self.bg.updateBar(bar)

    然后是收到bar,调用BarGenerator K线合成器的方法,更新一分钟bar信息。

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

def onXminBar(self, bar):

这个是最核心的函数,就是每隔15分钟k线后,运行的方法。

        """收到X分钟K线"""

        #全撤之前发出的委托

        self.cancelAll()

全撤所有委托,这里的委托并不是一定实际券商的委托,而且本地委托单;尤其像上期所不支持stoporder,都是通过本地条件单实现。这里是取消这些委托。

        #保存K线数据

        am = self.am

        am.updateBar(bar)

        if not am.inited:

            return

这里计算复制arraymanger,用AM去处理;这里说下,下面是ArrayManager的updateBar方法,缓存size默认是100,里面这些属性都是存储在list;
如果list没有填满100条,视为没有初始化完成,inited为默认false, count> 100时候,inited = True,初始化完成;
如果填满100条了,把后99条前推一位,把最新一条插入到最后。就是下面代码表示的。
这里面就是最初initdays的作用,通过十天数据,完成初始化。最近这里bar是15分钟bar。
然后还有一个情况是没有满100条时候,其实也是同样操作,因为新数据是从后端插入,也是整体前移直到填满100条后。


  1. classArrayManager(object):
  2. ……
  3. defupdateBar(self,bar):
  4.   """更新K线"""
  5.      self.count+=1
  6.      ifnotself.initedandself.count>=self.size:
  7.          self.inited=True
  8.      self.openArray[0:self.size-1]=self.openArray[1:self.size]
  9.      self.highArray[0:self.size-1]=self.highArray[1:self.size]
  10.      self.lowArray[0:self.size-1]=self.lowArray[1:self.size]
  11.      self.closeArray[0:self.size-1]=self.closeArray[1:self.size]
  12.      self.volumeArray[0:self.size-1]=self.volumeArray[1:self.size]
  13.      self.openArray[-1]=bar.open
  14.      self.highArray[-1]=bar.high
  15.      self.lowArray[-1]=bar.low
  16.      self.closeArray[-1]=bar.close
  17.      self.volumeArray[-1]=bar.volume



        #计算指标数值

        self.bollUp, self.bollDown = am.boll(self.bollWindow, self.bollDev)

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

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

AM根据那100条bar,可以按照策略参数,可以计算出策略变量,bollUp,BollDown,cciValue和atrVaule。AM具体计算方法可以查询,有些是是vnpy实现,有些是Ta-lib。

        #判断是否要进行交易

        #当前无仓位,发送开仓委托

        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)

这个是是否开仓,根据cciVaule,如果大于0,视为多方市场,开多买入,如果小于0,视为空方市场,开空单。多单开仓价格是bollup布林线上轨价格,空单价格是布林线下轨价格。这里的True是stop order阻止单,及当实际价格突破布林线上轨下单,如果没有突破,实际并没有下单。空单同理。但是这里k线是15分钟,其实存在15分钟时候脉冲式突破上轨,系统按照市价单下单,但是买在最高点情况。这个也是这个策略一个商榷地方。还有一个就是更新intraTradeHigh和intraTradeLow。

        #持有多头仓位

        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)

如果持有多单,按照bar.high和self.intraTradeHigh选出价高者,这个intraTradeHigh是多单开仓时候Kbar的最高点。卖出价格是这个价格减去atrVaule和Multipier乘机。也是开阻止单,当实际价格下跌到卖出价格时候按照市场价格销售。

        #持有空头仓位

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

保存pos仓位,intraTradeHigh和intraTradeLow到数据库,更新GUI界面。

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

    def onOrder(self, order):

        """收到委托变化推送(必须由用户继承实现)"""

        pass

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

    def onTrade(self, trade):

        #发出状态更新事件

        self.putEvent()

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

    def onStopOrder(self, so):

        """停止单推送"""

        pass

    

其他一些数据,为空


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/22259926/viewspace-2156067/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/22259926/viewspace-2156067/

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值