vnpy,BollChannel布林線軌道策略分析

張國平發表於2018-06-12


最近一致在用BollChannel軌道策略,也是VNPY原包提供的模版策略,修改了也不少,這裡面就隨便分析。BollChannel策略是很精巧的邏輯。基於15分鐘K線輪詢,利用阻止單跟隨15分鐘間的市場變動。

class BollChannelStrategy(CtaTemplate):

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

VNPY中,每個策略都是一個類,繼承CtaTemplate,這樣也就繼承了被實盤engine和回測engine呼叫啟用的這樣一套使用介面。

    className = 'BollChannelStrategy'

    author = u'用Python的交易員'

這兩個引數是作為資訊,體現在實盤執行介面中,可以看到和白色框中,是策略引數;下面黃色框中,是系統按市場盤面資訊

和策略引數計算出的策略變數。
vnpy,BollChannel布林線軌道策略分析

    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更新,

vnpy,BollChannel布林線軌道策略分析

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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章