❶ Python API面紗下的函數——基於CTP的國內期貨程序化交易之報單流程講解
用戶們已經閱讀了真格量化的Python API文檔,了解到它是一些交易櫃台,如CTP C++ API的封裝。接下來,我們可以看看這些API在C++中的原始面貌。
以CTP櫃台為例,與海外市場許多連續交易的品種相比,國內期貨市場的品種需要考慮更多的規則。
首先就是交易時間段。許多外盤品種能全天23小時連續交易,而國內許多期貨品種,全天分四個時間段交易,分別為9:00至10:15、10:30至11:30、13:30至15:00及21:00至次日02:30。交易時間段多,平倉時間段也多,這樣無形中就增加了很多業務邏輯。
例如在真格量化中,「收盤事件」包含了小節交易的暫停事件:
其次,今昨倉的區分。例如上期所的期貨品種平倉時分平今和平倉,這樣平倉報單時就要根據成交時間分別判斷,是前一個交易日的單子還是當前交易日的單子,否則報單參數不正確,單子將直接被交易系統拒絕。
在CTP開發過程中主要用到的頭文件為:ThostFtdcTraderApi.h、ThostFtdcUserApiDataType.h及ThostFtdcUserApiStruct.h,動態庫為:libthosttraderapi.so。下面是一些代碼示例:
CThostFtdcTraderApi *pTradeApi = CThostFtdcTraderApi::CreateFtdcTraderApi(dirName);
通過調用CreateFtdcTraderApi()創建API實例——pTradeApi,隨後調用該實例發起各種請求,比如連接伺服器、用戶登錄、報單、撤單、查詢持倉、查詢資金等等。
2. 創建CTP API回調實例:
CFtdcTradeSpi *pTradeSpi = new CFtdcTradeSpi(pTradeApi, this);
這個需要自己編寫相應實現類,需要繼承上期技術提供的CThostFtdcTraderSpi類。重寫該類裡面的方法,以處理伺服器發過來的各類數據。
3. 將上述兩個實例關聯起來,並發起連接伺服器請求:
pTradeApi->RegisterSpi(pTradeSpi);
pTradeSpi->connect(serverAddr, brokerId, username, password);
連接伺服器以及實例初始化相關代碼:
這可以對應真格量化的賬戶登錄Python代碼:
在C++中連接請求發出後,OnFrontConnected()會響應請求,然後在該函數內可以調用登錄函數pTradeApi_->ReqUserLogin()完成用戶登錄操作,相應的OnRspUserLogin()會響應請求。由於國內期貨在交易日內首次登錄時需要做投資者結算結果確認操作,所以在OnRspUserLogin()函數內,可以進一步調用pTradeApi_->ReqSettlementInfoConfirm()做投資者結算結果確認,確認結果將在OnRspSettlementInfoConfirm()內返回。做完投資者結算結果確認操作,整個伺服器連接與用戶登錄過程就完成了,可以正常下單交易了。
C++登錄賬戶部分:
C++確認結算單部分:
4. 期貨報單:
(1)ReqOrderInsert():報單請求
開發者需要正確填寫買賣/方向、開倉/平倉、市價/限價、委託數量、委託價格等等,填寫完畢就可以調用ReqOrderInsert()報單了。
(2)OnRspOrderInsert():報單請求應答
報單成功後,該函數就會被回調。當然我們也可以用OnRtnOrder()來監控報單的狀態變化。
(3)OnRtnOrder():委託變化通知
當委託狀態發生變化時,該函數會被回調。一般常見的委託狀態主要有:未知、未成交還在隊列中、部分成交還在隊列中、完全成交等。
對應真格量化中查委託的狀態:
一次報單,如果數量比較多,一般不會一次全部成交,而是會分多批次成交,所以該函數會不斷被回調。隨著不斷回調,每次返回的委託量、成交量、剩餘量等數據會不斷變更。這也是我們在真格量化中委託發出後,一般會受到多條委託狀態變化回報的原因。
(4)OnRtnTrade():成交信息變化推送通知
該函數比較重要,返回的每一條信息都是成交信息,裡麵包含成交量、成交價、成交費用等等,這些都是投資者關心的數據,對應真格量化的OnTradeDeal函數。
5. 查詢期貨賬號持倉:
查詢持倉主要調用pTradeApi_->ReqQryInvestorPosition(),按照文檔說明填寫合適的參數即可。查詢持倉響應函數為:
該函數一般需要由開發者自己重寫,應注意有時持倉數據不會一次全部返回,而是隨著成交的進行而一批一批返回,需要開發者監聽成交狀況的變化而進行更新,相當於在真格量化中在OnTradeDeal函數中利用GetPositions函數刷新持倉數據。