Merge pull request #1975 from vnpy/dev

Dev
This commit is contained in:
vn.py 2019-07-30 10:24:12 +08:00 committed by GitHub
commit 9608ec0f41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1209 additions and 22 deletions

View File

@ -14,9 +14,13 @@
vn.py是一套基于Python的开源量化交易系统开发框架于2015年1月正式发布在开源社区5年持续不断的贡献下一步步成长为全功能量化交易平台目前国内外金融机构用户已经超过300家包括私募基金、证券自营和资管、期货资管和子公司、高校研究机构、自营交易公司、交易所、Token Fund等。 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的使用教程欢迎关注。 <p align="center">
<img src ="https://vnpy.oss-cn-shanghai.aliyuncs.com/vnpy_qr.jpg"/>
</p>
在使用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)。 2.0版本基于Python 3.7全新重构开发如需Python 2上的版本请点击[长期支持版本v1.9.2 LTS](https://github.com/vnpy/vnpy/tree/v1.9.2-LTS)。

View File

@ -74,6 +74,7 @@ def main():
| 接口 | 类型 | | 接口 | 类型 |
| -------- | :----------------------------------------: | | -------- | :----------------------------------------: |
| CTP | 期货 | | CTP | 期货 |
| MINI | 期货 |
| FEMAS | 期货 | | FEMAS | 期货 |
| XTP | 国内股票、指数、基金、债券、期权、融资融券 | | XTP | 国内股票、指数、基金、债券、期权、融资融券 |
| OES | 国内股票 | | OES | 国内股票 |
@ -85,12 +86,13 @@ def main():
| ALPACA | 美股 | | ALPACA | 美股 |
| BITFINEX | 数字货币 | | BITFINEX | 数字货币 |
| BITMEX | 数字货币 | | BITMEX | 数字货币 |
| BINANCE | 数字货币 |
| OKEX | 数字货币 | | OKEX | 数字货币 |
| OKEXF | 数字货币 | | OKEXF | 数字货币 |
| HUOBI | 数字货币 | | HUOBI | 数字货币 |
| HBDM | 数字货币 | | HBDM | 数字货币 |
| ONETOKEN | 数字货币 | | ONETOKEN | 数字货币 |
| RPC | RPC服务 | | RPC | RPC服务 |
@ -130,6 +132,37 @@ main_engine.add_gateway(CtpGateway)
- 实盘账号在期货公司开户通过联系客户经理可以开通。用户名为纯数字经纪商编号也是4位纯数字。每个期货公司的经纪商编号都不同另外实盘账号也可以开通仿真交易功能同样需要联系客户经理。 - 实盘账号在期货公司开户通过联系客户经理可以开通。用户名为纯数字经纪商编号也是4位纯数字。每个期货公司的经纪商编号都不同另外实盘账号也可以开通仿真交易功能同样需要联系客户经理。
&nbsp;
### MINI
#### 如何加载
先从gateway上调用MiniGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.mini import MiniGateway
main_engine.add_gateway(MiniGateway)
```
&nbsp;
#### 相关字段
- 用户名username
- 密码password
- 经纪商编号brokerid
- 交易服务器地址td_address
- 行情服务器地址md_address
- 产品名称product_info
- 授权编码auth_code
&nbsp;
#### 获取账号
在期货公司开户通过联系客户经理可以开通。用户名为纯数字经纪商编号也是4位纯数字。每个期货公司的经纪商编号都不同另外实盘账号也可以开通仿真交易功能同样需要联系客户经理。
&nbsp; &nbsp;
### 飞马FEMAS ### 飞马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)
```
&nbsp;
#### 相关字段 #### 相关字段
- 账号: username
- 密码: password
- 交易服务器: td_address
- 行情服务器: md_address
&nbsp;
#### 获取账号 #### 获取账号
#### 其他特点 测试账号请联系华鑫证券申请
&nbsp; &nbsp;
@ -400,11 +449,21 @@ main_engine.add_gateway(TigerGateway)
### ALPACA ### ALPACA
#### 如何加载 #### 如何加载
先从gateway上调用AlpacaGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.alpaca import AlpacaGateway
main_engine.add_gateway(AlpacaGateway)
```
&nbsp;
#### 相关字段 #### 相关字段
- KEY ID: key
- Secret Key: secret
- 会话数: 10
- 服务器:["REAL", "PAPER"]
#### 获取账号 #### 获取账号
在OKEX官网开户并且入金后可以获得API接入权限。
#### 其他特点 #### 其他特点
&nbsp; &nbsp;
@ -655,6 +714,38 @@ main_engine.add_gateway(OnetokenGateway)
&nbsp;
&nbsp;
### BINANCE
#### 如何加载
先从gateway上调用BinanceGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.binance import BinanceGateway
main_engine.add_gateway(BinanceGateway)
```
&nbsp;
#### 相关字段
- Key秘钥
- secret
- session_number(会话数)3
- proxy_host
- proxy_port
&nbsp;
#### 获取账号
在BINANCE官网开户并且入金后可以获得API接入权限。
&nbsp; &nbsp;
@ -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)
&nbsp;
### 加载需要用的接口
加载接口示例在根目录"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()
```
&nbsp;
### 配置和连接
打开cmd窗口使用命令“Python run.py"即可进入VN Trader操作界面。在左上方的菜单栏中点击"系统"->"连接CTP”按钮会弹出账号配置窗口输入账号、密码等相关信息即连接接口。
连接接口的流程首先是初始化账户信息然后调用connet()函数来连接交易端口和行情端口。
- 交易端口:查询用户相关信息(如账户资金、持仓、委托记录、成交记录)、查询可交易合约信息、挂撤单操作;
- 行情端口:接收订阅的行情信息推送、接收用户相关信息(如账户资金更新、持仓更新、委托推送、成交推送)更新的回调推送。
&nbsp;
### 修改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文件。
&nbsp;
### 查看可交易的合约
先登录接口,然后在菜单栏中点击"帮助"->"查询合约”按钮会空白的“查询合约”窗口。点击“查询”按钮后才会显示查询结果,如图。
![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/gateway/query_contract.png)
&nbsp;
## 接口分类
| 接口 | 类型 |
| -------- | :----------------------------------------: |
| CTP | 期货 |
| MINI | 期货 |
| FEMAS | 期货 |
| XTP | 国内股票、指数、基金、债券、期权、融资融券 |
| OES | 国内股票 |
| TORA | 国内股票 |
| IB | 外盘股票、期货、期权 |
| TAP | 外盘期货、期权 |
| FUTU | 国内股票、港股、美股 |
| TIGER | 国内股票、港股、美股 |
| ALPACA | 美股 |
| BITFINEX | 数字货币 |
| BITMEX | 数字货币 |
| BINANCE | 数字货币 |
| OKEX | 数字货币 |
| OKEXF | 数字货币 |
| HUOBI | 数字货币 |
| HBDM | 数字货币 |
| ONETOKEN | 数字货币 |
| RPC | RPC服务 |
&nbsp;
## 接口详解
### CTP
#### 如何加载
run.py文件提供了接口加载示例先从gateway上调用ctpGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.ctp import CtpGateway
main_engine.add_gateway(CtpGateway)
```
&nbsp;
#### 相关字段
- 用户名username
- 密码password
- 经纪商编号brokerid
- 交易服务器地址td_address
- 行情服务器地址md_address
- 产品名称product_info
- 授权编码auth_code
&nbsp;
#### 获取账号 #### 获取账号
- 仿真账号从SimNow网站上获取。只需输入手机号码和短信验证即可。短信验证有时只能在工作日正常工作时段收到SimNow的用户名为6位纯数字经纪商编号为9999并且提供2套环境用于盘中仿真交易以及盘后的测试。
- 实盘账号在期货公司开户通过联系客户经理可以开通。用户名为纯数字经纪商编号也是4位纯数字。每个期货公司的经纪商编号都不同另外实盘账号也可以开通仿真交易功能同样需要联系客户经理。
&nbsp;
### MINI
#### 如何加载
先从gateway上调用MiniGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.mini import MiniGateway
main_engine.add_gateway(MiniGateway)
```
&nbsp;
#### 相关字段
- 用户名username
- 密码password
- 经纪商编号brokerid
- 交易服务器地址td_address
- 行情服务器地址md_address
- 产品名称product_info
- 授权编码auth_code
&nbsp;
#### 获取账号
在期货公司开户通过联系客户经理可以开通。用户名为纯数字经纪商编号也是4位纯数字。每个期货公司的经纪商编号都不同另外实盘账号也可以开通仿真交易功能同样需要联系客户经理。
&nbsp;
### 飞马FEMAS
#### 如何加载
先从gateway上调用FemasGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.femas import FemasGateway
main_engine.add_gateway(FemasGateway)
```
&nbsp;
#### 相关字段
- 用户名username
- 密码password
- 经纪商编号brokerid
- 交易服务器地址td_address
- 行情服务器地址md_address
- 产品名称product_info
- 授权编码auth_code
&nbsp;
#### 获取账号
在期货公司开户通过联系客户经理可以开通。用户名为纯数字经纪商编号也是4位纯数字。每个期货公司的经纪商编号都不同另外实盘账号也可以开通仿真交易功能同样需要联系客户经理。
&nbsp;
### 中泰柜台(XTP)
#### 如何加载
先从gateway上调用XtpGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.xtp import XtpGateway
main_engine.add_gateway(XtpGateway)
```
&nbsp;
#### 相关字段
- 账号:
- 密码:
- 客户号": 1
- 行情地址:
- 行情端口": 0
- 交易地址:
- 交易端口": 0
- 行情协议: ["TCP", "UDP"]
- 授权码:
&nbsp;
#### 获取账号
测试账号请联系中泰证券申请。
#### 其他特点 #### 其他特点
&nbsp; XTP是首家提供融资融券的极速柜台。
&nbsp;
### 宽睿柜台(OES)
#### 如何加载
先从gateway上调用OesGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.oes import OesGateway
main_engine.add_gateway(OesGateway)
```
&nbsp;
#### 相关字段
- 用户名username
- 密码password
- 硬盘序列号hdd_serial
- 交易委托服务器td_ord_server
- 交易回报服务器td_rpt_server
- 交易查询服务器td_qry_server
- 行情推送服务器md_tcp_server
- 行情查询服务器md_qry_server
&nbsp;
#### 获取账号
测试账号请联系宽睿科技申请
&nbsp;
#### 其他特点
宽睿柜台提供内网UDP低延时组播行情以及实时成交信息推送。
&nbsp;
### 华鑫奇点(TORA)
#### 如何加载
先从gateway上调用ToraGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.tota import ToraGateway
main_engine.add_gateway(OesGateway)
```
&nbsp;
#### 相关字段
- 账号: username
- 密码: password
- 交易服务器: td_address
- 行情服务器: md_address
&nbsp;
#### 获取账号
测试账号请联系华鑫证券申请
&nbsp;
### 盈透证券(IB)
#### 如何加载
先从gateway上调用IbGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.ib import IbGateway
main_engine.add_gateway(IbGateway)
```
&nbsp;
#### 相关字段
- TWS地址127.0.0.1
- TWS端口7497
- 客户号1
&nbsp;
#### 获取账号
在盈透证券开户并且入金后可以获得API接入权限。拥有实盘账号后才可以申请开通仿真交易账号。
&nbsp;
#### 其他特点
可交易品种几乎覆盖全球的股票、期权、期权;手续费相对较低。
注意IB接口的合约代码较为特殊请前往官网的产品查询板块查询VN Trader中使用的是盈透证券对于每个合约在某一交易所的唯一标识符ConId来作为合约代码而非Symbol或者LocalName。
&nbsp;
### 易盛外盘(TAP)
#### 如何加载
先从gateway上调用TapGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.tap import TapGateway
main_engine.add_gateway(TapGateway)
```
&nbsp;
#### 相关字段
- 授权码auth code
- 行情账号quote username
- 行情密码quote password
- 行情地址123.15.58.21
- 行情端口7171
&nbsp;
#### 获取账号
在TAP开户并且入金后可以获得API接入权限。
&nbsp;
### 富途证券(FUTU)
#### 如何加载
先从gateway上调用FutuGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.futu import FutuGateway
main_engine.add_gateway(FutuGateway)
```
&nbsp;
#### 相关字段
- 地址127.0.0.1
- 密码:
- 端口11111
- 市场HK 或 US
- 环境TrdEnv.REAL 或 TrdEnv.SIMULATE
&nbsp;
#### 获取账号
在富途证券开户并且入金后可以获得API接入权限。拥有实盘账号后才可以申请开通仿真交易账号。
&nbsp;
### 老虎证券(TIGER)
#### 如何加载
先从gateway上调用TigerGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.tiger import TigerGateway
main_engine.add_gateway(TigerGateway)
```
&nbsp;
#### 相关字段
- 用户IDtiger_id
- 环球账户account
- 标准账户standard_account
- 秘钥private_key
&nbsp;
#### 获取账号
在老虎证券开户并且入金后可以获得API接入权限。拥有实盘账号后才可以申请开通仿真交易账号。
&nbsp;
### ALPACA
#### 如何加载
先从gateway上调用AlpacaGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.alpaca import AlpacaGateway
main_engine.add_gateway(AlpacaGateway)
```
&nbsp;
#### 相关字段
- KEY ID: key
- Secret Key: secret
- 会话数: 10
- 服务器:["REAL", "PAPER"]
#### 获取账号
在OKEX官网开户并且入金后可以获得API接入权限。
#### 其他特点
&nbsp;
### BITMEX
#### 如何加载
先从gateway上调用BitmexGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.bitmex import BitmexGateway
main_engine.add_gateway(BitmexGateway)
```
&nbsp;
#### 相关字段
- 用户IDID
- 密码Secret
- 会话数3
- 服务器REAL 或 TESTNET
- 代理地址:
- 代理端口:
&nbsp;
#### 获取账号
在BITMEX官网开户并且入金后可以获得API接入权限。
&nbsp;
### OKEX现货OKEX
#### 如何加载
先从gateway上调用OkexGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.okex import OkexGateway
main_engine.add_gateway(OkexGateway)
```
&nbsp;
#### 相关字段
- API秘钥API Key
- 密码秘钥Secret Key
- 会话数3
- 密码passphrase
- 代理地址:
- 代理端口:
&nbsp;
#### 获取账号
在OKEX官网开户并且入金后可以获得API接入权限。
&nbsp;
### OKEX期货OKEXF
#### 如何加载
先从gateway上调用OkexfGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.okexf import OkexfGateway
main_engine.add_gateway(OkexfGateway)
```
&nbsp;
#### 相关字段
- API秘钥API Key
- 密码秘钥Secret Key
- 会话数3
- 密码passphrase
- 杠杆Leverage
- 代理地址:
- 代理端口:
&nbsp;
#### 获取账号
在OKEX官网开户并且入金后可以获得API接入权限。
&nbsp;
### 火币(HUOBI)
#### 如何加载
先从gateway上调用HuobiGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.huobi import HuobiGateway
main_engine.add_gateway(HuobiGateway)
```
&nbsp;
#### 相关字段
- API秘钥API Key
- 密码秘钥Secret Key
- 会话数3
- 代理地址:
- 代理端口:
&nbsp;
#### 获取账号
在火币官网开户并且入金后可以获得API接入权限。
&nbsp;
### 火币合约(HBDM)
#### 如何加载
先从gateway上调用HbdmGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.hbdm import HbdmGateway
main_engine.add_gateway(HbdmGateway)
```
&nbsp;
#### 相关字段
- API秘钥API Key
- 密码秘钥Secret Key
- 会话数3
- 代理地址:
- 代理端口:
&nbsp;
#### 获取账号
在火币官网开户并且入金后可以获得API接入权限。
&nbsp;
### BITFINEX
#### 如何加载
先从gateway上调用BitFinexGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.bitfinex import BitfinexGateway
main_engine.add_gateway(BitfinexGateway)
```
&nbsp;
#### 相关字段
- 用户IDID
- 密码Secret
- 会话数3
- 代理地址:
- 代理端口:
&nbsp;
#### 获取账号
在BITFINEX官网开户并且入金后可以获得API接入权限。
&nbsp;
### ONETOKEN
#### 如何加载
先从gateway上调用OnetokenGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.onetoken import OnetokenGateway
main_engine.add_gateway(OnetokenGateway)
```
&nbsp;
#### 相关字段
- Key秘钥OT Key
- 密码秘钥OT Secret
- 会话数3
- 交易所:["BINANCE", "BITMEX", "OKEX", "OKEF", "HUOBIP", "HUOBIF"]
- 账号:
- 代理地址:
- 代理端口:
&nbsp;
#### 获取账号
在Onetoken官网开户并且入金后可以获得API接入权限。
&nbsp;
&nbsp;
### BINANCE
#### 如何加载
先从gateway上调用BinanceGateway类然后通过add_gateway()函数添加到main_engine上。
```
from vnpy.gateway.binance import BinanceGateway
main_engine.add_gateway(BinanceGateway)
```
&nbsp;
#### 相关字段
- Key秘钥
- secret
- session_number(会话数)3
- proxy_host
- proxy_port
&nbsp;
#### 获取账号
在BINANCE官网开户并且入金后可以获得API接入权限。
&nbsp;
### 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后客户端多个进程会自动订阅来自服务端分发的订阅数据

View File

@ -1 +1,33 @@
# RPC服务 # RPC服务
由于全局锁GIL的存在单进程的Python程序只能利用CPU单核的算力为了突破这一限制解决方案就是多进程分布式的程序架构。但每个进程之间的数据在操作系统内默认是独立隔离的无法直接访问。RPC全称Remote-Procedure-Call中文“远程过程调用”是最常用的跨进程通讯方式之一。
## RPC服务器
### 加载模块
### 启动运行
## RPC客户端
### 加载接口
### 连接使用
## 参考样例
位于examples/server_client目录下
### 服务器进程
GUI模式
无界面模式
### 客户端进程

View File

@ -1 +1,234 @@
# 脚本策略 # 脚本策略
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.18710101",
"行情服务器":"tcp://180.168.146.18710111",
"产品名称":"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连接上交易接口后还需要订阅特定的合约才能收到交易所推送过来的数据。以订阅螺纹钢19091910为例
```
engine.subscribe(vt_symbols = ["rb1909.SHFE","rb1910.SHFE"])
```
- vt_symbols需要填写的参数形式是列表内部包含vt_symbol。
&nbsp;
## 脚本策略模式
### 加载启动
如在脚本策略模式下使用需要提前编写相关脚本策略文件假设为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循环内部进行。
&nbsp;
## 函数功能说明
### 单条查询
* **在单条查询函数中都有use_df参数用来控制是否将函数返回的类对象转化成DataFrame仅在get_tick中做一次详细说明其余函数同理。**
&nbsp;
* get\_tick查询单个标的最新tick。
```
tick = engine.get_tick(vt_symbol="rb1910.SHFE",use_df=False)
```
- vt_symbol字符串参数表示本地合约代码。
- use_dfbool变量默认False返回TickData类对象否则返回相应DataFrame。
![](https://m.qpic.cn/psb?/V12TMAOq2xN6BZ/o38RYahmAsmLqPDz2cUixiDU19TGFqMH0e8WBg3wgHU!/b/dL4AAAAAAAAA&bo=iQaAAuIHBAMDCcM!&rf=viewer_4)
DataFrame的列是TickData类属性行是TickData个数由于单条查询则只有一行。
&nbsp;
* 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)
&nbsp;
* 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)
&nbsp;
* 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}"
```
&nbsp;
* get\_position根据vt_positionid来查询持仓情况包括接口名称、交易所、合约代码、数量、冻结数量等。
```
position = engine.get_position(vt_positionid='rb1909.SHFE.Direction.LONG')
```
- vt_positionidvnpy内部对于一笔特定持仓的唯一持仓编号格式为"vt_symbol.Direction.LONG",其中方向可选择为```DIRECTION.SHORT```或```DIRECTION.NET```
![](https://m.qpic.cn/psb?/V12TMAOq2xN6BZ/szBIwwFgVmdXsBGYAWpkpZoA9m5ER0hmu*xya9c7u.Y!/b/dLYAAAAAAAAA&bo=3geuAN4HrgARCT4!&rf=viewer_4)
&nbsp;
### 多条查询
* **在多条查询函数中use_df参数都可以用来控制是否将函数返回的类对象转化成DataFrame仅在get_ticks中做一次详细说明其余函数同理。**
&nbsp;
* get\_ticks查询多个合约最新tick。
```
ticks = engine.get_ticks(vt_symbols=['rb1910.SHFE','rb1909.SHFE'],use_df = True)
```
- use\_dfFalse则返回一个列表元素为TickDataTrue则返回DataFrame列是TickData的属性每一行代表一个TickData。
- vt_symbols一个列表元素为合约字符串vt_symbol。
![](https://m.qpic.cn/psb?/V12TMAOq2xN6BZ/ghZR0VV5APiKLh5Zx73x7qgz1IwJ3zrG4MKVNen8PXc!/b/dL8AAAAAAAAA&bo=kAWAAvYHlAMDCV0!&rf=viewer_4)
&nbsp;
* 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构成。
&nbsp;
* get\_trades根据给定的一个vt_orderid返回这次报单过程中的所有TradeData对象。
```
trades = engine.get_trades(vt_orderid = your_vt_orderid,use_df = True)
```
- vt_orderidvnpy本地订单id注意由于每一个委托OrderData可能由于市场流动性情况和多笔市场上的反向委托成交对应有多笔成交TradeData因此该函数会返回所有对应成交TraderData。
&nbsp;
### 全量查询
在全量查询中唯一参数是use_df默认为False返回的是一个包含相应数据的List对象,例如ContractDataAccountDataPositionData。
* 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_symbolvnpy本地合约代码
- price报单价格注意是字符串格式
- volume报单数量注意是字符串格式
- order_typeOrderType枚举常量默认为限价单(OrderType.LIMIT)同时支持停止单OrderType.STOP、FAKOrderType.FAK、FOKOrderType.FOK、市价单OrderType.MARKET不同交易所支持报单方式不完全一致。
* cancel_order根据vt_orderid取消某一笔委托。
```
engine.cancel_order(vt_orderid = 'CTP.3_-9351590_1')
```
### 信息输出
* write_log可以用于记录买卖时的交易情况将信息输出在脚本策略窗口下方空白栏里。
&nbsp;
* 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.sendertemail.username。
- email.receiver接受邮件的邮箱地址比如xxxx@outlook.com。

View File

@ -323,6 +323,11 @@ class CtaEngine(BaseEngine):
for req in req_list: for req in req_list:
vt_orderid = self.main_engine.send_order( vt_orderid = self.main_engine.send_order(
req, contract.gateway_name) req, contract.gateway_name)
# Check if sending order successful
if not vt_orderid:
continue
vt_orderids.append(vt_orderid) vt_orderids.append(vt_orderid)
self.offset_converter.update_order_request(req, vt_orderid) self.offset_converter.update_order_request(req, vt_orderid)

View File

@ -236,7 +236,7 @@ class ScriptEngine(BaseEngine):
"""""" """"""
return get_data(self.main_engine.get_position, arg=vt_positionid, use_df=use_df) 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) return get_data(self.main_engine.get_all_positions, use_df=use_df)

View File

@ -9,6 +9,7 @@ import json
import zlib import zlib
import hashlib import hashlib
import hmac import hmac
import sys
from copy import copy from copy import copy
from datetime import datetime from datetime import datetime
from threading import Lock from threading import Lock
@ -752,6 +753,19 @@ class HbdmRestApi(RestClient):
if not issubclass(exception_type, ConnectionError): if not issubclass(exception_type, ConnectionError):
self.on_error(exception_type, exception_value, tb, request) 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 = ""): def check_error(self, data: dict, func: str = ""):
"""""" """"""
if data["status"] != "error": if data["status"] != "error":

View File

@ -9,6 +9,7 @@ import json
import zlib import zlib
import hashlib import hashlib
import hmac import hmac
import sys
from copy import copy from copy import copy
from datetime import datetime from datetime import datetime
@ -440,7 +441,20 @@ class HuobiRestApi(RestClient):
self.gateway.write_log(f"委托撤单成功:{order.orderid}") self.gateway.write_log(f"委托撤单成功:{order.orderid}")
self.order_manager.on_order(order) 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 = ""): def check_error(self, data: dict, func: str = ""):
"""""" """"""
if data["status"] != "error": if data["status"] != "error":

View File

@ -434,7 +434,16 @@ class IbApi(EWrapper):
accountName, 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 return
ib_size = contract.multiplier ib_size = contract.multiplier
@ -444,7 +453,7 @@ class IbApi(EWrapper):
pos = PositionData( pos = PositionData(
symbol=contract.conId, symbol=contract.conId,
exchange=EXCHANGE_IB2VT.get(contract.exchange, contract.exchange), exchange=exchange,
direction=Direction.NET, direction=Direction.NET,
volume=position, volume=position,
price=price, price=price,

View File

@ -387,28 +387,28 @@ class OkexfRestApi(RestClient):
return return
for pos_data in data["holding"][0]: for pos_data in data["holding"][0]:
if float(pos_data["long_qty"]) > 0: if int(pos_data["long_qty"]) > 0:
pos = PositionData( pos = PositionData(
symbol=pos_data["instrument_id"].upper(), symbol=pos_data["instrument_id"].upper(),
exchange=Exchange.OKEX, exchange=Exchange.OKEX,
direction=Direction.LONG, 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"]), frozen=float(pos_data["long_qty"]) - float(pos_data["long_avail_qty"]),
price=pos_data["long_avg_cost"], price=float(pos_data["long_avg_cost"]),
pnl=pos_data["realised_pnl"], pnl=float(pos_data["realised_pnl"]),
gateway_name=self.gateway_name, gateway_name=self.gateway_name,
) )
self.gateway.on_position(pos) self.gateway.on_position(pos)
if float(pos_data["short_qty"]) > 0: if int(pos_data["short_qty"]) > 0:
pos = PositionData( pos = PositionData(
symbol=pos_data["instrument_id"], symbol=pos_data["instrument_id"],
exchange=Exchange.OKEX, exchange=Exchange.OKEX,
direction=Direction.SHORT, 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"]), frozen=float(pos_data["short_qty"]) - float(pos_data["short_avail_qty"]),
price=pos_data["short_avg_cost"], price=float(["short_avg_cost"]),
pnl=pos_data["realised_pnl"], pnl=float(["realised_pnl"]),
gateway_name=self.gateway_name, gateway_name=self.gateway_name,
) )
self.gateway.on_position(pos) self.gateway.on_position(pos)

View File

@ -50,7 +50,7 @@ class RpcGateway(BaseGateway):
def send_order(self, req: OrderRequest): def send_order(self, req: OrderRequest):
"""""" """"""
gateway_name = self.symbol_gateway_map.get(req.vt_symbol, "") 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): def cancel_order(self, req: CancelRequest):
"""""" """"""