vnpy/docs/script_trader.md

241 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 脚本策略
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://static.vnpy.com/upload/temp/82dd7cfd-6a98-4908-a770-582cfb7e69bc.jpg)
**注**
- 如果对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。
 
## 脚本策略模式
### 加载启动
如在脚本策略模式下使用需要提前编写相关脚本策略文件假设为demo_arbitrage.py,然后打开vntrader,在菜单栏"功能"处打开"脚本策略",在跳出的脚本策略窗口最上方打开/Path-To-demo_arbitrage.py/demo_arbitrage.py然后直接启动即可。
![](https://static.vnpy.com/upload/temp/bf6b06f8-26e9-466b-b3e0-5b3a6f99e6ba.jpg)
### 脚本策略
脚本策略文件编写需要遵循一定格式,下面展示一个基础的模板
```
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_dfbool变量默认False返回TickData类对象否则返回相应DataFrame。
![](https://static.vnpy.com/upload/temp/d00ca165-1266-4812-afaa-f6723745d6a4.png)
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://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相关设置。
```
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_positionidvnpy内部对于一笔特定持仓的唯一持仓编号格式为"vt_symbol.Direction.LONG",其中方向可选择为```DIRECTION.SHORT```或```DIRECTION.NET```
![](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)
```
- use_dfFalse则返回一个列表元素为TickDataTrue则返回DataFrame列是TickData的属性每一行代表一个TickData。
- vt_symbols一个列表元素为合约字符串vt_symbol。
![](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。
* 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://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服务。
- 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。