在vnpy1.9.2中,VtGateway是负责行情获取的基类,它有两个成员变量:eventEngine和gatewayName,在新做一个VtGateway时将它们初始化,值从外部传入。成员函数有onTick(),onTrade()和onOrder()等等,用来处理具体的事件。拿其中一个函数举例,在onTick()函数里,封装Event事件,事件放进事件引擎里面去。封装的事件不止一个,既有通用事件,又有特定合约的成交事件。
#vnpy/trader/vtGateway.py
def onTick(self, tick):
"""市场行情推送"""
# 通用事件
event1 = Event(type_=EVENT_TICK)
event1.dict_['data'] = tick
self.eventEngine.put(event1)
# 特定合约代码的事件
event2 = Event(type_=EVENT_TICK+tick.vtSymbol)
event2.dict_['data'] = tick
self.eventEngine.put(event2)
这里,tick包含了事件的信息,包括tick行情合约的代码,在构造Event时,需要制定它的type_,在通用事件的定义中,直接使用EVENT_TICK,在特定合约代码事件中,简单地加上一个tick.vtSymbol。
/vnpy/trader/vtEvent
from vnpy.event.eventType import *
# 系统相关
EVENT_TIMER = 'eTimer' # 计时器事件,每隔1秒发送一次
EVENT_LOG = 'eLog' # 日志事件,全局通用
# Gateway相关
EVENT_TICK = 'eTick.' # TICK行情事件,可后接具体的vtSymbol
……
vnpy中,各种券商的行情接口都需要继承vtGateway类,并且对接引擎的调用。对于接口开发来说,最大的问题在于各种各样的数据封装方式。以ib接口为例,首先继承vtGateway
/vnpy/trader/gateway/ibGateway/ibGateway.py
class IbGateway(VtGateway):
在IbGateway的构造函数中,实例化一个成员子类IbWrapper用来实现诸多与接口api相关的封装
self.api = IbWrapper(self) # API接口
IbWrapper类里面有很多与底层api,也就是券商给出的api的调用了,例如currentTime(self,Time),tickPrice()等等。
/vnpy/trader/gateway/ibGateway/ibGateway.py Class IbWrapper
def tickPrice(self, tickerId, field, price, canAutoExecute):
"""行情价格相关推送"""
if field in tickFieldMap:
# 对于股票、期货等行情,有新价格推送时仅更新tick缓存
# 只有当发生成交后,tickString更新最新成交价时才推送新的tick
# 即bid/ask的价格变动并不会触发新的tick推送
tick = self.tickDict[tickerId]
key = tickFieldMap[field]
tick.__setattr__(key, price)
# IB的外汇行情没有成交价和时间,通过本地计算生成,同时立即推送
p = self.tickProductDict[tickerId]
if p == PRODUCT_FOREX or p == PRODUCT_SPOT:
tick.lastPrice = (tick.bidPrice1 + tick.askPrice1) / 2
dt = datetime.now()
tick.time = dt.strftime('%H:%M:%S.%f')
tick.date = dt.strftime('%Y%m%d')
# 行情数据更新
newtick = copy(tick)
self.gateway.onTick(newtick)
else:
print(field)
通过IbWrapper封装好的数据在IbGateway中调用。在类IbGateway的构造函数里,实例化了IbWrapper,并且在类内用self.api大肆调用。
self.api = IbWrapper(self) # API接口
def subscribe(self, subscribeReq):
在vnpy中,顶层设计是main()函数,在main里,创建Qt应用(略),创建事件引擎
/安装完成后的examples/run.py
ee=EventEngine()
之后创建主引擎
me=MainEngine
再之后添加交易接口
me.addGateway(ibGateway)
之后添加上层应用
me.addApp(riskManager)
#等等,还有很多上层应用种类
最后创建主窗口(展示主窗口,没写在下面)
mw=MainWinow(me,ee)
在主线程中启动Qt消息循环
sys.exit(qApp.exec())
在MainEngine中,实例化一个DataEngine类成员,维护一个tickDict字典,来保存各个行情标的的tick数据,在processTickEvent()函数中更新
/vnpy/trader/vtEngine
def processTickEvent(self, event):
"""处理成交事件"""
tick = event.dict_['data']
self.tickDict[tick.vtSymbol] = tick
在主引擎MainEngine中,addGateway()函数做了如下事情
/vnpy/trader/vtEngine
def addGateway(self, gatewayModule):
"""添加底层接口"""
gatewayName = gatewayModule.gatewayName
# 创建接口实例
self.gatewayDict[gatewayName] = gatewayModule.gatewayClass(self.eventEngine,
gatewayName)
# 设置接口轮询
if gatewayModule.gatewayQryEnabled:
self.gatewayDict[gatewayName].setQryEnabled(gatewayModule.gatewayQryEnabled)
# 保存接口详细信息
d = {
'gatewayName': gatewayModule.gatewayName,
'gatewayDisplayName': gatewayModule.gatewayDisplayName,
'gatewayType': gatewayModule.gatewayType
}
self.gatewayDetailList.append(d)
gatewayClass是在各个券商接口类的构造方法,写在对应的__init__.py里面,以火币接口为例
/vnpy/trader/gateway/huobiGateway/__init__.py
# encoding: UTF-8
from __future__ import absolute_import
from vnpy.trader import vtConstant
from .huobiGateway import HuobiGateway
gatewayClass = HuobiGateway
gatewayName = 'HUOBI'
gatewayDisplayName = u'火币'
gatewayType = vtConstant.GATEWAYTYPE_BTC
gatewayQryEnabled = False