diff --git a/README.md b/README.md index f46f0d19..4ed0dc18 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,13 @@ vn.py是一套基于Python的开源量化交易系统开发框架,于2015年1月正式发布,在开源社区5年持续不断的贡献下一步步成长为全功能量化交易平台,目前国内外金融机构用户已经超过300家,包括:私募基金、证券自营和资管、期货资管和子公司、高校研究机构、自营交易公司、交易所、Token Fund等。 -使用过程中有任何疑问,请查看[**vn.py项目文档**](https://www.vnpy.com/docs/cn/index.html),如果无法解决请前往[**官方社区论坛**](https://www.vnpy.com/forum/)的【提问求助】板块寻求帮助,也欢迎在【经验分享】板块分享你的使用心得! +**傻瓜式入门教程**已经在官方微信公众号[**vnpy-community**]全新上线,新手使用过程中有任何疑问看这个解决是最快的,后续会不断增加进阶经验、发布公告、活动报名等功能,请扫描下方二维码关注: -官方微信公众号:**vnpy-community**,接下来将在公众号中陆续上线各种关于vn.py的使用教程,欢迎关注。 +

+ +

+ +在使用vn.py进行二次开发(策略、模块等)的过程中有任何疑问,请查看[**vn.py项目文档**](https://www.vnpy.com/docs/cn/index.html),如果无法解决请前往[**官方社区论坛**](https://www.vnpy.com/forum/)的【提问求助】板块寻求帮助,也欢迎在【经验分享】板块分享你的使用心得! 2.0版本基于Python 3.7全新重构开发,如需Python 2上的版本请点击:[长期支持版本v1.9.2 LTS](https://github.com/vnpy/vnpy/tree/v1.9.2-LTS)。 diff --git a/docs/gateway.md b/docs/gateway.md index 4b184b12..90a53e22 100644 --- a/docs/gateway.md +++ b/docs/gateway.md @@ -74,6 +74,7 @@ def main(): | 接口 | 类型 | | -------- | :----------------------------------------: | | CTP | 期货 | +| MINI | 期货 | | FEMAS | 期货 | | XTP | 国内股票、指数、基金、债券、期权、融资融券 | | OES | 国内股票 | @@ -85,12 +86,13 @@ def main(): | ALPACA | 美股 | | BITFINEX | 数字货币 | | BITMEX | 数字货币 | +| BINANCE | 数字货币 | | OKEX | 数字货币 | | OKEXF | 数字货币 | | HUOBI | 数字货币 | | HBDM | 数字货币 | | ONETOKEN | 数字货币 | -| RPC | RPC服务 | +| RPC | RPC服务 | @@ -130,6 +132,37 @@ main_engine.add_gateway(CtpGateway) - 实盘账号:在期货公司开户,通过联系客户经理可以开通。用户名为纯数字,经纪商编号也是4位纯数字。(每个期货公司的经纪商编号都不同)另外,实盘账号也可以开通仿真交易功能,同样需要联系客户经理。 +  + +### MINI + +#### 如何加载 + +先从gateway上调用MiniGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.mini import MiniGateway +main_engine.add_gateway(MiniGateway) +``` + +  + +#### 相关字段 + +- 用户名:username +- 密码:password: +- 经纪商编号:brokerid +- 交易服务器地址:td_address +- 行情服务器地址:md_address +- 产品名称:product_info +- 授权编码:auth_code + +  + +#### 获取账号 + +在期货公司开户,通过联系客户经理可以开通。用户名为纯数字,经纪商编号也是4位纯数字。(每个期货公司的经纪商编号都不同)另外,实盘账号也可以开通仿真交易功能,同样需要联系客户经理。 + +   ### 飞马(FEMAS) @@ -248,11 +281,27 @@ main_engine.add_gateway(OesGateway) #### 如何加载 +先从gateway上调用ToraGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.tota import ToraGateway +main_engine.add_gateway(OesGateway) +``` + +  + #### 相关字段 +- 账号: username +- 密码: password +- 交易服务器: td_address +- 行情服务器: md_address + +  + #### 获取账号 -#### 其他特点 +测试账号请联系华鑫证券申请 +   @@ -400,11 +449,21 @@ main_engine.add_gateway(TigerGateway) ### ALPACA #### 如何加载 +先从gateway上调用AlpacaGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.alpaca import AlpacaGateway +main_engine.add_gateway(AlpacaGateway) +``` + +  #### 相关字段 - +- KEY ID: key +- Secret Key: secret +- 会话数: 10 +- 服务器:["REAL", "PAPER"] #### 获取账号 - +在OKEX官网开户并且入金后可以获得API接入权限。 #### 其他特点   @@ -655,6 +714,38 @@ main_engine.add_gateway(OnetokenGateway) +  + +  + +### BINANCE + +#### 如何加载 + +先从gateway上调用BinanceGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.binance import BinanceGateway +main_engine.add_gateway(BinanceGateway) +``` + +  + + +#### 相关字段 + +- Key秘钥 +- secret +- session_number(会话数):3 +- proxy_host +- proxy_port + +  + + +#### 获取账号 + +在BINANCE官网开户并且入金后可以获得API接入权限。 +   @@ -662,10 +753,795 @@ main_engine.add_gateway(OnetokenGateway) #### 如何加载 +RPC的加载涉及到服务端和客户端 +- 服务端:运行vntrader时加载rpc_service模块 + ``` + from vnpy.app.rpc_service import RpcService + ``` + 启动vntrader后,首先连接外部交易交易如CTP,然后点击菜单栏"功能"->"RPC服务",点击"启动" +- 客户端:运行vntrader时加载RpcGateway + ``` + from vnpy.gateway.rpc import RpcGateway + ``` + 启动vntrader后,连接rpc接口即可。 #### 相关字段 +在服务端和客户端,使用默认填好的参数即可 + +#### 获取账号 +使用rpc无须额外申请账号,只需要一个外部接口账号 + +#### 其他特点 +rpc服务支持同一外部接口数据在本地多进程分发,比如在服务端连接了ctp接口,订阅了rb1910后,客户端多个进程会自动订阅来自服务端分发的订阅数据# 交易接口 + +## 如何连接 + +从gateway文件夹上引入接口程序,通过add_gateway()函数调动,最终展示到图形化操作界面VN Trader中。 + +在菜单栏中点击"系统"->"连接CTP”按钮会弹出如图账号配置窗口,输入账号、密码等相关信息即连接接口,并立刻进行查询工作: 如查询账号信息、查询持仓、查询委托信息、查询成交信息等。 + +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/gateway/login.png) + +  + +### 加载需要用的接口 + +加载接口示例在根目录"tests\trader"文件夹的run.py文件中。 +- 从gateway文件夹引入接口类文件,如from vnpy.gateway.ctp import CtpGateway; +- 创建事件引擎对象并且通过add_gateway()函数添加接口程序; +- 创建图形化对象main_window,以VN Trader操作界面展示出来。 + + +``` +from vnpy.gateway.ctp import CtpGateway + +def main(): + """""" + qapp = create_qapp() + main_engine = MainEngine(event_engine) + main_engine.add_gateway(CtpGateway) + main_window = MainWindow(main_engine, event_engine) + main_window.showMaximized() + qapp.exec() +``` + +  + + +### 配置和连接 + +打开cmd窗口,使用命令“Python run.py"即可进入VN Trader操作界面。在左上方的菜单栏中点击"系统"->"连接CTP”按钮会弹出账号配置窗口,输入账号、密码等相关信息即连接接口。 + +连接接口的流程首先是初始化账户信息,然后调用connet()函数来连接交易端口和行情端口。 +- 交易端口:查询用户相关信息(如账户资金、持仓、委托记录、成交记录)、查询可交易合约信息、挂撤单操作; +- 行情端口:接收订阅的行情信息推送、接收用户相关信息(如账户资金更新、持仓更新、委托推送、成交推送)更新的回调推送。 + + +  + + +### 修改json配置文件 + +接口配置相关保存在json文件中,放在如图C盘用户目录下的.vntrader文件夹内。 + +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/gateway/.vntrader.png) + +所以要修改接口配置文件,用户即可以在图形化界面VN Trader内修改,也可以直接在.vntrader修改json文件。 +另外将json配置文件分离于vnpy的好处在于:避免每次升级都要重新配置json文件。 + + +  + + +### 查看可交易的合约 + +先登录接口,然后在菜单栏中点击"帮助"->"查询合约”按钮会空白的“查询合约”窗口。点击“查询”按钮后才会显示查询结果,如图。 + +![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/gateway/query_contract.png) + + + +  + +## 接口分类 + +| 接口 | 类型 | +| -------- | :----------------------------------------: | +| CTP | 期货 | +| MINI | 期货 | +| FEMAS | 期货 | +| XTP | 国内股票、指数、基金、债券、期权、融资融券 | +| OES | 国内股票 | +| TORA | 国内股票 | +| IB | 外盘股票、期货、期权 | +| TAP | 外盘期货、期权 | +| FUTU | 国内股票、港股、美股 | +| TIGER | 国内股票、港股、美股 | +| ALPACA | 美股 | +| BITFINEX | 数字货币 | +| BITMEX | 数字货币 | +| BINANCE | 数字货币 | +| OKEX | 数字货币 | +| OKEXF | 数字货币 | +| HUOBI | 数字货币 | +| HBDM | 数字货币 | +| ONETOKEN | 数字货币 | +| RPC | RPC服务 | + + + +  + + +## 接口详解 + +### CTP + +#### 如何加载 + +run.py文件提供了接口加载示例:先从gateway上调用ctpGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.ctp import CtpGateway +main_engine.add_gateway(CtpGateway) +``` + +  + +#### 相关字段 + +- 用户名:username +- 密码:password: +- 经纪商编号:brokerid +- 交易服务器地址:td_address +- 行情服务器地址:md_address +- 产品名称:product_info +- 授权编码:auth_code + +  #### 获取账号 +- 仿真账号:从SimNow网站上获取。只需输入手机号码和短信验证即可。(短信验证有时只能在工作日正常工作时段收到)SimNow的用户名为6位纯数字,经纪商编号为9999,并且提供2套环境用于盘中仿真交易以及盘后的测试。 + +- 实盘账号:在期货公司开户,通过联系客户经理可以开通。用户名为纯数字,经纪商编号也是4位纯数字。(每个期货公司的经纪商编号都不同)另外,实盘账号也可以开通仿真交易功能,同样需要联系客户经理。 + + +  + +### MINI + +#### 如何加载 + +先从gateway上调用MiniGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.mini import MiniGateway +main_engine.add_gateway(MiniGateway) +``` + +  + +#### 相关字段 + +- 用户名:username +- 密码:password: +- 经纪商编号:brokerid +- 交易服务器地址:td_address +- 行情服务器地址:md_address +- 产品名称:product_info +- 授权编码:auth_code + +  + +#### 获取账号 + +在期货公司开户,通过联系客户经理可以开通。用户名为纯数字,经纪商编号也是4位纯数字。(每个期货公司的经纪商编号都不同)另外,实盘账号也可以开通仿真交易功能,同样需要联系客户经理。 + + +  + +### 飞马(FEMAS) + +#### 如何加载 + +先从gateway上调用FemasGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.femas import FemasGateway +main_engine.add_gateway(FemasGateway) +``` + +  + +#### 相关字段 + +- 用户名:username +- 密码:password: +- 经纪商编号:brokerid +- 交易服务器地址:td_address +- 行情服务器地址:md_address +- 产品名称:product_info +- 授权编码:auth_code + +  + +#### 获取账号 + +在期货公司开户,通过联系客户经理可以开通。用户名为纯数字,经纪商编号也是4位纯数字。(每个期货公司的经纪商编号都不同)另外,实盘账号也可以开通仿真交易功能,同样需要联系客户经理。 + + +  + + + +### 中泰柜台(XTP) + +#### 如何加载 + +先从gateway上调用XtpGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.xtp import XtpGateway +main_engine.add_gateway(XtpGateway) +``` + +  + + +#### 相关字段 + +- 账号: +- 密码: +- 客户号": 1 +- 行情地址: +- 行情端口": 0 +- 交易地址: +- 交易端口": 0 +- 行情协议: ["TCP", "UDP"] +- 授权码: + +  + + +#### 获取账号 + +测试账号请联系中泰证券申请。 + #### 其他特点 -  \ No newline at end of file +XTP是首家提供融资融券的极速柜台。 + +  + + +### 宽睿柜台(OES) + +#### 如何加载 + +先从gateway上调用OesGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.oes import OesGateway +main_engine.add_gateway(OesGateway) +``` + +  + + +#### 相关字段 + +- 用户名:username +- 密码:password +- 硬盘序列号:hdd_serial +- 交易委托服务器:td_ord_server +- 交易回报服务器:td_rpt_server +- 交易查询服务器:td_qry_server +- 行情推送服务器:md_tcp_server +- 行情查询服务器:md_qry_server + +  + + +#### 获取账号 + +测试账号请联系宽睿科技申请 + +  + +#### 其他特点 + +宽睿柜台提供内网UDP低延时组播行情以及实时成交信息推送。 + +  + + +### 华鑫奇点(TORA) + +#### 如何加载 + +先从gateway上调用ToraGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.tota import ToraGateway +main_engine.add_gateway(OesGateway) +``` + +  + +#### 相关字段 + +- 账号: username +- 密码: password +- 交易服务器: td_address +- 行情服务器: md_address + +  + +#### 获取账号 + +测试账号请联系华鑫证券申请 + + +  + +### 盈透证券(IB) + +#### 如何加载 + +先从gateway上调用IbGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.ib import IbGateway +main_engine.add_gateway(IbGateway) +``` + +  + + +#### 相关字段 + +- TWS地址:127.0.0.1 +- TWS端口:7497 +- 客户号:1 + + +  + + +#### 获取账号 + +在盈透证券开户并且入金后可以获得API接入权限。拥有实盘账号后才可以申请开通仿真交易账号。 + +  + +#### 其他特点 + +可交易品种几乎覆盖全球的股票、期权、期权;手续费相对较低。 + +注意IB接口的合约代码较为特殊,请前往官网的产品查询板块查询,VN Trader中使用的是盈透证券对于每个合约在某一交易所的唯一标识符ConId来作为合约代码,而非Symbol或者LocalName。 + +  + + +### 易盛外盘(TAP) + +#### 如何加载 + +先从gateway上调用TapGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.tap import TapGateway +main_engine.add_gateway(TapGateway) +``` + +  + + +#### 相关字段 + +- 授权码:auth code +- 行情账号:quote username +- 行情密码:quote password +- 行情地址:123.15.58.21 +- 行情端口:7171 + + + +  + + +#### 获取账号 + +在TAP开户并且入金后可以获得API接入权限。 + +  + + +### 富途证券(FUTU) + +#### 如何加载 + +先从gateway上调用FutuGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.futu import FutuGateway +main_engine.add_gateway(FutuGateway) +``` + +  + + +#### 相关字段 + +- 地址:127.0.0.1 +- 密码: +- 端口:11111 +- 市场:HK 或 US +- 环境:TrdEnv.REAL 或 TrdEnv.SIMULATE + + +  + + +#### 获取账号 + +在富途证券开户并且入金后可以获得API接入权限。拥有实盘账号后才可以申请开通仿真交易账号。 + + + + + + +  + +### 老虎证券(TIGER) + + +#### 如何加载 + +先从gateway上调用TigerGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.tiger import TigerGateway +main_engine.add_gateway(TigerGateway) +``` + +  + + +#### 相关字段 + +- 用户ID:tiger_id +- 环球账户:account +- 标准账户:standard_account +- 秘钥:private_key + + + +  + + +#### 获取账号 + +在老虎证券开户并且入金后可以获得API接入权限。拥有实盘账号后才可以申请开通仿真交易账号。 + + +  + + +### ALPACA + +#### 如何加载 +先从gateway上调用AlpacaGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.alpaca import AlpacaGateway +main_engine.add_gateway(AlpacaGateway) +``` + +  + +#### 相关字段 +- KEY ID: key +- Secret Key: secret +- 会话数: 10 +- 服务器:["REAL", "PAPER"] +#### 获取账号 +在OKEX官网开户并且入金后可以获得API接入权限。 +#### 其他特点 + +  + + +### BITMEX + +#### 如何加载 + +先从gateway上调用BitmexGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.bitmex import BitmexGateway +main_engine.add_gateway(BitmexGateway) +``` + +  + + +#### 相关字段 + +- 用户ID:ID +- 密码:Secret +- 会话数:3 +- 服务器:REAL 或 TESTNET +- 代理地址: +- 代理端口: + + + +  + + +#### 获取账号 + +在BITMEX官网开户并且入金后可以获得API接入权限。 + + + +  + +### OKEX现货(OKEX) + + +#### 如何加载 + +先从gateway上调用OkexGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.okex import OkexGateway +main_engine.add_gateway(OkexGateway) +``` + +  + + +#### 相关字段 + +- API秘钥:API Key +- 密码秘钥:Secret Key +- 会话数:3 +- 密码:passphrase +- 代理地址: +- 代理端口: + + + +  + + +#### 获取账号 + +在OKEX官网开户并且入金后可以获得API接入权限。 + + + +  + + +### OKEX期货(OKEXF) + + +#### 如何加载 + +先从gateway上调用OkexfGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.okexf import OkexfGateway +main_engine.add_gateway(OkexfGateway) +``` + +  + + +#### 相关字段 + +- API秘钥:API Key +- 密码秘钥:Secret Key +- 会话数:3 +- 密码:passphrase +- 杠杆:Leverage +- 代理地址: +- 代理端口: + + + +  + + +#### 获取账号 + +在OKEX官网开户并且入金后可以获得API接入权限。 + + +  + +### 火币(HUOBI) + +#### 如何加载 + +先从gateway上调用HuobiGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.huobi import HuobiGateway +main_engine.add_gateway(HuobiGateway) +``` + +  + + +#### 相关字段 + +- API秘钥:API Key +- 密码秘钥:Secret Key +- 会话数:3 +- 代理地址: +- 代理端口: + + + +  + + +#### 获取账号 + +在火币官网开户并且入金后可以获得API接入权限。 + + +  + + + +### 火币合约(HBDM) + +#### 如何加载 + +先从gateway上调用HbdmGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.hbdm import HbdmGateway +main_engine.add_gateway(HbdmGateway) +``` + +  + + +#### 相关字段 + +- API秘钥:API Key +- 密码秘钥:Secret Key +- 会话数:3 +- 代理地址: +- 代理端口: + + + +  + + +#### 获取账号 + +在火币官网开户并且入金后可以获得API接入权限。 + + +  + +### BITFINEX + +#### 如何加载 + +先从gateway上调用BitFinexGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.bitfinex import BitfinexGateway +main_engine.add_gateway(BitfinexGateway) +``` + +  + + +#### 相关字段 + +- 用户ID:ID +- 密码:Secret +- 会话数:3 +- 代理地址: +- 代理端口: + + + +  + + +#### 获取账号 + +在BITFINEX官网开户并且入金后可以获得API接入权限。 + + + +  + + +### ONETOKEN + +#### 如何加载 + +先从gateway上调用OnetokenGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.onetoken import OnetokenGateway +main_engine.add_gateway(OnetokenGateway) +``` + +  + + +#### 相关字段 + +- Key秘钥:OT Key +- 密码秘钥:OT Secret +- 会话数:3 +- 交易所:["BINANCE", "BITMEX", "OKEX", "OKEF", "HUOBIP", "HUOBIF"] +- 账号: +- 代理地址: +- 代理端口: + + + +  + + +#### 获取账号 + +在Onetoken官网开户并且入金后可以获得API接入权限。 + + + +  + +  + +### BINANCE + +#### 如何加载 + +先从gateway上调用BinanceGateway类;然后通过add_gateway()函数添加到main_engine上。 +``` +from vnpy.gateway.binance import BinanceGateway +main_engine.add_gateway(BinanceGateway) +``` + +  + + +#### 相关字段 + +- Key秘钥 +- secret +- session_number(会话数):3 +- proxy_host +- proxy_port + +  + + +#### 获取账号 + +在BINANCE官网开户并且入金后可以获得API接入权限。 + +  + + +### RPC + +#### 如何加载 + +RPC的加载涉及到服务端和客户端 +- 服务端:运行vntrader时加载rpc_service模块 + ``` + from vnpy.app.rpc_service import RpcService + ``` + 启动vntrader后,首先连接外部交易交易如CTP,然后点击菜单栏"功能"->"RPC服务",点击"启动" +- 客户端:运行vntrader时加载RpcGateway + ``` + from vnpy.gateway.rpc import RpcGateway + ``` + 启动vntrader后,连接rpc接口即可。 +#### 相关字段 +在服务端和客户端,使用默认填好的参数即可 + +#### 获取账号 +使用rpc无须额外申请账号,只需要一个外部接口账号 + +#### 其他特点 +rpc服务支持同一外部接口数据在本地多进程分发,比如在服务端连接了ctp接口,订阅了rb1910后,客户端多个进程会自动订阅来自服务端分发的订阅数据 diff --git a/docs/rpc_service.md b/docs/rpc_service.md index f309bffa..7365ebc6 100644 --- a/docs/rpc_service.md +++ b/docs/rpc_service.md @@ -1 +1,33 @@ -# RPC服务 \ No newline at end of file +# RPC服务 + +由于全局锁GIL的存在,单进程的Python程序只能利用CPU单核的算力,为了突破这一限制,解决方案就是多进程分布式的程序架构。但每个进程之间的数据,在操作系统内默认是独立隔离的,无法直接访问。RPC全称Remote-Procedure-Call,中文“远程过程调用”,是最常用的跨进程通讯方式之一。 + + + + +## RPC服务器 + +### 加载模块 + +### 启动运行 + + +## RPC客户端 + +### 加载接口 + +### 连接使用 + + +## 参考样例 + +位于examples/server_client目录下 + +### 服务器进程 + +GUI模式 + +无界面模式 + +### 客户端进程 + diff --git a/docs/script_trader.md b/docs/script_trader.md index 5767632d..3fd1fb2f 100644 --- a/docs/script_trader.md +++ b/docs/script_trader.md @@ -1 +1,234 @@ -# 脚本策略 \ No newline at end of file +# 脚本策略 + +ScriptTrader模块的作用:既提供交互式的量化分析和程序化交易功能,又能提供以整个策略连续运行的脚本策略功能。 +ScriptTrader可视为直接利用python对证券交易客户端进行操作,它与CTA策略模块较为明显的区别在于突破了单交易所,单标的的限制,可以较方便的实现如股指期货和一篮子股票之间的对冲策略、跨品种套利、股票市场扫描自动化选股等功能。 + +## Jupyter模式 + +### 加载启动 +Jupyter模式下,一切都以 **ScriptEngine** 为核心 +成功启动jupyter notebook后,进行如下操作来加载组件、初始化脚本引擎: +``` +from vnpy.app.script_trader import init_cli_trading +from vnpy.gateway.ctp import CtpGateway + +engine = init_cli_trading([CtpGateway]) +``` +**注**: +- ScriptEngine支持同时连接多个接口,因此除了上述CTP接口,还可以自行添加其他交易接口。 +- 在```init_cli_trading(gateways: Sequence[BaseGateway])```中,将多个需要连接的接口类用列表的形式传递给init\_cli\_trading。 +- init\_cli\_trading可视为vnpy封好的初始化启动函数,函数内部将主引擎、脚本引擎等各种对象已经组装完毕,仅返回ScriptEngine供用户直接使用。 + +### 连接接口 +不同接口需要不同的配置参数,以ctp为例,连入simnow模拟交易。 +``` +setting = { + "用户名": "xxxx", + "密码": "xxxx", + "经纪商代码": "9999", + "交易服务器":"tcp://180.168.146.187:10101", + "行情服务器":"tcp://180.168.146.187:10111", + "产品名称":"simnow_xxx_test", + "授权编码":"0000000000000000", + "产品信息": "" +} +engine.connect_gateway(setting,"CTP") +``` +![](https://m.qpic.cn/psb?/V12TMAOq2xN6BZ/n*ZnJEhNKgpm2vJ6XWASfsVE9RGs.XlkkiypK1iId8Y!/b/dLYAAAAAAAAA&bo=ggSoA4IEqAMRCT4!&rf=viewer_4) +**注**: +- 如果对setting的填写有疑问,可以按照vnpy/gateway目录下的接口类的default_setting来填写。 + +### 查询数据 + +这里介绍一下连接上交易接口并成功订阅数据后的数据存储。底层接口不停向主引擎推送新的数据,在主引擎里维护着一个ticks字典用于缓存不同标的的最新tick数据(仅能缓存最新的)。 +use_df可选参数的作用(返回pandas.DataFrame,在Jupyter中分析更方便)。 + +### 发出指令 +- subscribe:连接上交易接口后还需要订阅特定的合约才能收到交易所推送过来的数据。以订阅螺纹钢1909,1910为例 + ``` + engine.subscribe(vt_symbols = ["rb1909.SHFE","rb1910.SHFE"]) + ``` + - vt_symbols:需要填写的参数形式是列表,内部包含vt_symbol。 +   +## 脚本策略模式 + +### 加载启动 + +如在脚本策略模式下使用,需要提前编写相关脚本策略文件,假设为demo_arbitrage.py,然后打开vntrader,在菜单栏"功能"处打开"脚本策略",在跳出的脚本策略窗口最上方打开/Path-To-demo_arbitrage.py/demo_arbitrage.py,然后直接启动即可。 +![](https://m.qpic.cn/psb?/V12TMAOq2xN6BZ/S4RiCWfQvQck6*2aJ201*.mB0Jkvn.f6yOC2zf5a02A!/b/dLsAAAAAAAAA&bo=Mge8ADIHvAARCT4!&rf=viewer_4) +### 脚本策略 +脚本策略文件编写需要遵循一定格式,下面展示一个基础的模板 +``` +from time import sleep +from vnpy.app.script_trader import ScriptEngine + +def run(engine: ScriptEngine): + """""" + vt_symbols = ["IF1912.CFFEX", "rb2001.SHFE"] + + # 订阅行情 + engine.subscribe(vt_symbols) + + # 获取合约信息 + for vt_symbol in vt_symbols: + contract = engine.get_contract(vt_symbol) + msg = f"合约信息,{contract}" + engine.write_log(msg) + + # 持续运行,使用strategy_active来判断是否要退出程序 + while engine.strategy_active: + # 轮询获取行情 + for vt_symbol in vt_symbols: + tick = engine.get_tick(vt_symbol) + msg = f"最新行情, {tick}" + engine.write_log(msg) + + # 等待3秒进入下一轮 + sleep(3) +``` +该脚本策略的功能为:订阅两个品种的行情,打印合约信息,每隔3秒获取最新行情。 +### 运行控制 + +while循环的退出控制变量:engine.strategy_active +- engine.strategy_active是脚本策略的开关,当点击“启动”时,该控制变量变为True,程序将一直在while循环内部不断运行;当点击“停止”时,该控制变量变为False,程序将运行完当前while循环后完全退出 +- 脚本策略在编写时最重要的一点是主体部分要在while循环内部进行。 +  +## 函数功能说明 + +### 单条查询 +* **在单条查询函数中,都有use_df参数用来控制是否将函数返回的类对象转化成DataFrame,仅在get_tick中做一次详细说明,其余函数同理。** +  + +* get\_tick:查询单个标的最新tick。 + ``` + tick = engine.get_tick(vt_symbol="rb1910.SHFE",use_df=False) + ``` + - vt_symbol:字符串参数,表示本地合约代码。 + - use_df:bool变量,默认False,返回TickData类对象,否则返回相应DataFrame。 + + ![](https://m.qpic.cn/psb?/V12TMAOq2xN6BZ/o38RYahmAsmLqPDz2cUixiDU19TGFqMH0e8WBg3wgHU!/b/dL4AAAAAAAAA&bo=iQaAAuIHBAMDCcM!&rf=viewer_4) + 注:DataFrame的列是TickData类属性,行是TickData个数,由于单条查询,则只有一行。 +   + +* get\_order:根据vt_orderid查询委托单的详细信息。 + ``` + order = engine.get_order(vt_orderid='CTP.3_-9351590_1',use_df=False) + ``` + - vt_orderid:在委托下单时,会自动返回该委托的vt_orderid,以"CTP.3_-9351590_1"为例,它由ctp接口的name,frontid,sessionid,order_ref构成。其中,frontid和sessionid在vnpy连接上CTP接口后由CTP回调产生,order_ref是vnpy内部维护的用于区分order的一个变量。最前面还要加上接口名是因为vnpy可能同时连着很多接口进行交易。 + + ![](https://m.qpic.cn/psb?/V12TMAOq2xN6BZ/cvmqxaHqSjRaRoR6FXdY3vt7JRm2XtNAYB*lwDY0rmY!/b/dAgBAAAAAAAA&bo=1AfGANQHxgADCSw!&rf=viewer_4) +   + +* get\_contract:根据本地vt_symbol来查询对应合约对象的详细信息。 + ``` + contract = engine.get_contract(vt_symbol="rb1910.SHFE",use_df=False) + ``` + - vt_symbol:字符串参数,表示本地合约代码。 + + ![](https://m.qpic.cn/psb?/V12TMAOq2xN6BZ/*.vXu2esXg2.iImnZ838FFYMrCBeDBOXnnFKAcpaUK0!/b/dL8AAAAAAAAA&bo=6AfUAOgH1AARCT4!&rf=viewer_4) +  + +* get\_bars:查询历史数据,要求提前在vt_setting.json中配置好rqdata相关设置。 + ``` + bars = engine.get_bars(vt_symbol="rb1910.SHFE",start_date="20190101", + interval=Interval.MINUTE,use_df=False) + ``` + - vt_symbol:字符串参数,表示本地合约代码。 + - start_date:字符串参数,格式必须为'%Y%m%d'。 + - interval:查询数据的间隔,可选参数有[Interval.MINUTE,Interval.HOUR,Interval.DAILY,Interval.WEEKLY]。 + + 特别说明:默认返回的是返回的bars是一个list,里面包含了一系列BarData数据,其中BarData定义了如下字段: + ``` + @dataclass + class BarData(BaseData): + + symbol: str + exchange: Exchange + datetime: datetime + interval: Interval = None + volume: float = 0 + open_interest: float = 0 + open_price: float = 0 + high_price: float = 0 + low_price: float = 0 + close_price: float = 0 + + def __post_init__(self): + self.vt_symbol = f"{self.symbol}.{self.exchange.value}" + ``` +   + +* get\_position:根据vt_positionid来查询持仓情况,包括接口名称、交易所、合约代码、数量、冻结数量等。 + ``` + position = engine.get_position(vt_positionid='rb1909.SHFE.Direction.LONG') + ``` + - vt_positionid:vnpy内部对于一笔特定持仓的唯一持仓编号,格式为"vt_symbol.Direction.LONG",其中方向可选择为```DIRECTION.SHORT```或```DIRECTION.NET``` + + ![](https://m.qpic.cn/psb?/V12TMAOq2xN6BZ/szBIwwFgVmdXsBGYAWpkpZoA9m5ER0hmu*xya9c7u.Y!/b/dLYAAAAAAAAA&bo=3geuAN4HrgARCT4!&rf=viewer_4) + +  + +### 多条查询 +* **在多条查询函数中,use_df参数都可以用来控制是否将函数返回的类对象转化成DataFrame,仅在get_ticks中做一次详细说明,其余函数同理。** +  + +* get\_ticks:查询多个合约最新tick。 + ``` + ticks = engine.get_ticks(vt_symbols=['rb1910.SHFE','rb1909.SHFE'],use_df = True) + ``` + - use\_df:False则返回一个列表,元素为TickData;True则返回DataFrame,列是TickData的属性,每一行代表一个TickData。 + - vt_symbols:一个列表,元素为合约字符串vt_symbol。 + + ![](https://m.qpic.cn/psb?/V12TMAOq2xN6BZ/ghZR0VV5APiKLh5Zx73x7qgz1IwJ3zrG4MKVNen8PXc!/b/dL8AAAAAAAAA&bo=kAWAAvYHlAMDCV0!&rf=viewer_4) +  + +* get\_orders:根据查询多个vt_orderid查询其详细信息,**注**:如果use\_df=False则返回的是一个list,包含OrderData类对象,否则返回一个列是OrderData属性具有多行数据的DataFrame + ``` + orders = engine.get_orders([orderid_one,orderid_two],use_df=True) + ``` + - vt_orderids:列表,元素是vt_orderid形式的字符串,和上面提到的get_order的参数形式一致,由ctp接口的name,frontid,sessionid,order_ref构成。 +   +* get\_trades:根据给定的一个vt_orderid返回这次报单过程中的所有TradeData对象。 + ``` + trades = engine.get_trades(vt_orderid = your_vt_orderid,use_df = True) + ``` + - vt_orderid:vnpy本地订单id,注意,由于每一个委托OrderData,可能由于市场流动性情况和多笔市场上的反向委托成交,对应有多笔成交TradeData,因此该函数会返回所有对应成交TraderData。 +   +### 全量查询 + +在全量查询中,唯一参数是use_df,默认为False,返回的是一个包含相应数据的List对象,例如ContractData,AccountData,PositionData。 +* get\_all\_contracts:默认返回一个list,包含了全市场的ContractData,如果use\_df=True则返回相应的DataFrame。 +* get\_all\_active\_orders:首先,active\_order指的是“已提交的、未成交的、部分成交的”订单,已完成的order将不显示;函数将返回list,包含这些OrderData。 +* get\_all\_accounts::默认返回一个list,包含了AccountData,如果use\_df=True则返回相应的DataFrame。 +* get\_all\_position:默认返回一个List,包含了PositionData,如果use\_df=True则返回相应的DataFrame。 +![](https://m.qpic.cn/psb?/V12TMAOq2xN6BZ/Ym0EnCJddVzIZUHBVTAHvhI6mMhUFD0p2.BTAVHMtjs!/b/dFYBAAAAAAAA&bo=vAdKBbwHSgUDCSw!&rf=viewer_4) +### 交易委托 + +* buy:以buy为例,发出一个交易委托,需要的参数有:**本地合约代码、价格、数量、下单类型**。其中,本地合约代码指的是vt_symbol;下单类型默认下限价单,可以自行更改,参考trader/constant下的OrderType枚举类;执行交易委托后会返回vt\_orderid + ``` + #engine.buy(vt_symbol = "rb1910.SHFE",price = "3200",volume = "1",order_type=OrderType.LIMIT) + ``` + - vt_symbol:vnpy本地合约代码 + - price:报单价格,注意是字符串格式 + - volume:报单数量,注意是字符串格式 + - order_type:OrderType枚举常量,默认为限价单(OrderType.LIMIT),同时支持停止单(OrderType.STOP)、FAK(OrderType.FAK)、FOK(OrderType.FOK)、市价单(OrderType.MARKET),不同交易所支持报单方式不完全一致。 +* cancel_order:根据vt_orderid取消某一笔委托。 + ``` + engine.cancel_order(vt_orderid = 'CTP.3_-9351590_1') + ``` +### 信息输出 + +* write_log:可以用于记录买卖时的交易情况,将信息输出在脚本策略窗口下方空白栏里。 +  +* send_email:用于实时通过email通知用户策略运行情况,需要提前在vt\_setting.json下配置email相关信息。其中脚本策略发的邮件标题为“脚本策略引擎通知”,msg:字符串,表示邮件正文内容。 + ``` + engine.send_email(msg = "Your Msg") + ``` + ![](https://m.qpic.cn/psb?/V12TMAOq2xN6BZ/bjXP43yUR36j5dB8YSu3cLpc1xY8jN8envDYxeSS1zA!/b/dL4AAAAAAAAA&bo=JAayASQGsgEDCSw!&rf=viewer_4) + 使用邮箱前需要开通SMTP服务。 + - email.server:邮件服务器地址,vnpy默认填写好了QQ邮箱服务器地址,不用改可以直接用,如果需要使用其他邮箱,需要自行查找一下其他的服务器地址。 + - email.port:邮件服务器端口号,vnpm默认填好了QQ邮箱服务器端口,可直接用。 + - email.username:填写邮箱地址即可,如xxxx@qq.com。 + - email.password:对于QQ邮箱,此处不是邮箱密码,而是开通SMTP后系统生成的一个授权码。 + - email.sendert:email.username。 + - email.receiver:接受邮件的邮箱地址,比如xxxx@outlook.com。 \ No newline at end of file diff --git a/vnpy/app/cta_strategy/engine.py b/vnpy/app/cta_strategy/engine.py index bcaf2e6a..abf1c565 100644 --- a/vnpy/app/cta_strategy/engine.py +++ b/vnpy/app/cta_strategy/engine.py @@ -323,6 +323,11 @@ class CtaEngine(BaseEngine): for req in req_list: vt_orderid = self.main_engine.send_order( req, contract.gateway_name) + + # Check if sending order successful + if not vt_orderid: + continue + vt_orderids.append(vt_orderid) self.offset_converter.update_order_request(req, vt_orderid) diff --git a/vnpy/app/script_trader/engine.py b/vnpy/app/script_trader/engine.py index 8eb754d5..7b730cd6 100644 --- a/vnpy/app/script_trader/engine.py +++ b/vnpy/app/script_trader/engine.py @@ -236,7 +236,7 @@ class ScriptEngine(BaseEngine): """""" return get_data(self.main_engine.get_position, arg=vt_positionid, use_df=use_df) - def get_all_positions(self, use_df: bool = False) -> Sequence[AccountData]: + def get_all_positions(self, use_df: bool = False) -> Sequence[PositionData]: """""" return get_data(self.main_engine.get_all_positions, use_df=use_df) diff --git a/vnpy/gateway/hbdm/hbdm_gateway.py b/vnpy/gateway/hbdm/hbdm_gateway.py index 743ae2a0..5a822659 100644 --- a/vnpy/gateway/hbdm/hbdm_gateway.py +++ b/vnpy/gateway/hbdm/hbdm_gateway.py @@ -9,6 +9,7 @@ import json import zlib import hashlib import hmac +import sys from copy import copy from datetime import datetime from threading import Lock @@ -752,6 +753,19 @@ class HbdmRestApi(RestClient): if not issubclass(exception_type, ConnectionError): self.on_error(exception_type, exception_value, tb, request) + def on_error( + self, exception_type: type, exception_value: Exception, tb, request: Request + ): + """ + Callback to handler request exception. + """ + msg = f"触发异常,状态码:{exception_type},信息:{exception_value}" + self.gateway.write_log(msg) + + sys.stderr.write( + self.exception_detail(exception_type, exception_value, tb, request) + ) + def check_error(self, data: dict, func: str = ""): """""" if data["status"] != "error": diff --git a/vnpy/gateway/huobi/huobi_gateway.py b/vnpy/gateway/huobi/huobi_gateway.py index e57088d5..08c18e05 100644 --- a/vnpy/gateway/huobi/huobi_gateway.py +++ b/vnpy/gateway/huobi/huobi_gateway.py @@ -9,6 +9,7 @@ import json import zlib import hashlib import hmac +import sys from copy import copy from datetime import datetime @@ -440,7 +441,20 @@ class HuobiRestApi(RestClient): self.gateway.write_log(f"委托撤单成功:{order.orderid}") self.order_manager.on_order(order) - + + def on_error( + self, exception_type: type, exception_value: Exception, tb, request: Request + ): + """ + Callback to handler request exception. + """ + msg = f"触发异常,状态码:{exception_type},信息:{exception_value}" + self.gateway.write_log(msg) + + sys.stderr.write( + self.exception_detail(exception_type, exception_value, tb, request) + ) + def check_error(self, data: dict, func: str = ""): """""" if data["status"] != "error": diff --git a/vnpy/gateway/ib/ib_gateway.py b/vnpy/gateway/ib/ib_gateway.py index 930334a5..4b8996cf 100644 --- a/vnpy/gateway/ib/ib_gateway.py +++ b/vnpy/gateway/ib/ib_gateway.py @@ -434,7 +434,16 @@ class IbApi(EWrapper): accountName, ) - if not contract.exchange: + if contract.exchange: + exchange = EXCHANGE_IB2VT.get(contract.exchange, None) + elif contract.primaryExchange: + exchange = EXCHANGE_IB2VT.get(contract.primaryExchange, None) + else: + exchange = Exchange.SMART # Use smart routing for default + + if not exchange: + msg = f"存在不支持的交易所持仓{contract.conId} {contract.exchange} {contract.primaryExchange}" + self.gateway.write_log(msg) return ib_size = contract.multiplier @@ -444,7 +453,7 @@ class IbApi(EWrapper): pos = PositionData( symbol=contract.conId, - exchange=EXCHANGE_IB2VT.get(contract.exchange, contract.exchange), + exchange=exchange, direction=Direction.NET, volume=position, price=price, diff --git a/vnpy/gateway/okexf/okexf_gateway.py b/vnpy/gateway/okexf/okexf_gateway.py index 7a3eca7d..28138c41 100644 --- a/vnpy/gateway/okexf/okexf_gateway.py +++ b/vnpy/gateway/okexf/okexf_gateway.py @@ -387,28 +387,28 @@ class OkexfRestApi(RestClient): return for pos_data in data["holding"][0]: - if float(pos_data["long_qty"]) > 0: + if int(pos_data["long_qty"]) > 0: pos = PositionData( symbol=pos_data["instrument_id"].upper(), exchange=Exchange.OKEX, direction=Direction.LONG, - volume=pos_data["long_qty"], + volume=int(pos_data["long_qty"]), frozen=float(pos_data["long_qty"]) - float(pos_data["long_avail_qty"]), - price=pos_data["long_avg_cost"], - pnl=pos_data["realised_pnl"], + price=float(pos_data["long_avg_cost"]), + pnl=float(pos_data["realised_pnl"]), gateway_name=self.gateway_name, ) self.gateway.on_position(pos) - if float(pos_data["short_qty"]) > 0: + if int(pos_data["short_qty"]) > 0: pos = PositionData( symbol=pos_data["instrument_id"], exchange=Exchange.OKEX, direction=Direction.SHORT, - volume=pos_data["short_qty"], + volume=int(pos_data["short_qty"]), frozen=float(pos_data["short_qty"]) - float(pos_data["short_avail_qty"]), - price=pos_data["short_avg_cost"], - pnl=pos_data["realised_pnl"], + price=float(["short_avg_cost"]), + pnl=float(["realised_pnl"]), gateway_name=self.gateway_name, ) self.gateway.on_position(pos) diff --git a/vnpy/gateway/rpc/rpc_gateway.py b/vnpy/gateway/rpc/rpc_gateway.py index c9ad39a8..a1807adb 100644 --- a/vnpy/gateway/rpc/rpc_gateway.py +++ b/vnpy/gateway/rpc/rpc_gateway.py @@ -50,7 +50,7 @@ class RpcGateway(BaseGateway): def send_order(self, req: OrderRequest): """""" gateway_name = self.symbol_gateway_map.get(req.vt_symbol, "") - self.client.send_order(req, gateway_name) + return self.client.send_order(req, gateway_name) def cancel_order(self, req: CancelRequest): """"""