Python做量化|使用AlgoPlus接收期貨實時行情

  • 2019 年 11 月 14 日
  • 筆記

金融領域也是 Python 的重要方向之一,我知道有一些讀者就是沖著做量化交易才接觸 Python 的。今天給大家分享一個使用 Python 的期貨交易API。


量化交易在中國發展方興未艾。因為T+0且允許做空的交易制度、交易所的大力推動、資訊技術紅利帶來的賺錢效應培養了一大批擁躉等原因,量化交易在期貨行業起步比較早,而且發展比較成熟。

雖然各期貨交易所都開發了自己的交易後台,但是上期所的CTP仍是目前使用最廣泛的。所以,對於想從事量化研究、交易的同學們而言,學習CTP開發是一門必修課。本文就帶大家了解一下CTP,並給大家介紹一個python版CTP交易介面——AlgoPlus

關於CTP

CTP是Comprehensive Transaction Platform的簡稱。CTP有MdApi和TraderApi兩個獨立的開放介面。

MdApi負責行情相關操作(訂閱、接收)。

TraderApi負責交易相關的操作(買、賣、撤、查)。

MdApi與TraderApi方法的執行過程都是非同步的,每一個請求都對應一個或多個負責接收執行結果的回調函數。例如,通過ReqOrderInsert方法向交易所發出買開倉指令,對應的回調方法OnRtnOrder可以實時接收交易所伺服器發回來的執行通知。

關於AlgoPlus

上期所CTP的官方API只支援C++語言,除非有開發經驗,否則不推薦直接使用C++語言開發。

python語言在許多領域被非常廣泛的應用,量化交易也不例外。本文給大家介紹的AlgoPlus就是對官方CTP封裝的python版量化投資介面。相比較其他Python版CTP,AlgoPlus具有以下特點:

  1. 忠實於CTP官方特性。簡單的說,AlgoPlus就是官方CTP的python翻譯版,沒有過度的封裝,讓交易者根據自己的實際情況選擇官方設計的功能。
  2. 使用Cython、ctypes技術封裝,即能實現了低延時的要求,又能兼容python語言的易用性。經過嚴格測試,AlgoPlus從策略觸發交易訊號到調用C++方法,延時只有40微秒左右。
  3. 從實戰的角度為同學們展示量化策略的開發過程,例如趨勢策略、套利策略、風控策略、執行演算法等教程。

安裝AlgoPlus

第一步:安裝Anaconda。

第二步:使用pip install algoplus命令安裝。

當你看到以下內容時:

Processing dependencies for AlgoPlus==1.5  Finished processing dependencies for AlgoPlus==1.5  請按任意鍵繼續. . .

安裝成功!

註冊模擬帳號

1、Simnow是上海期貨交易所旗下技術公司維護的一套模擬交易系統,只需註冊帳號即可免費使用:http://www.simnow.com.cn/

2、在常用下載頁面下載一個客戶端,方便實時查看模擬交易情況:http://www.simnow.com.cn/static/softwareDownload.action

3、記錄個人主頁中的InvestrorID,以及產品與服務頁面中的伺服器地址。配置賬戶參數時需要使用這些資訊。

配置賬戶資訊

FutureAccountInfo是一個期貨賬戶類,包括broker_id(所屬期貨公司的標識),server_dict(行情與交易伺服器地址),reserve_server_dict(備用伺服器地址)、investor_id(賬戶)、password(密碼)、app_id(客戶端ID,與auth_code對應,監管要求)、auth_code(客戶端ID對應的授權碼,監管要求)、instrument_id_list(訂閱合約列表)、md_page_dir(行情相關文件存放地址)、td_page_dir(交易相關文件存放地址)。

將所有的賬戶資訊存放入my_future_account_info_dict字典中。創建交易介面實例時找到相應的賬戶資訊作為參數。

# -*- coding: utf-8 -*-    BASE_LOCATION = "."  # 根目錄地址  MD_LOCATION = BASE_LOCATION + "\MarketData"  # 行情數據地址  TD_LOCATION = BASE_LOCATION + "\TradingData"  # 交易數據地址  SD_LOCATION = BASE_LOCATION + "\StrategyData"  # 策略數據地址    class FutureAccountInfo:      def __init__(self, broker_id, server_dict, reserve_server_dict, investor_id, password, app_id, auth_code, instrument_id_list, md_page_dir=MD_LOCATION, td_page_dir=TD_LOCATION):          self.broker_id = broker_id  # 期貨公司BrokerID          self.server_dict = server_dict  # 伺服器地址。TDServer為交易伺服器,MDServer為行情伺服器。伺服器地址格式為"ip:port"          self.reserve_server_dict = reserve_server_dict  # 備用伺服器地址          self.investor_id = investor_id  # 賬戶          self.password = password  # 密碼          self.app_id = app_id  # 認證使用AppID          self.auth_code = auth_code  # 認證使用授權碼          self.instrument_id_list = instrument_id_list  # 訂閱合約列表[]          self.md_page_dir = md_page_dir  # MdApi流文件存儲地址,默認MD_LOCATION          self.td_page_dir = td_page_dir  # TraderApi流文件存儲地址,默認TD_LOCATION    my_future_account_info_dict = {      # 交易時間測試      'SimNow': FutureAccountInfo(          broker_id='9999'  # 期貨公司BrokerID          # TDServer為交易伺服器,MDServer為行情伺服器。伺服器地址格式為"ip:port"          , server_dict={'TDServer': "180.168.146.187:10100", 'MDServer': '180.168.146.187:10110'}          # 備用伺服器地址          , reserve_server_dict={'電信1': {'TDServer': "180.168.146.187:10100", 'MDServer': '180.168.146.187:10110'},                                 '電信2': {'TDServer': "180.168.146.187:10101", 'MDServer': '180.168.146.187:10111'},                                   '其他1': {'TDServer': "180.168.146.187:10130", 'MDServer': '180.168.146.187:10131'},  # 7*24                                 '其他2': {'TDServer': "218.202.237.33:10102", 'MDServer': '218.202.237.33:10112'},  # 移動                                 }          , investor_id=''  # 賬戶          , password=''  # 密碼          , app_id='simnow_client_test'  # 認證使用AppID          , auth_code='0000000000000000'  # 認證使用授權碼          # 訂閱合約列表          , instrument_id_list=[b'rb2001', b'fu2001'] # 訂閱螺紋2001合約和燃料油2001合約      ),  }

AlgoPlus創建行情介面

MdApi是行情介面,使用時只需要傳遞賬戶參數創建一個實例就可以了。下面是一個完整的例子:

from AlgoPlus.CTP.MdApi import MdApi    class TickEngine(MdApi):      # ///深度行情通知      def OnRtnDepthMarketData(self, pDepthMarketData):          print(pDepthMarketData)          # print(f"{pDepthMarketData.InstrumentID}當前最新價:{pDepthMarketData.LastPrice}")    if __name__ == '__main__':      from account_info import my_future_account_info_dict      future_account = my_future_account_info_dict['SimNow']      tick_engine = TickEngine(future_account.server_dict['MDServer']                               , future_account.broker_id                               , future_account.investor_id                               , future_account.password                               , future_account.app_id                               , future_account.auth_code                               , future_account.instrument_id_list                               , None                               , future_account.md_page_dir)      tick_engine.Join()

1、從AlgoPlus.CTP.MdApi文件中導入MdApi類。MdApi已對工作流程的前六步進行了封裝。

2、TickEngine是MdApi的子類。TickEngine類主要實現收到行情的數據處理演算法,示例只將收到的行情列印出來。

3、創建行情介面實例前,需要導入賬戶資訊。示例的賬戶資訊存放在同一個目錄下的account_info.py文件中。

4、交易時間運行以上程式碼就可以將接收到的實時期貨行情列印出來。

5、回調函數OnRtnDepthMarketData接收到的pDepthMarketData行情是DepthMarketDataField結構體的實例,在AlgoPlus.CTP.ApiStruct中被定義。以調用屬性的方式可以獲取行情任意欄位的數值,例如pDepthMarketData.LastPrice表示最新價。DepthMarketDataField包括以下欄位:

class DepthMarketDataField(BaseField):      """深度行情"""      _fields_ = [          ('TradingDay', c_char * 9)  # ///交易日          , ('InstrumentID', c_char * 31)  # 合約程式碼          , ('ExchangeID', c_char * 9)  # 交易所程式碼          , ('ExchangeInstID', c_char * 31)  # 合約在交易所的程式碼          , ('LastPrice', c_double)  # 最新價          , ('PreSettlementPrice', c_double)  # 上次結算價          , ('PreClosePrice', c_double)  # 昨收盤          , ('PreOpenInterest', c_double)  # 昨持倉量          , ('OpenPrice', c_double)  # 今開盤          , ('HighestPrice', c_double)  # 最高價          , ('LowestPrice', c_double)  # 最低價          , ('Volume', c_int)  # 數量          , ('Turnover', c_double)  # 成交金額          , ('OpenInterest', c_double)  # 持倉量          , ('ClosePrice', c_double)  # 今收盤          , ('SettlementPrice', c_double)  # 本次結算價          , ('UpperLimitPrice', c_double)  # 漲停板價          , ('LowerLimitPrice', c_double)  # 跌停板價          , ('PreDelta', c_double)  # 昨虛實度          , ('CurrDelta', c_double)  # 今虛實度          , ('UpdateTime', c_char * 9)  # 最後修改時間          , ('UpdateMillisec', c_int)  # 最後修改毫秒          , ('BidPrice1', c_double)  # 申買價一          , ('BidVolume1', c_int)  # 申買量一          , ('AskPrice1', c_double)  # 申賣價一          , ('AskVolume1', c_int)  # 申賣量一          , ('BidPrice2', c_double)  # 申買價二          , ('BidVolume2', c_int)  # 申買量二          , ('AskPrice2', c_double)  # 申賣價二          , ('AskVolume2', c_int)  # 申賣量二          , ('BidPrice3', c_double)  # 申買價三          , ('BidVolume3', c_int)  # 申買量三          , ('AskPrice3', c_double)  # 申賣價三          , ('AskVolume3', c_int)  # 申賣量三          , ('BidPrice4', c_double)  # 申買價四          , ('BidVolume4', c_int)  # 申買量四          , ('AskPrice4', c_double)  # 申賣價四          , ('AskVolume4', c_int)  # 申賣量四          , ('BidPrice5', c_double)  # 申買價五          , ('BidVolume5', c_int)  # 申買量五          , ('AskPrice5', c_double)  # 申賣價五          , ('AskVolume5', c_int)  # 申賣量五          , ('AveragePrice', c_double)  # 當日均價          , ('ActionDay', c_char * 9)  # 業務日期      ]

其他

項目已在 Github 和碼雲上開源。