基於CTP的程序化交易系統開發

http://blog.sina.com.cn/s/blog_56e7157f01016ri2.html

    自從綜合交易平臺(CTP)的API開放以來,很多人開始編寫自己的程序化交易系統,今天我想說說自己的一些看法。
   
 首先解讀一下CTP的接口說明,CTPAPI使用建立在TCP協議之上FTD協議(《期貨交易數據交換協議》)與交易託管系統進行通訊,而交易託管系統負責投資者的交易業務處理。FTD 協議中規定了所有的通訊都基於某一種通訊模式。

交易涉及的通訊模式共有三種:

1.對話通訊模式,是指由會員端主動發起的通訊請求。該請求被交易所端接收和處理,並給予響應。例如報單、查詢等。這種通訊模式與普通的客戶/服務器模式相同。

2.私有通訊模式,是指交易所端主動,向某個特定的會員發出的信息。例如成交

回報等。

3.廣播通訊模式,是指交易所端主動,向市場中的所有會員都發出相同的信息。

例如公告、市場公共信息等。

CTP交易API提供了兩個接口,分別爲CThostFtdcTraderApi 和CThostFtdcTraderSpi

我們自己開發的交易系統通過CThostFtdcTraderApiCTP發送操作請求,通過CThostFtdcTraderSpi接收CTP的任何響應。

現在把主要的業務舉例在下表中

業務舉例

通訊模式

CThostFtdcTraderApi

CThostFtdcTraderSpi

登錄

對話模式

ReqUserLogin

OnRspUserLogin

報單錄入

ReqOrderInsert

OnRspOrderInsert

報單查詢

ReqQryOrder

OnRspQryOrder

成交查詢

ReqQryTrade

OnRspQryTrade

報單回報

私有模式

 

OnRtnOrder

成交回報

 

OnRtnTrade

行情涉及的通訊模式共有兩種:

1.對話通訊模式,同交易一樣,是指由會員端主動發起的通訊請求。該請求被交易所端接收和處理,並給予響應。例如登錄,退訂等。

2.廣播通訊模式,主要是行情訂閱,當訂閱行情後交易所端主動向會員連續主動發出行情信息。

業務舉例

通訊模式

CThostFtdcMdApi

CThostFtdcMdSpi

  登錄

對話
模式

ReqUserLogin

OnRspUserLogin

行情訂閱

廣播

模式

SubscribeMarketData

OnRspQryDepthMarketData

行情退訂

對話模式

UnSubMarketData

 

OnRspUnSubMarketData

 

可見,通過CTP提供的接口,我們可以向CTP發送業務申請,也不斷的按照三種通訊模式中的其中一種接收CTP的響應。因此我們寫的交易系統中至少就應該有兩個線程,一個稱其爲主業務線程,負責對CTP發出業務申請;另一個線程爲API工作線程,負責接收CTP通過廣播通訊模式,對話通訊模式,私有通訊模式其中一種模式對交易系統的響應。

    綜上所述,我們的程序化交易系統需要完成的業務可以劃分爲:

1.基本操作,比如登錄,訂閱等;

2.行情操作,比如對行情數據的接收,存儲等

3.訂單操作,比如報單;對報單,成交狀況的查詢;報單,成交狀況的私有回報等。

4.數據監聽和處理操作,比如接收到新數據之後的統計處理,滿足統計條件後的報單處理(其實這裏就是我們的策略所在)

    那麼,我建議將我們的程序化交易系統分爲四個線程,分別處理上述業務。程序的主線程就可以完成基本操作,完成登入,訂閱等初始化工作。

    其它三個線程工作關係如下圖所示:

基於CTP的程序化交易系統開發(一)

程序化交易系統是一個複雜的多線程網絡程序,在開發過程中要特別注意處理很多的線程互斥、數據處理造成的網絡丟包等一系列棘手問題。另外,對於CTP開發的資料,大家可以留言給我,我儘量提供,也歡迎大家多多討論。



    本文開始先說說CTP給開發者提供了什麼。CTP提供給開發者的文件一共有4個頭文件 ThostFtdcTraderApi.h,ThostFtdcMdApi.h,ThostFtdcUserApiStruct.h,ThostFtdcUserApiDataType.h 和2個dll:thosttraderapi.dll,thostmduserapi.dll(動態鏈接庫,如果是靜態庫則是thosttraderapi.lib,thostmduserapi.lib)。
    其中
ThostFtdcTraderApi.h定義了交易請求接口CThostFtdcUserApi和交易事件處理接口CThostFtdcUserSpi;
    ThostFtdcMdApi.h
定義了行情請求接口CThostFtdcMdApi,行情事件處理接口CThostFtdcMdSpi;
    ThostFtdcUserApiStruct.h定義了接口方法中用到的數據結構。
    ThostFtdcUserApiDataType.h定義了數據結構中用到數據類型,枚舉描述。
    開發者通過
CThostFtdcUserApi就可以完成交易接口的初始化,登入,確認結算結果,查詢合約,查詢資金,查詢持倉,報單,撤單等業務操作;通過CThostFtdcUserSpi獲取相應回報
    開發者也可以通過
CThostFtdcMdApi完成行情接口的初始化,登入,訂閱,收行情等業務;通過CThostFtdcMdSpi獲取相應的行情業務操作的回報
   上文提到了基於CTP的程序化交易系統開發最好要有四個線程:
1.完成初始化及退出操作的主線程;
2.行情接受和處理線程;
3.新行情數據監聽和處理線程;
4.訂單管理線程
現在先討論一下主線程的初始化工作。初始化工作包括交易接口和行情接口兩部分,對於交易接口的初始化,程序必須完成如下步驟:
1, 產生一個CThostFtdcTraderApi實例
2, 產生一個事件處理的實例
3, 註冊一個事件處理的實例
4, 訂閱私有流
5, 訂閱公共流
6, 設置交易託管服務的地址。
初始化過程的時序圖如下:
基於CTP的程序化交易系統開發(二)

對於行情接口的初始化工作要簡單一些,因爲接口默認就訂閱了公有流和私有流,初始化過程的時序圖如下:
基於CTP的程序化交易系統開發(二)

    接下來就是行情接收和處理線程,行情的接收是通過CThostFtdcMdApi::SubscribeMarketData()完成對行情的訂閱,通過CThostFtdcMdSpi::OnRtnDepthMarketData()完成對於行情數據的接收。此線程的工作主要要完成如下三個方面:
1.行情數據的存儲:由於SubscribeMarketData()可以對多個合約行情進行訂閱,所以在接收到數據後的處理首先要考慮對不同合約的數據分別以合適的方式(這裏合適的方式是指存取,遍歷,查詢,增刪等操作最爲穩定快速的算法)存儲。
2.行情數據的補齊:這是一個相當重要的問題。當tick數據爲空的時候,必須以合適的方式補齊(因爲缺失的數據對後來的統計指標計算有較大的影響,所以數據補齊是相當考究的)。
3.最新行情數據到來時向數據監聽線程發出信號。
   在下一文中我將討論一下剩餘的數據監聽和處理線程和訂單管理線程。


   最近比較忙,好容易今天事情少點,趕緊繼續寫博客基於CTP的程序化交易系統開發(三),謝謝大家的關注。
   接到上篇說哈,本文討論一下數據監聽線程和訂單管理線程做些什麼。
   一,數據監聽線程
   數據監聽線程,當行情處理線程接收到新的行情數據時,也就是每當一個tick到來時,就向數據監聽線程發出信號,觸發此線程啓動,然後依次進行:
1.各種指標計算,
2.然後進行策略計算,
3.最後在滿足策略時進行交易。
   指標計算,就是指根據新到來的數據以及歷史數據進行某些統計值的計算,比如常見的MA,MACD,RSI等,當然也可以自己構造出某個統計值。這裏需要提到的是數據週期的問題(我在之前的博文中曾解釋過)。如果指標計算是基於數據週期,那麼對於行情數據就要進行數據的拼裝,也就是說將每一tick數據(500毫秒)拼裝成你所需要的數據週期(也就是拼裝成K線),然後將每個週期(每根k線)中的open,high,low,close計算出來,以便進行統計值的計算。
   策略計算就是將你的計算出來的指標,按照你自己的交易思想,交易策略進行邏輯的組合,然後在滿足策略邏輯的時候進行交易。
   這裏我建議一下架構,就是不要將指標計算和策略計算以及交易寫到一個函數裏面,而是將每一個指標計算寫成一個函數,然後分別用函數指針指向它;然後策略計算以及交易寫成一個函數,然後用函數指針指向它,並將其壓入一個堆棧,此後每添加一個指標,就將指標對應的函數指針壓入堆棧;
基於CTP的程序化交易系統開發(三)

當每次數據監聽線程啓動時就依次彈出每個指標並計算,最後完成策略函數。
  二,訂單管理線程
    訂單管理線程,主要是用於處理訂單管理中的兩個問題:
    1.訂單隊列的管理,一般按照報單的時間先後順序用數組等數據結構進行管理,原則是每一個業務請求要準確對應其回報,每一組請求和回報要準確的對應其歸屬的訂單。其關鍵就在於業務請求編號交易序列號。
    業務請求號是指發送請求時設定的RequestID,TraderApi返回響應時返回相關請求的RequestID。因爲TraderApi是異步實現的,終端程序可能連續發出多個請求和查詢指令。RequestID可以把請求/查詢指令和相關的回報關聯起來。
    而交易序列號是組合而成的。從報單到成交的交易過程中,會產生如下幾組交易序列號:
FrontID + SessionID + OrderRef
    用戶使用這組交易序列號可以按照自己的方式來唯一標示發出的任何一筆委託。用戶登入成功後,會收到前置機編號FrontID, 會話編號SessionID 和最大報單引用MaxOrderRef。用戶在報單時設定報單引用OrderRef。 OrderRef可以從MaxOrderRef開始遞增。如果用戶沒有設定OrderRef,在報單響應中,Thost會爲用戶設置一個的OrderRef。使得每個報單的這組序列號保持唯一。
    通過這個交易序列號,就可以確定委託回報和成交回報的歸屬,也可以使用這組交易序列號進行撤單操作。
2.訂單的各種狀態的管理:在回報中,訂單的狀態有很多種,請參考ThostFtdcUserApiDataType.h,我建議根據其含義歸納爲這五種狀態:報單中,已成交,撤單中,已撤單,出錯,因爲這五種狀態對於策略邏輯的完成是至關重要的。
    下面說一下訂單交易的機制與時序。先給出一個時序圖:
基於CTP的程序化交易系統開發(三)

    其中,報單響應和回報的機制是當Thost收到報單指令,如果沒有通過參數校驗,拒絕接受報單指令。用戶就會收到OnRspOrderInsert消息,其中包含了錯誤編碼和錯誤消息。如果Thost接受了報單指令,用戶不會收到OnRspOrderInser,而會收到OnRtnOrder,用來更新委託狀態。交易所收到報單後,通過校驗。用戶會收到OnRtnOrder、OnRtnTrade。如果交易所認爲報單錯誤,用戶就會收到OnErrRtnOrder。
    撤單響應和回報和報單響應和回報相似。當Thost收到撤單指令,如果沒有通過參數校驗,拒絕接受撤單指令。用戶就會收到OnRspOrderAction消息,其中包含了錯誤編碼和錯誤消息。如果Thost接受了撤單指令,用戶不會收到OnRspOrderAction,而會收到OnRtnOrder,用來更新委託狀態。交易所收到撤單後,通過校驗,執行了撤單操作。用戶會收到OnRtnOrder。如果交易所認爲報單錯誤,用戶就會收到OnErrRtnOrderAction。


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