交易网关Gateway
Gateway封装思路
CTP,全称为中国期货市场监控中心交易系统(China Financial Futures Exchange Trading System),是由中国金融期货交易所开发的一套综合性交易系统。该系统不仅支持期货交易,还涵盖了期权、债券等多种金融产品的交易。通过期货公司提供的CTP接口,可实现期货交易。
中金所提供的CTP接口是用C++写成的,接下来看看VNPY是如何将C++接口转化为python接口,又进一步实现系统交互。这些内容封装在了vnpy_ctp
包里。
以下是vnpy_ctp
的文件目录
初始材料
初始材料为交易所提供的.dll动态链接库和.h头文件,最重要的如下两个:
ThostFtdcMdApi.h
:C++头文件,包含获取行情相关的指令ThostFtdcTraderApi.h
:C++头文件,包含交易相关指令,如报单、撤单
在头文件中,一般只声明函数,没有函数的具体实现,而这些函数的具体实现在动态和静态链接库中。
在ThostFtdcMdApi.h
中,定义了两个类:
CThostFtdcMdApi
:完成行情接口的初始化、登录、订阅、接收行情等业务CThostFtdcMdSpi
:获取相应业务操作的返回信息
class CThostFtdcMdSpi
{
public:
virtual void OnFrontConnected(){};
///@param nReason
/// 0x1001
/// 0x1002
/// 0x2001
/// 0x2002
/// 0x2003
virtual void OnFrontDisconnected(int nReason){};
@param nTimeLapse
virtual void OnHeartBeatWarning(int nTimeLapse){};
virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
virtual void OnRspUserLogout(CThostFtdcUserLogoutField *pUserLogout, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
virtual void OnRspQryMulticastInstrument(CThostFtdcMulticastInstrumentField *pMulticastInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
virtual void OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
virtual void OnRspSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
virtual void OnRspUnSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
virtual void OnRspSubForQuoteRsp(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
virtual void OnRspUnSubForQuoteRsp(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
virtual void OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData) {};
virtual void OnRtnForQuoteRsp(CThostFtdcForQuoteRspField *pForQuoteRsp) {};
};
在ThostFtdcTraderApi.h
中,同样定义了两个类:
CThostFtdcTraderApi
:完成交易接口的初始化、登录、确认计算结果,查询合约,查询资金,报单,撤单等业务操作CThostFtdcTraderSpi
:获取相应操作的返回信息
VNPY的Python封装
为了实现C++到python的接口转换,VNPY分行情接口和交易接口,重写了两个类:
MdApi
- 定义在
vnctpmd
里 - 继承自
CThostFtdcMdSpi
,但成员变量包含CThostFtdcMdApi
,以及一个负责处理回调数据的任务队列task_queue
- 定义在
TdApi
- 定义在
vnctptd
里 - 类似
MdApi
- 定义在
然后,上述C++对象通过pybind11模块编译为python的MdApi
类和TdApi
,见文件vnctpmd.cp310-win_amd64.pyd
和vnctptd.cp310-win_amd64.pyd
。到此,就完成了C++下CTP的python封装。
剩下还需要实现交易接口每次触发回调事件的时候,通知本地的事件引擎,与本地vntrader
实现交互。这是交易网关BaseGateway
的主要作用。
交易网关模板BaseGateway
BaseGateway
提供了一个交易网关交互的模板,有两块内容:
- 一是实现了与VNPY事件引擎交互的函数
- 二是声明了与网关交互的函数,具体的实现根据交易接口的不同,让用户自定义
所以,BaseGateway
是一个高度抽象、高度可定制的模板,几乎所有其他的交易网关使用都可以继承自它。
与事件引擎交互
class BaseGateway(ABC):
# Default name for the gateway.
default_name: str = ""
# Fields required in setting dict for connect function.
default_setting: Dict[str, Any] = {}
# Exchanges supported in the gateway.
exchanges: List[Exchange] = []
def __init__(self, event_engine: EventEngine, gateway_name: str) -> None:
""""""
self.event_engine: EventEngine = event_engine
self.gateway_name: str = gateway_name
首先是初始化部分,简单地传入事件引擎实例和交易网关。
def on_event(self, type: str, data: Any = None) -> None:
"""
General event push.
"""
event: Event = Event(type, data)
self.event_engine.put(event)
on_event
是回调函数的同一接口,它将回调事件封装为Event(type, data)
,再将事件推送到事件引擎中。在实盘时,需要作出反馈的事件如下:
- 实时Tick数据
- 每拿到一笔Tick数据,就将一个
EVENT_TICK
推送到事件引擎
def on_tick(self, tick: TickData) -> None: """ Tick event push. Tick event of a specific vt_symbol is also pushed. """ self.on_event(EVENT_TICK, tick) self.on_event(EVENT_TICK + tick.vt_symbol, tick)
- 这里可以回顾
CtaEngine
中的process_tick_event
函数,此函数需要传入的参数event: Event
来自于这里。
- 每拿到一笔Tick数据,就将一个
- 成交记录
- 每笔成交都被推送
def on_trade(self, trade: TradeData) -> None: """ Trade event push. Trade event of a specific vt_symbol is also pushed. """ self.on_event(EVENT_TRADE, trade) self.on_event(EVENT_TRADE + trade.vt_symbol, trade)
- 订单记录
- 每次订单提交都被推送
def on_order(self, order: OrderData) -> None: """ Order event push. Order event of a specific vt_orderid is also pushed. """ self.on_event(EVENT_ORDER, order) self.on_event(EVENT_ORDER + order.vt_orderid, order)
- 持仓查询
- 持仓查询事件
def on_position(self, position: PositionData) -> None: """ Position event push. Position event of a specific vt_symbol is also pushed. """ self.on_event(EVENT_POSITION, position) self.on_event(EVENT_POSITION + position.vt_symbol, position)
- 账户余额查询
- 账户余额查询事件
def on_account(self, account: AccountData) -> None: """ Account event push. Account event of a specific vt_accountid is also pushed. """ self.on_event(EVENT_ACCOUNT, account) self.on_event(EVENT_ACCOUNT + account.vt_accountid, account)
- 报价查询
- 报价查询事件
def on_quote(self, quote: QuoteData) -> None: """ Quote event push. Quote event of a specific vt_symbol is also pushed. """ self.on_event(EVENT_QUOTE, quote) self.on_event(EVENT_QUOTE + quote.vt_symbol, quote)
-
其他
def on_log(self, log: LogData) -> None: """ Log event push. """ self.on_event(EVENT_LOG, log) def on_contract(self, contract: ContractData) -> None: """ Contract event push. """ self.on_event(EVENT_CONTRACT, contract) def write_log(self, msg: str) -> None: """ Write a log event from gateway. """ log: LogData = LogData(msg=msg, gateway_name=self.gateway_name) self.on_log(log)
与交易网关交互
具体的实现要因交易网关不同而不同。基本功能模板如下:
- 连接交易网关
@abstractmethod def connect(self, setting: dict) -> None: pass
- 关闭与交易网关的连接
@abstractmethod def close(self) -> None: """ Close gateway connection. """ pass
- 订阅实时行情
@abstractmethod def subscribe(self, req: SubscribeRequest) -> None: """ Subscribe tick data update. """ pass
- 提交订单
@abstractmethod
def send_order(self, req: OrderRequest) -> str:
pass
- 取消订单
@abstractmethod def cancel_order(self, req: CancelRequest) -> None: """ Cancel an existing order. implementation should finish the tasks blow: * send request to server """ pass
- 提交报价
def send_quote(self, req: QuoteRequest) -> str: return ""
- 取消报价
def cancel_quote(self, req: CancelRequest) -> None: """ Cancel an existing quote. implementation should finish the tasks blow: * send request to server """ pass
- 查询:账户余额、持仓、历史行情
@abstractmethod def query_account(self) -> None: """ Query account balance. """ pass @abstractmethod def query_position(self) -> None: """ Query holding positions. """ pass def query_history(self, req: HistoryRequest) -> List[BarData]: """ Query bar history data. """ pass def get_default_setting(self) -> Dict[str, Any]: """ Return default setting dict. """ return self.default_setting
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix