vnpy源碼學習記錄(3) ----------CTP網關


介紹CTP網關之前先看看網關類的抽象類:BaseGateway
BaseGateway用於創建與不同交易系統的網關連接的抽象網關類。該類必須是線程安全的(所有方法必須線程安全,對象之間沒有可變的共享屬性);所有方法都需要是非阻塞的;每個方法和回調方法都需滿足在docstring中描述的需求;如果連接斷開會自動重新連接。
所有的方法必須要實現所有的@abstractmethod
回調函數必須手動響應
on_tick on_trade on_order on_position on_account on_contract
所有傳給回調函數的XxxData類必須是常量,也就是說傳給on_xxx函數的對象就不該被修改了。如果使用緩存來保存數據的引用,在傳遞數據到on_xx方法前使用copy.copy來創建一個新對象。
default_setting和exchanges屬性保存連接網關的信息和網關支持的交易所
__init__()中初始化事件引擎和網關名

self.event_engine = event_engine
self.gateway_name = gateway_name

vnpy覆蓋了國內外所有交易品種的交易接口(vnpy.gateway目錄下)。這裏暫時只介紹CTP和RPC兩種網關

CTP網關

CtpGateway vnpy/gateway/ctp/ctp_gateway.py

1. 實例化CTP網關

main_engine.add_gateway(CtpGateway)  # 將ctp添加到主引擎中
   def add_gateway(self, gateway_class: BaseGateway):
        gateway = gateway_class(self.event_engine)  # 實例化  
        self.gateways[gateway.gateway_name] = gateway 添加進網關字典

        #將網關支持的交易所添加到引擎          
        for exchange in gateway.exchanges:
            if exchange not in self.exchanges:
                self.exchanges.append(exchange)
        return gateway

CtpGateway繼承BaseGateway,super().__init__(event_engine, "CTP") ,設置網關名爲”CTP”。首先加載default_setting和exchanges信息,default_setting初始化CTP連接信息,CTP接口支持"CFFEX" “SHFE” “CZCE” “DCE” "INE"這5種交易所,加載到exchanges屬性。類裏面初始化了兩個對象,分別對交易api和行情api:

self.td_api = CtpTdApi(self)
self.md_api = CtpMdApi(self)

CtpTdApi和CtpMdApi分別繼承MdApi和TdApi。這兩個類裏包含了vnpy封裝的ctp接口。
main_engine.connect(setting, "CTP") 連接CTP setting屬性爲連接的信息 格式如下:
在這裏插入圖片描述

1.2 連接CTP

在主引擎中調用connect方法,先找出當前的網關接口,然後通過網關接口調用網關內的connect方法:

def connect(self, setting: dict, gateway_name: str): 
    gateway = self.get_gateway(gateway_name)
    if gateway:
        gateway.connect(setting, self)

此處在CtpGateway中調用connect()方法,先解析出setting屬性,即CTP連接信息,然後處理連接地址,再分別連接交易服務器和行情服務器,並啓動輪詢:

def connect(self, setting: dict):
    user_id = setting["用戶名"]
    password = setting["密碼"]
    broker_id = setting["經紀商代碼"]
    td_address = setting["交易服務器"]
    md_address = setting["行情服務器"]
    app_id = setting["產品名稱"]
    auth_code = setting["授權編碼"]
    product_info = setting["產品信息"]
    if not td_address.startswith("tcp://"):
            td_address = "tcp://" + td_address
    if not md_address.startswith("tcp://"):
            md_address = "tcp://" + md_address

    self.td_api.connect(td_address, user_id, password, broker_id, auth_code, app_id)
    self.md_api.connect(md_address, user_id, password, broker_id)
	self.init_query()

連接交易服務器

首先將參數設置爲實例對象屬性,然後對connect_status(服務器連接狀態,默認爲False)進行判斷

if not self.connect_status:
path = get_folder_path(self.gateway_name.lower())
# 創建TdApi  存貯訂閱信息文件的目錄,默認爲當前目錄.返回創建出的用戶Api
    self.createFtdcTraderApi(str(path) + "\\Td")  

    self.subscribePrivateTopic(0)  # 訂閱私有流
    self.subscribePublicTopic(0)  # 訂閱公有流

    self.registerFront(address)  # 註冊前置機
    self.init()  # 初始化交易服務器
    self.connect_status = True
else:
	self.authenticate()

方法self.init()初始化服務器,在CTP後臺調用processTask方法,初始化時方法執行的操作有:交易服務器連接、交易服務器授權驗證、交易服務器登錄、結算信息、合約信息查詢
然後將self.connect_status設置爲True
上面初始化時執行的操作在vnpy中都有回調函數,分別爲:onFrontConnectedonRspAuthenticateonRspUserLoginonRspSettlementInfoConfirmonRspQryInstrument
如果self.connect_status判斷爲True(服務器中途斷開後進行重新連接時會出現該情況),則手動執行操作。先進行交易服務器授權驗證self.authenticate()

self.reqAuthenticate(req, self.reqid)

然後驗證方法回調之後進行登錄操作。再一步步往下執行。
如中途服務器斷開回調函數onFrontDisconnected將被調用,在方法裏將login_status設爲False
CTP中所有的請求都是按照reqXxx的格式,所有的回調都是按照onRspXxx的格式

連接行情服務器

行情服務器和交易服務器類似,不同的是交易服務器只需要連接和登錄

輪詢

輪詢方法init_query是用於定時查詢賬戶信息和持倉信息的。

def init_query(self):
    self.count = 0
    # 將查詢賬戶信息和持倉信息的方法放入字典中,然後註冊計時器,每秒鐘調用process_timer_event方法
    self.query_functions = [self.query_account, self.query_position]
    self.event_engine.register(EVENT_TIMER, self.process_timer_event)

process_timer_event方法中,對count的操作表示每兩秒執行一次process_timer_event方法,然後彈出query_functions的首項並執行,再將該方法放入query_functions的尾部:

def process_timer_event(self, event):
    self.count += 1
    if self.count < 2:
            return
    self.count = 0
    func = self.query_functions.pop(0)
    func()
	self.query_functions.append(func)

CTP中所有的交易服務器的函數可以在vnpy/api/ctp/vnctp/vnctptd/vnctptd.cpp中找到
行情服務器的函數可以在vnpy/api/ctp/vnctp/vnctpmd/vnctpmd.cpp中找到

對數據的獲取及處理

通過CTP接口查詢到信息以後,可以對數據進行自定義處理。下面以回報的合約信息爲例。
onRspQryInstrument回調函數返回了通過CTP接口查詢到的合約數據,對數據做處理之後執行self.gateway.on_contract(contract)語句,調用了CtpGateway的父類BaseGateway中的on_contract()方法。
方法中對合約事件進行推送:

self.on_event(EVENT_CONTRACT, contract)

約信息就通過on_event在事件引擎中被推送(放入隊列),前面在事件引擎中介紹過的_run()方法中,只要引擎啓動了,引擎就會一直從隊列中取出事件,並處理它。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章