Pythonノート11-VNに基づく.pyのリアルタイムKラインジェネレータ

47703 ワード

from vnpy.trader.vtObject import VtBarData
from datetime import timedelta
import pymongo
from queue import Queue, Empty
from threading import Thread

class Bargenerate02:
    '''       K   '''
    def __init__(self, x=5):
        #   K       
        self.bar = None
        self.lastTick = None
        #   XminK 
        self.minxBar = None
        self.minX = x
        #        collection
        self.collections = {}
        #       
        self.active = False  #   
        self.queue = Queue()  #   
        self.thread = Thread(target=self.run)  #       
        #       
        self.callOpen = 0
        self.callAction = 0
        #          
        self.initVolume = 0

    def setDBname(self, dbname):
        '''        '''
        self.dbname = dbname

    def connetDB(self):
        '''     '''
        self.client = pymongo.MongoClient('localhost', 27017)

    def createCollection(self, symbols):
        '''
                    collection
          :  K :rb1905 X  K :rb1905.Xmin
        :param symbols: list       
        :return:
        '''
        for symbol in symbols:
            self.collections[symbol] = []
            self.symbol = symbol
            self.symbolXmin = symbol + '.' + str(self.minX) + 'min'
            collection = self.client[self.dbname][self.symbol]
            collection.ensure_index([('datetime', pymongo.DESCENDING)])
            collectionXmin = self.client[self.dbname][self.symbolXmin]
            collectionXmin.ensure_index([('datetime', pymongo.DESCENDING)])
            self.collections[symbol].append(collection)
            self.collections[symbol].append(collectionXmin)

    def formatMin(self, dateTime):
        '''     '''
        #      ,10:55:50     10:56:00
        dateTime += timedelta(minutes=1)
        dateTime = dateTime.replace(second=0, microsecond=0)
        return dateTime

    def updateTick(self, tick):
        '''       tick   '''
        #   tick    
        self.barTime = tick.datetime
        if self.bar:
            if self.barTime.day != self.lastTick.datetime.day:
                #   ,     bar
                self.createNewBar(tick, first=1)

            elif self.barTime >= self.formatMin(self.lastTick.datetime):

                #                ,    tick     bar
                #        bar time,      bar
                self.updateBar(self.lastTick, timeFormat=1)
                if self.checkClose(self.barTime):
                    #         ,    tick,       
                    #       bar
                    self.updateBar(tick)
                else:
                    self.createNewBar(tick)

            else:
                #      ,  
                self.updateBar(tick)
        else:
            #   bar     
            #      bar
            self.createNewBar(tick, first=1)

    def checkCallAction(self, t):
        '''      '''
        if (t.hour == 12 and t.minute == 59) or (
                t.hour == 0 and t.minute == 59):
            return True

    def checkOpenLose(self, now, tick):
        '''            K '''
        hour = now.hour
        #      
        if 1 <= hour < 13:
            nightOpenTime = now.replace(hour=1, minute=0, second=0, microsecond=0)
            self.addBlankBar(now, nightOpenTime, tick, first=1)
        elif 13 <= hour < 19:
            dayOpenTime = now.replace(hour=13, minute=0, second=0, microsecond=0)
            self.addBlankBar(now, dayOpenTime, tick, first=1)

    def addBlankBar(self, now, last, tick, first=0):
        '''
            K 
                     ,     ,  K  OHLC        ,
                ,       。
                  ,  OHLC     tick      
        :param now:   tick  
        :param last:          
        :param tick:
        :param first:         
        :return:
        '''
        delta = (now - last).seconds // 60
        for i in range(1, delta + 1):
            bar_datetime = last + timedelta(minutes=i)
            if (bar_datetime.hour >= 3 and bar_datetime.hour < 13) \
                    or (bar_datetime.hour == 15 and bar_datetime.minute >= 30) \
                    or (bar_datetime.hour == 16) \
                    or (bar_datetime.hour == 17 and bar_datetime.minute <= 30) \
                    or (bar_datetime.hour >= 19) \
                    or (bar_datetime.hour == 14 and 15 <= bar_datetime.minute <= 30):
                continue
            bar = VtBarData()
            if self.callAction:
                #           ,       call_open
                bar.open = self.callOpen
                bar.high = self.callOpen
                bar.low = self.callOpen
                bar.close = self.callOpen
                #       
                #      ,       
                # self.callOpen = 0
                # self.callAction = 0
                #                 
                self.lastVolume = 0
            else:
                if first:
                    bar.open = tick.preClosePrice
                    bar.high = tick.preClosePrice
                    bar.low = tick.preClosePrice
                    bar.close = tick.preClosePrice
                else:
                    bar.open = tick.lastPrice
                    bar.high = tick.lastPrice
                    bar.low = tick.lastPrice
                    bar.close = tick.lastPrice
            bar.openInterest = tick.openInterest
            bar.volume = '0'
            bar.date = bar_datetime.strftime('%Y%m%d')
            bar.time = bar_datetime.strftime('%H:%M:%S')
            bar.datetime = bar_datetime
            bar.gatewayName = tick.gatewayName
            bar.symbol = tick.symbol
            bar.vtSymbol = tick.vtSymbol
            bar.exchange = tick.exchange
            self.insertData(bar, update=0)

    def checkClose(self, now):
        '''       '''
        huor = now.hour
        minute = now.minute
        second = now.second
        microsecond = now.microsecond
        if huor == 3 and minute == 0 and second == 0 and microsecond == 0:
            return True
        elif huor == 14 and minute == 15 and second == 0 and microsecond == 0:
            return True
        elif huor == 15 and minute == 30 and second == 0 and microsecond == 0:
            return True
        elif huor == 19 and minute == 0 and second == 0 and microsecond == 0:
            return True

    def insertData(self, data, index=0, update=1, timeFormat=0):
        '''
         tick  bar    
        :param data: tick,bar
        :param index: 0  1min 1   xmin
        :param update: 0  insert 1    update
        :return:
        '''
        dataPut = data
        self.queue.put((dataPut, index, update, timeFormat))

    def createNewBar(self, tick, first=0):
        '''    K '''
        #       ,        
        if self.checkCallAction(self.barTime):
            #     TICK  ,  lastPrice
            #     ,      TICK  ,     tick,        
            self.callOpen = tick.lastPrice
            self.callAction = 1
            self.lastTick = tick
        else:
            #        
            if first:
                #    ,      
                self.checkOpenLose(self.barTime, tick)
            else:
                self.addBlankBar(self.barTime, self.formatMin(self.lastTick.datetime), self.lastTick)
            #      bar
            self.bar = VtBarData()
            if self.callAction:
                #           ,       call_open
                self.bar.open = self.callOpen
                #       
                self.callOpen = 0
                self.callAction = 0
                #        ,        
                self.initVolume = 0
            else:
                self.bar.open = tick.lastPrice
                if self.lastTick:
                    if first:
                        #            
                        self.initVolume = 0
                    else:
                        #       tick,  volume     volume
                        self.initVolume = self.lastTick.volume
            self.bar.high = tick.lastPrice
            self.bar.low = tick.lastPrice
            self.bar.close = tick.lastPrice
            self.bar.openInterest = tick.openInterest
            self.bar.volume = int(tick.volume) - self.initVolume
            self.bar.date = tick.date
            self.bar.time = tick.time
            self.bar.datetime = tick.datetime
            self.bar.gatewayName = tick.gatewayName
            self.bar.symbol = tick.symbol
            self.bar.vtSymbol = tick.vtSymbol
            self.bar.exchange = tick.exchange

            self.insertData(self.bar, update=0)
            #      tick
            self.lastTick = tick

    def updateBar(self, tick, timeFormat=0):
        '''  K '''
        self.bar.high = max(self.bar.high, tick.lastPrice)
        self.bar.low = min(self.bar.low, tick.lastPrice)
        self.bar.close = tick.lastPrice
        self.bar.openInterest = tick.openInterest
        self.bar.volume = str(int(tick.volume) - self.initVolume)
        self.bar.time = tick.time
        self.bar.datetime = tick.datetime
        self.insertData(self.bar, timeFormat=timeFormat)
        self.lastTick = tick

    def run(self):
        '''       '''
        while self.active:
            try:
                data, index, update, timeFormat = self.queue.get(block=True, timeout=1)
                if update:
                    flt = {'_id': data._id}

                    if timeFormat:
                        data.datetime = self.formatMin(data.datetime)
                    self.collections[data.symbol][index].update(flt, {'$set': data.__dict__})
                else:
                    self.collections[data.symbol][index].insert(data.__dict__)
            except Empty:
                pass

    def start(self):
        '''  '''
        self.active = True
        self.thread.start()

    def stop(self):
        '''  '''
        if self.active:
            self.active = False
            self.thread.join()

最近の先物プロジェクトでは、送られてきたtickをリアルタイムで保存し、1分間のK線、5分間のK線をリアルタイムで生成する必要があります.