Merge pull request #1991 from 1122455801/scripe_trading.md_0803

[Update] script_trader.md
This commit is contained in:
vn.py 2019-08-03 11:46:01 +08:00 committed by GitHub
commit cf9ae5c84f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,26 +1,31 @@
# 脚本策略 # 脚本策略
ScriptTrader模块提供了交互式的量化分析和程序化交易功能又提供以整个策略连续运行的脚本策略功能。
ScriptTrader模块的作用既提供交互式的量化分析和程序化交易功能又能提供以整个策略连续运行的脚本策略功能。 故其可视为直接利用Python对证券交易客户端进行操作。它与CTA策略模块的区别在于
ScriptTrader可视为直接利用python对证券交易客户端进行操作它与CTA策略模块较为明显的区别在于突破了单交易所单标的的限制可以较方便的实现如股指期货和一篮子股票之间的对冲策略、跨品种套利、股票市场扫描自动化选股等功能。 - 突破了单交易所,单标的的限制,
- 可以较方便的实现如股指期货和一篮子股票之间的对冲策略、跨品种套利、股票市场扫描自动化选股等功能。
 
## Jupyter模式 ## Jupyter模式
### 加载启动 ### 加载启动
Jupyter模式下一切都以 **ScriptEngine** 为核心 Jupyter模式是基于脚本引擎(ScriptEngine)驱动的。首先打开Jupyter notebook后然后加载组件、初始化脚本引擎。其中
成功启动jupyter notebook后进行如下操作来加载组件、初始化脚本引擎
``` ```
from vnpy.app.script_trader import init_cli_trading from vnpy.app.script_trader import init_cli_trading
from vnpy.gateway.ctp import CtpGateway from vnpy.gateway.ctp import CtpGateway
engine = init_cli_trading([CtpGateway]) engine = init_cli_trading([CtpGateway])
``` ```
**注**
- ScriptEngine支持同时连接多个接口因此除了上述CTP接口还可以自行添加其他交易接口。 其中:
- 在```init_cli_trading(gateways: Sequence[BaseGateway])```中将多个需要连接的接口类用列表的形式传递给init_cli_trading。 - 脚本引擎可以支持同时连接多个接口如CTP、BITMEX、OES等
- init_cli_trading可视为vnpy封好的初始化启动函数函数内部将主引擎、脚本引擎等各种对象已经组装完毕仅返回ScriptEngine供用户直接使用。 - init_cli_trading(gateways: Sequence[BaseGateway])可以将多个接口类以列表的形式传递给init_cli_trading
- init_cli_trading可视为vnpy封好的初始化启动函数对主引擎、脚本引擎等各种对象进行了封装。
 
### 连接接口 ### 连接接口
不同接口需要不同的配置参数以ctp为例连入simnow模拟交易。 不同接口需要不同的配置参数,SimNow的配置如下
``` ```
setting = { setting = {
"用户名": "xxxx", "用户名": "xxxx",
@ -34,30 +39,45 @@ setting = {
} }
engine.connect_gateway(setting,"CTP") engine.connect_gateway(setting,"CTP")
``` ```
setting配置如下图所示其他接口配置可以参考vnpy/gateway目录下的接口类的default_setting来填写。
![](https://static.vnpy.com/upload/temp/82dd7cfd-6a98-4908-a770-582cfb7e69bc.jpg) ![](https://static.vnpy.com/upload/temp/82dd7cfd-6a98-4908-a770-582cfb7e69bc.jpg)
**注**
- 如果对setting的填写有疑问可以按照vnpy/gateway目录下的接口类的default_setting来填写。
 
### 查询数据 ### 查询数据
这里介绍一下连接上交易接口并成功订阅数据后的数据存储:
- 底层接口不停向主引擎推送新的数据;
- 主引擎里维护着一个ticks字典用于缓存不同标的的最新tick数据仅能缓存最新的
- use_df的作用是转换成DataFrame格式便于数据分析。
这里介绍一下连接上交易接口并成功订阅数据后的数据存储。底层接口不停向主引擎推送新的数据在主引擎里维护着一个ticks字典用于缓存不同标的的最新tick数据仅能缓存最新的  
use_df可选参数的作用返回pandas.DataFrame在Jupyter中分析更方便
### 订阅行情
subscribe()函数用于订阅行情信息,若需要订阅一篮子合约的行情,可以使用列表格式。
```
engine.subscribe(vt_symbols = ["rb1909.SHFE","rb1910.SHFE"])
```
 
### 发出指令
- subscribe连接上交易接口后还需要订阅特定的合约才能收到交易所推送过来的数据。以订阅螺纹钢19091910为例
```
engine.subscribe(vt_symbols = ["rb1909.SHFE","rb1910.SHFE"])
```
- vt_symbols需要填写的参数形式是列表内部包含vt_symbol。
 
## 脚本策略模式 ## 脚本策略模式
### 加载启动 ### 加载启动
- 若使用脚本策略模式需要提前编写相关脚本策略文件如demo_arbitrage.py,
如在脚本策略模式下使用需要提前编写相关脚本策略文件假设为demo_arbitrage.py,然后打开vntrader,在菜单栏"功能"处打开"脚本策略",在跳出的脚本策略窗口最上方打开/Path-To-demo_arbitrage.py/demo_arbitrage.py然后直接启动即可。 - 然后打开VnTrader,在菜单栏"功能"处打开"脚本策略",在跳出的脚本策略窗口最上方打开/Path-To-demo_arbitrage.py/demo_arbitrage.py然后
- 点击如下图的“启动”。
![](https://static.vnpy.com/upload/temp/bf6b06f8-26e9-466b-b3e0-5b3a6f99e6ba.jpg) ![](https://static.vnpy.com/upload/temp/bf6b06f8-26e9-466b-b3e0-5b3a6f99e6ba.jpg)
 
### 脚本策略 ### 脚本策略
脚本策略文件编写需要遵循一定格式,下面展示一个基础的模板 脚本策略文件编写需要遵循一定格式,下面提供使用模板,其作用为:
- 订阅两个品种的行情;
- 打印合约信息;
- 每隔3秒获取最新行情。
``` ```
from time import sleep from time import sleep
from vnpy.app.script_trader import ScriptEngine from vnpy.app.script_trader import ScriptEngine
@ -86,156 +106,175 @@ def run(engine: ScriptEngine):
# 等待3秒进入下一轮 # 等待3秒进入下一轮
sleep(3) sleep(3)
``` ```
该脚本策略的功能为订阅两个品种的行情打印合约信息每隔3秒获取最新行情。
### 运行控制
while循环的退出控制变量engine.strategy_active  
- engine.strategy_active是脚本策略的开关当点击“启动”时该控制变量变为True程序将一直在while循环内部不断运行当点击“停止”时该控制变量变为False程序将运行完当前while循环后完全退出
- 脚本策略在编写时最重要的一点是主体部分要在while循环内部进行。 ### 运行控制
engine.strategy_active用于控制While循环可视作是脚本策略的开关
- 点击“启动”按钮启动While循环执行脚本策略
- 点击“停止”按钮退出While循环停止脚本策略。
   
## 函数功能说明 ## 函数功能说明
### 单条查询 ### 单条查询
* **在单条查询函数中都有use_df参数用来控制是否将函数返回的类对象转化成DataFrame仅在get_tick中做一次详细说明其余函数同理。**
get_tick查询单个标的最新tickuse_df为可选参数用于把返回的类对象转化成DataFrame格式便于数据分析。
```
tick = engine.get_tick(vt_symbol="rb1910.SHFE",use_df=False)
```
其中:
- vt_symbol为本地合约代码格式是合约品种+交易所如rb1910.SHFE。
- use_df为bool变量默认False返回TickData类对象否则返回相应DataFrame如图。
![](https://static.vnpy.com/upload/temp/d00ca165-1266-4812-afaa-f6723745d6a4.png)
   
* get_tick查询单个标的最新tick。 get_order根据vt_orderid查询委托单的详细信息。
``` ```
tick = engine.get_tick(vt_symbol="rb1910.SHFE",use_df=False) order = engine.get_order(vt_orderid='CTP.3_-9351590_1',use_df=False)
``` ```
- vt_symbol字符串参数表示本地合约代码。
- use_dfbool变量默认False返回TickData类对象否则返回相应DataFrame。
![](https://static.vnpy.com/upload/temp/d00ca165-1266-4812-afaa-f6723745d6a4.png) 其中vt_orderid为本地委托号在委托下单时会自动返回该委托的vt_orderid
DataFrame的列是TickData类属性行是TickData个数由于单条查询则只有一行。 - 以"CTP.3_-9351590_1"为例它由ctp接口的name,frontid,sessionid,order_ref构成
  - frontid和sessionid在vnpy连接上CTP接口后由CTP回调产生
- order_ref是vnpy内部维护的用于区分order的一个变量。
* get_order根据vt_orderid查询委托单的详细信息。 ![](https://static.vnpy.com/upload/temp/ae9f6d7f-49da-41e4-a862-825bf146118d.png)
```
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://static.vnpy.com/upload/temp/ae9f6d7f-49da-41e4-a862-825bf146118d.png)
 
* get_contract根据本地vt_symbol来查询对应合约对象的详细信息。
```
contract = engine.get_contract(vt_symbol="rb1910.SHFE",use_df=False)
```
- vt_symbol字符串参数表示本地合约代码。
![](https://static.vnpy.com/upload/temp/4111776b-91fd-44e6-8b2c-289961862a3a.jpg)
   
* get_bars查询历史数据要求提前在vt_setting.json中配置好rqdata相关设置。 get_contract根据本地vt_symbol来查询对应合约对象的详细信息。
``` ```
bars = engine.get_bars(vt_symbol="rb1910.SHFE",start_date="20190101", contract = engine.get_contract(vt_symbol="rb1910.SHFE",use_df=False)
```
![](https://static.vnpy.com/upload/temp/4111776b-91fd-44e6-8b2c-289961862a3a.jpg)
 
get_bars查询历史数据。需要初始化RQData客户端
```
bars = engine.get_bars(vt_symbol="rb1910.SHFE",start_date="20190101",
interval=Interval.MINUTE,use_df=False) 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定义了如下字段 其中:
``` - vt_symbol本地合约代码。
@dataclass - start_date起始日期格式必须为"%Y%m%d"。
class BarData(BaseData): - intervalK线周期包括分钟、小时、日、周
- bars包含了一系列BarData数据的列表对象其BarData的定义如下
```
@dataclass
class BarData(BaseData):
symbol: str symbol: str
exchange: Exchange exchange: Exchange
datetime: datetime datetime: datetime
interval: Interval = None interval: Interval = None
volume: float = 0 volume: float = 0
open_interest: float = 0 open_interest: float = 0
open_price: float = 0 open_price: float = 0
high_price: float = 0 high_price: float = 0
low_price: float = 0 low_price: float = 0
close_price: float = 0 close_price: float = 0
def __post_init__(self): def __post_init__(self):
self.vt_symbol = f"{self.symbol}.{self.exchange.value}" self.vt_symbol = f"{self.symbol}.{self.exchange.value}"
``` ```
 
* 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://static.vnpy.com/upload/temp/4c585dac-0ac9-4fd8-9926-ddc104512359.jpg) get_position根据vt_positionid来查询持仓情况返回对象包含接口名称、交易所、合约代码、数量、冻结数量等。
```
position = engine.get_position(vt_positionid='rb1909.SHFE.Direction.LONG')
```
注意vt_positionid为vnpy内部对于一笔特定持仓的唯一持仓编号格式为"vt_symbol.Direction.LONG",其中持仓方向可选多仓、空仓和净持仓,如图。
![](https://static.vnpy.com/upload/temp/4c585dac-0ac9-4fd8-9926-ddc104512359.jpg)
   
### 多条查询 ### 多条查询
* **在多条查询函数中use_df参数都可以用来控制是否将函数返回的类对象转化成DataFrame仅在get_ticks中做一次详细说明其余函数同理。** get_ticks查询多个合约最新tick。
```
ticks = engine.get_ticks(vt_symbols=['rb1910.SHFE','rb1909.SHFE'],use_df = True)
```
vt_symbols是列表格式里面包含多个vt_symbol如图。
![](https://static.vnpy.com/upload/temp/311e1ee8-1a3d-496f-833f-bbb7a3a624ab.png)
   
* get_ticks查询多个合约最新tick。 get_orders根据查询多个vt_orderid查询其详细信息。vt_orderids为列表里面包含多个vt_orderid
``` ```
ticks = engine.get_ticks(vt_symbols=['rb1910.SHFE','rb1909.SHFE'],use_df = True) orders = engine.get_orders([orderid_one,orderid_two],use_df=True)
``` ```
- use_dfFalse则返回一个列表元素为TickDataTrue则返回DataFrame列是TickData的属性每一行代表一个TickData。
- vt_symbols一个列表元素为合约字符串vt_symbol。
 
get_trades根据给定的一个vt_orderid返回这次报单过程中的所有TradeData对象。vt_orderid是本地委托号每一个委托OrderData由于部分成交关系可以对应多笔成交TradeData。
```
trades = engine.get_trades(vt_orderid = your_vt_orderid,use_df = True)
```
![](https://static.vnpy.com/upload/temp/311e1ee8-1a3d-496f-833f-bbb7a3a624ab.png)
   
* 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_orderidvnpy本地订单id注意由于每一个委托OrderData可能由于市场流动性情况和多笔市场上的反向委托成交对应有多笔成交TradeData因此该函数会返回所有对应成交TraderData。
 
### 全量查询 ### 全量查询
在全量查询中唯一参数是use_df默认为False返回的是一个包含相应数据的List对象,例如ContractDataAccountDataPositionData。 在全量查询中唯一参数是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_contracts默认返回一个list包含了全市场的ContractData如果use_df=True则返回相应的DataFrame
* get_all_accounts默认返回一个list包含了AccountData如果use_df=True则返回相应的DataFrame。 - get_all_active_orders活动委托指的是等待委托完全成交故其状态包含“已提交的、未成交的、部分成交”函数将返回包含一系列OrderData的列表对象
* get_all_position默认返回一个List,包含了PositionData,如果use_df=True则返回相应的DataFrame。 - get_all_accounts默认返回包含AccountData的列表对象
- get_all_position默认返回包含PositionData的列表对象如图。
![](https://static.vnpy.com/upload/temp/5d698a27-545b-46bb-9d16-428a8ccb7956.png) ![](https://static.vnpy.com/upload/temp/5d698a27-545b-46bb-9d16-428a8ccb7956.png)
### 交易委托
* 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可以用于记录买卖时的交易情况将信息输出在脚本策略窗口下方空白栏里。
   
* send_email用于实时通过email通知用户策略运行情况需要提前在vt_setting.json下配置email相关信息。其中脚本策略发的邮件标题为“脚本策略引擎通知”msg:字符串,表示邮件正文内容。 ### 交易委托
```
engine.send_email(msg = "Your Msg")
```
![](https://static.vnpy.com/upload/temp/8dd8d6b0-6c04-4cb4-a426-ad43d11a13eb.png)
使用邮箱前需要开通SMTP服务。 以委托买入为例engine.buy()函数入参包括:
- email.server邮件服务器地址vnpy默认填写好了QQ邮箱服务器地址不用改可以直接用如果需要使用其他邮箱需要自行查找一下其他的服务器地址。 - vt_symbol本地合约代码(字符串格式)
- email.port邮件服务器端口号vnpm默认填好了QQ邮箱服务器端口可直接用。 - price报单价格(字符串格式);
- email.username填写邮箱地址即可如xxxx@qq.com。 - volume报单数量(字符串格式);
- email.password对于QQ邮箱此处不是邮箱密码而是开通SMTP后系统生成的一个授权码。 - order_typeOrderType枚举常量默认为限价单(OrderType.LIMIT)同时支持停止单OrderType.STOP、FAKOrderType.FAK、FOKOrderType.FOK、市价单OrderType.MARKET不同交易所支持报单方式不完全一致。
- email.sendertemail.username。 ```
- email.receiver接受邮件的邮箱地址比如xxxx@outlook.com。 engine.buy(vt_symbol = "rb1910.SHFE",price = "3200",volume = "1",order_type=OrderType.LIMIT)
```
执行交易委托后会返回本地委托号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://static.vnpy.com/upload/temp/8dd8d6b0-6c04-4cb4-a426-ad43d11a13eb.png)
使用邮箱前需要开通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。