01
前言
我准备写一篇vnpy的入门文章,考虑到入门文章如果讲太多内部细节,就会显得特别累赘,所以将细节和用法单独分离出来,写在这里。本文主要介绍了vnpy中的EventEngine和MainEngine的用法。
2
MainEngine
MainEngine,顾名思义,vnpy的核心。每一个vnpy脚本都需要一个MainEngine的实例。实例化之后可以使用addGateway来增加某种接口(例如ctp接口)。之后可以调用connect连接到服务器。 vnpy连接时会根据提供的gatewayName参数,自动从相应的connect.json文件读取连接配置(IP,端口,用户名,密码等等)来连接(详情请看连接配置文件)。
vnpy的绝大部分操作都可以通过MainEngine完成,例如:
还有一些查询操作
还有gateway相关的操作:
用例:
from vnpy.trader.vtEngine import *
from vnpy.trader.gateway import ctpGateway
event_engine = EventEngine() # 实例化
EventEnginemain_engine = MainEngine(event_engine) # 实例化
MainENginemain_engine.addGateway(ctpGateway.gatewayName) # 增加ctp接口
main_engine.connect(ctpGateway.gatewayName) # 连接ctp服务器
MainEngine.addGateway(gatewayName)
增加某个接口
from vnpy.trader.gateway import ctpGateway
main_engine.addGateway(ctpGateway.gatewayName)
MainEngine.connect(gatewayName)
连接到某个接口的服务器
from vnpy.trader.gateway import ctpGateway
main_engine.addGateway(ctpGateway.gatewayName)
main_engine.connect(ctpGateway.gatewayName)
连接时会自动读取XXX_connect.json以获取连接参数。详情请看连接配置文件
MainEngine.subscribe(req: VtSubscribeReq, gatewayName)
跟服务器订阅行情
from vnpy.trader.vtEngine import VtSubscribeReqreq = VtSubscribeReq()
req.symbol = 'cu1807'
main_engine.subscribe(req, ctpGateway.gatewayName)
VtSubscribeReq详情请看vnpy/trader/vtObject.py
MainEngine.sendOrder(order: VtOrderReq, gatewayName)
下单
from vnpy.trader.vtEngine import *
order = VtOrderReq()
order.symbol = 'cu1807' # 合约代码
# order.exchange = constant.EMPTY_STRING # 交易所, ctp中不需要
# order.vtSymbol = symbol
# VT合约代码, ctp中不需要
order.price = 0 # 价格
order.volume = 1 # 数量
order.direction = constant.DIRECTION_LONG # 买/卖(多头、空头)
order.priceType = constant.PRICETYPE_MARKETPRICE # 价格类型
order.offset = constant.OFFSET_OPEN # 开平
# order.currency = currency
# 货币类型, ctp中不需要
# order.productClass = productClass
# 合约类型, ctp中不需要
order_id = main_engine.sendOrder(order, ctpGateway.gatewayName)
# 监听该订单
def on_order(event): # type: Event
data = event.dict_['data'] # type: VtOrderData print("order : {} status: {}".format(data.vtOrderID, data.status)) pass event_engine.register(EVENT_ORDER + order_id, on_order)
VtOrderReq详情请看vnpy/trader/vtObject.py
MainEngine.cancelOrder(order: VtOrderData, gatewayName)
取消某个订单。
若要取消某个sendOrder发出去的订单,请使用EventEngine的特定消息监听,以获取对应的VtOrderData。
def cancel_all_working_orders(): for order in main_engine.getAllWorkingOrders(): # type: VtOrderData main_engine.cancelOrder(order, order.gatewayName)
VtOrderData详情请看vnpy/trader/vtObject.py
MainEngine.getTick(vtSymbol)->VtTickData
获取行情。 在获取行情之前,必须从服务器订阅行情。使用MainEngine.subscribe从服务器订阅行情。
from vnpy.trader.vtEngine import VtTickData
tick = main_engine.getTick('cu1807') # type: VtTickData
if(tick): last_price = tick.lastPrice
MainEngine.getAllPositions()-> List[VtPositionData]
获取所有合约的仓位
VtPositionData详情请看vnpy/trader/vtObject.py
3
EventEngine
vnpy是基于事件驱动的,所以需要一个消息处理引擎。EventEngine类便是用于消息处理的。 每个vnpy脚本都需要一个EventEngine。直接构造即可。如果需要监听某个消息,使用EventEngine.register即可。因为MainEngine也会用到EventEngine,所以大部分消息只需要监听就可以收到消息。但是行情消息(EVENT_TICK)必须在服务器订阅之后才会收到消息,使用MainEngine.subscribe来跟服务器订阅行情。
一般情况下都不需要自己手动调用EventEngine的其他函数。因为EventEngine会被MainEngine启动。
注册消息时可以注册很多特定消息,一般用法是监听消息类型+ID的消息(详情请看用例或者vnpy/trader/vtGateway.py)。
用例:
from vnpy.trader.vtEngine import *
# 1HZ计时器
def on_timer(event): # type: Event
pass
# 行情消息
def on_tick(event): # type: Event tick = event.dict_['data'] # type: VtTickData symbol = tick.symbol price = tick.lastPrice pass
# 仓位变化消息
def on_position(event): # type: Event
data = event.dict_['data'] # type: VtPositionData symbol = data.symbol pos = data.position pass
# 特定合约的行情
def on_cu1807_tick(event): # type: Event tick = event.dict_['data'] # type: VtTickData current_cu1807_price = tick.lastPrice pass
# 特定合约的仓位
def on_cu1807_position(event): # type: data = event.dict_['data'] # type: VtPositionData pos = data.position pass
event_engine = EventEngine() # 实例化
EventEngineevent_engine.register(EVENT_TIMER, on_timer) # 监听1Hz的计时器
event_engine.register(EVENT_TICK, on_tick) # 监听行情消息(需要从服务器订阅)
# 特定消息
event_engine.register(EVENT_TICK + 'cu1807', on_cu1807_tick) # 监听cu1807的行情(需要从服务器订阅)
event_engine.register(EVENT_POSITION + 'cu1807', on_cu1807_position) # 监听cu1807的仓位变化
VtTickData详情请看vnpy/trader/vtObject.py。 vnpy.EventEngine的完全运行还依赖Qt环境,详情请看下文EventEngine和EventEngine2的区别。
EventEngine.register(type:str, handler:Callable[Event])
监听某个消息,当消息发生时,调用handler。
type的基本的一些值可以看vnpy/trader/vtEvent.py
EventEngine.start(timer:bool)
启动消息引擎,若timer为真,则顺便启动一个频率为1s的计时器 MainEngine使用的消息引擎不需要调用此方法。
EventEngine.stop()
停止消息引擎
EventEngine.put(event:Event)
在消息队列中增加一条消息。
from vnpy.trader.vtEngine import Event
EVENT_CUSTOM_1 = 'cusotm_event_1'
event = Event(EVENT_CUSTOM_1)
event.dict_['val1'] = 'value one'
event_engine.put(event)
EventEngine和EventEngine2的区别
vnpy有两个消息处理引擎,分别是EventEngine和EventEngine2,分别用于Qt环境和非Qt环境。 EventEngine内部用到了QTimer,所以正常运行需要Qt环境。 EventEngine2除了不依赖Qt之外,和EventEngine完全一样。
要完全运行EventEngine,需要构建Qt运行环境:
from vnpy.event import EventEngine
from vnpy.trader.uiQt import createQApp
def main(): app = createQApp()
event_engine = EventEngine() app.exec_() # 至此,Qt环境才算完全初始化完成
连接配置文件
vnpy连接到服务器时时会自动读取XXX_connect.json以获取连接参数。其中XXX是接口名称,例如ctp接口对应的就是CTP_connect.json。examples/VnTrader/目录下有各种connect.json的样本。推荐将该json文件放于当前工作目录下。
基于python的开源交易平台开发框架。截止目前,vn.py项目在Github上的Star已经达到5787,量化交易类开源项目第1,量化类项目第3(1、2依旧分别是Zipline和TuShare)。
项目官网:http://www.vnpy.org
论坛地址:www.vnpie.com
知乎专栏:https://zhuanlan.zhihu.com/vn-py
Developed by Traders,
for Traders