Merge branch 'dev' of https://github.com/vnpy/vnpy into dev

This commit is contained in:
vn.py 2019-08-01 14:47:20 +08:00
commit 31e76df8a7
6 changed files with 188 additions and 50 deletions

View File

@ -1,5 +1,5 @@
# 算法交易 # 算法交易
算法交易一般用于把巨型单子拆分成一个个小单,能够有效降低交易成本,冲击成本等。 算法交易可以用于把巨型单子拆分成一个个小单,能够有效降低交易成本,冲击成本等(冰山算法、狙击手算法);也可以在设定的阈值内进行高抛低吸操作(网格算法、套利算法)
   
@ -45,6 +45,7 @@
![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/algo_trader/trading_section.png) ![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/algo_trader/trading_section.png)
交易配置可以保存在json文件这样每次打开算法交易模块就不用重复输入配置。其操作是在“算法名称”选项输入该算法设置命名然后点击下方"保存设置”按钮。保存的json文件在C:\Users\Administrator\\.vntrader文件夹的algo_trading_setting.json中如图。 交易配置可以保存在json文件这样每次打开算法交易模块就不用重复输入配置。其操作是在“算法名称”选项输入该算法设置命名然后点击下方"保存设置”按钮。保存的json文件在C:\Users\Administrator\\.vntrader文件夹的algo_trading_setting.json中如图。
![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/algo_trader/setting.png) ![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/algo_trader/setting.png)
委托交易界面最下方的“全部停止”按钮用于一键停止所有执行中的算法交易。 委托交易界面最下方的“全部停止”按钮用于一键停止所有执行中的算法交易。

View File

@ -10,29 +10,28 @@ CSV载入模块在vnpy根目录下vnpy\app\csv_loader文件夹内engine.py里
- CSV表头信息日期时间、开盘价、最高价、最低价、收盘价、成交量 - CSV表头信息日期时间、开盘价、最高价、最低价、收盘价、成交量
``` ```
self.file_path: str = '' self.file_path: str = ""
self.symbol: str = "" self.symbol: str = ""
self.exchange: Exchange = Exchange.SSE self.exchange: Exchange = Exchange.SSE
self.interval: Interval = Interval.MINUTE self.interval: Interval = Interval.MINUTE
self.datetime_head: str = '' self.datetime_head: str = ""
self.open_head: str = '' self.open_head: str = ""
self.close_head: str = '' self.close_head: str = ""
self.low_head: str = '' self.low_head: str = ""
self.high_head: str = '' self.high_head: str = ""
self.volume_head: str = '' self.volume_head: str = ""
``` ```
以sql数据库为例 以SQL数据库为例把上期所的IF1909的历史数据插入到数据库中那么合约代码应该填写rb1909交易所中填写SHFE在本地数据库中会有symbol和exchange两个键值用于索引。
合约信息中合约代码是将csv中数据存入至何种品种数据库中。例如在合约代码中填写rb1909在交易所中填写SHFE在本地数据库中会有symbol和exchange两个键值用于索引。
在csv中日期时间一列格式需要为str格式。
   
## 数据载入 ## 数据载入
从文件路径中读取CSV文件然后在每一次迭代中载入数据到数据库中。 从文件路径中读取CSV文件然后在每一次迭代中载入数据到数据库中。
``` ```
with open(file_path, 'rt') as f: with open(file_path, "rt") as f:
reader = csv.DictReader(f) reader = csv.DictReader(f)
for item in reader: for item in reader:
@ -42,7 +41,7 @@ CSV载入模块在vnpy根目录下vnpy\app\csv_loader文件夹内engine.py里
载入数据的方法可以分成2类 载入数据的方法可以分成2类
- 直接插入合约代码、交易所、K线周期、成交量、开盘价、最高价、最低价、收盘价、接口名称 - 直接插入合约代码、交易所、K线周期、成交量、开盘价、最高价、最低价、收盘价、接口名称
- 需要处理日期时间根据其相应的时间格式通过strptime()转化成时间元、vt_symbol(合约代码.交易所格式如rb1905.SHFE) - 需要处理日期时间根据其相应的时间格式通过strptime()转化成时间元、vt_symbol(合约代码.交易所格式如rb1909.SHFE)
注意db_bar.replace()用于数据更新,即把旧的数据替换成新的。 注意db_bar.replace()用于数据更新,即把旧的数据替换成新的。
``` ```

View File

@ -1,5 +1,5 @@
# CTA回测模块 # CTA回测模块
CTA回测模块是基于PyQt5和pyqtgraph的图形化回测工具。启动VN Trader后在菜单栏中点击“功能-> CTA回测”即可进入该图形化回测界面如下图。CTA回测模块主要实现3个功能历史行情数据的下载、策略回测、参数优化。 CTA回测模块是基于PyQt5和pyqtgraph的图形化回测工具。启动VN Trader后在菜单栏中点击“功能-> CTA回测”即可进入该图形化回测界面如下图。CTA回测模块主要实现3个功能历史行情数据的下载、策略回测、参数优化、K线图表买卖点展示
![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/cta_backtester/cta_backtester.png) ![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/cta_backtester/cta_backtester.png)
@ -35,7 +35,10 @@ CTA回测模块是基于PyQt5和pyqtgraph的图形化回测工具。启动VN Tra
## 下载数据 ## 下载数据
在开始策略回测之前必须保证数据库内有充足的历史数据。故vnpy提供了历史数据一键下载的功能。 在开始策略回测之前必须保证数据库内有充足的历史数据。故vnpy提供了历史数据一键下载的功能。
下载数据功能主要是基于RQData的get_price()函数实现的。
### RQData
RQData提供国内股票、ETF、期货以及期权的历史数据。
其下载数据功能主要是基于RQData的get_price()函数实现的。
``` ```
get_price( get_price(
order_book_ids, start_date='2013-01-04', end_date='2014-01-04', order_book_ids, start_date='2013-01-04', end_date='2014-01-04',
@ -47,7 +50,7 @@ get_price(
在使用前要保证RQData初始化完毕然后填写以下4个字段信息 在使用前要保证RQData初始化完毕然后填写以下4个字段信息
- 本地代码:格式为合约品种+交易所如IF88.CFFEX、rb88.SHFE然后在底层通过RqdataClient的to_rq_symbol()函数转换成符合RQData格式对应RQData中get_price()函数的order_book_ids字段。 - 本地代码:格式为合约品种+交易所如IF88.CFFEX、rb88.SHFE然后在底层通过RqdataClient的to_rq_symbol()函数转换成符合RQData格式对应RQData中get_price()函数的order_book_ids字段。
- K线周期可以填1m、60m、1d对应get_price()函数的frequency字段。 - K线周期可以填1m、1h、d、w对应get_price()函数的frequency字段。
- 开始日期格式为yy/mm/dd如2017/4/21对应get_price()函数的start_date字段。点击窗口右侧箭头按钮可改变日期大小 - 开始日期格式为yy/mm/dd如2017/4/21对应get_price()函数的start_date字段。点击窗口右侧箭头按钮可改变日期大小
- 结束日期格式为yy/mm/dd如2019/4/22对应get_price()函数的end_date字段。点击窗口右侧箭头按钮可改变日期大小 - 结束日期格式为yy/mm/dd如2019/4/22对应get_price()函数的end_date字段。点击窗口右侧箭头按钮可改变日期大小
@ -56,13 +59,152 @@ get_price(
![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/cta_backtester/data_loader.png) ![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/cta_backtester/data_loader.png)
 
### IB
盈透证券提供外盘股票、期货、期权的历史数据。
下载前必须连接好IB接口因为其下载数据功能主要是基于IbGateway类query_history()函数实现的。
```
def query_history(self, req: HistoryRequest):
""""""
self.history_req = req
self.reqid += 1
ib_contract = Contract()
ib_contract.conId = str(req.symbol)
ib_contract.exchange = EXCHANGE_VT2IB[req.exchange]
if req.end:
end = req.end
end_str = end.strftime("%Y%m%d %H:%M:%S")
else:
end = datetime.now()
end_str = ""
delta = end - req.start
days = min(delta.days, 180) # IB only provides 6-month data
duration = f"{days} D"
bar_size = INTERVAL_VT2IB[req.interval]
if req.exchange == Exchange.IDEALPRO:
bar_type = "MIDPOINT"
else:
bar_type = "TRADES"
self.client.reqHistoricalData(
self.reqid,
ib_contract,
end_str,
duration,
bar_size,
bar_type,
1,
1,
False,
[]
)
self.history_condition.acquire() # Wait for async data return
self.history_condition.wait()
self.history_condition.release()
history = self.history_buf
self.history_buf = [] # Create new buffer list
self.history_req = None
return history
```
 
### BITMEX
BITMEX交易所提供数字货币历史数据。
由于仿真环境与实盘环境行情差异比较大故需要用实盘账号登录BIMEX接口来下载真实行情数据其下载数据功能主要是基于BitmexGateway类query_history()函数实现的。
```
def query_history(self, req: HistoryRequest):
""""""
if not self.check_rate_limit():
return
history = []
count = 750
start_time = req.start.isoformat()
while True:
# Create query params
params = {
"binSize": INTERVAL_VT2BITMEX[req.interval],
"symbol": req.symbol,
"count": count,
"startTime": start_time
}
# Add end time if specified
if req.end:
params["endTime"] = req.end.isoformat()
# Get response from server
resp = self.request(
"GET",
"/trade/bucketed",
params=params
)
# Break if request failed with other status code
if resp.status_code // 100 != 2:
msg = f"获取历史数据失败,状态码:{resp.status_code},信息:{resp.text}"
self.gateway.write_log(msg)
break
else:
data = resp.json()
if not data:
msg = f"获取历史数据为空,开始时间:{start_time},数量:{count}"
break
for d in data:
dt = datetime.strptime(
d["timestamp"], "%Y-%m-%dT%H:%M:%S.%fZ")
bar = BarData(
symbol=req.symbol,
exchange=req.exchange,
datetime=dt,
interval=req.interval,
volume=d["volume"],
open_price=d["open"],
high_price=d["high"],
low_price=d["low"],
close_price=d["close"],
gateway_name=self.gateway_name
)
history.append(bar)
begin = data[0]["timestamp"]
end = data[-1]["timestamp"]
msg = f"获取历史数据成功,{req.symbol} - {req.interval.value}{begin} - {end}"
self.gateway.write_log(msg)
# Break if total data count less than 750 (latest date collected)
if len(data) < 750:
break
# Update start time
start_time = bar.datetime + TIMEDELTA_MAP[req.interval]
return history
```
&nbsp; &nbsp;
## 策略回测 ## 策略回测
下载完历史数据后,需要配置以下字段:交易策略、手续费率、交易滑点、合约乘数、价格跳动、回测资金。 下载完历史数据后,需要配置以下字段:交易策略、手续费率、交易滑点、合约乘数、价格跳动、回测资金。
这些字段主要对应BacktesterEngine类的run_backtesting函数。 这些字段主要对应BacktesterEngine类的run_backtesting函数。
若数据库已存在历史数据无需重复下载直接从本地数据库中导入数据进行回测。注意vt_symbol的格式为品种代码.交易所的形式如IF1908.CFFEX导入时会自动将其分割为品种和交易所两部分
``` ```
def run_backtesting( def run_backtesting(
self, class_name: str, vt_symbol: str, interval: str, start: datetime, self, class_name: str, vt_symbol: str, interval: str, start: datetime,
@ -70,8 +212,7 @@ def run_backtesting(
capital: int, setting: dict capital: int, setting: dict
) )
``` ```
如果没有RqData用于下载历史数据一般情况则可以通过完整填写所有字段从本地已连接的数据库中导入数据进行回测
注:本地代码应以品种代码.交易所的形式(导入时会自动将其分割为品种和交易所两部分)
点击下方的“开始回测”按钮可以开始回测: 点击下方的“开始回测”按钮可以开始回测:
首先会弹出如图所示的参数配置窗口用于调整策略参数。该设置对应的是run_backtesting()函数的setting字典。 首先会弹出如图所示的参数配置窗口用于调整策略参数。该设置对应的是run_backtesting()函数的setting字典。
@ -101,6 +242,21 @@ def run_backtesting(
![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/cta_backtester/show_result_chat.png) ![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/cta_backtester/show_result_chat.png)
&nbsp;
### K线图
K线图是基于PyQtGraph开发的整个模块由以下五大组件构成
- BarManagerK线序列数据管理工具
- ChartItem基础图形类继承实现后可以绘制K线、成交量、技术指标等
- DatetimeAxis针对K线时间戳设计的定制坐标轴
- ChartCursor十字光标控件用于显示特定位置的数据细节
- ChartWidget包含以上所有部分提供单一函数入口的绘图组件
在回测完毕后点击“K线图表”按钮即可显示历史K线行情数据默认1分钟并且标识有具体的买卖点位如下图。
![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/cta_backtester/bar_chart.png)
&nbsp; &nbsp;
## 参数优化 ## 参数优化

View File

@ -8,7 +8,7 @@ CTA策略模块主要由7部分构成如下图
- base定义了CTA模块中用到的一些基础设置如引擎类型回测/实盘、回测模式K线/Tick、本地停止单的定义以及停止单状态等待中/已撤销/已触发)。 - base定义了CTA模块中用到的一些基础设置如引擎类型回测/实盘、回测模式K线/Tick、本地停止单的定义以及停止单状态等待中/已撤销/已触发)。
- template定义了CTA策略模板包含信号生成和委托管理、CTA信号仅负责信号生成、目标仓位算法仅负责委托管理适用于拆分巨型委托降低冲击成本 - template定义了CTA策略模板包含信号生成和委托管理、CTA信号仅负责信号生成、目标仓位算法仅负责委托管理适用于拆分巨型委托降低冲击成本
- strategies: 官方提供的cta策略示例包含从最基础的双均线策略到通道突破类型的布林带策略到跨时间周期策略再到把信号生成和委托管理独立开来的多信号策略。 - strategies: 官方提供的cta策略示例包含从最基础的双均线策略到通道突破类型的布林带策略到跨时间周期策略再到把信号生成和委托管理独立开来的多信号策略。(用户自定义的策略也可以放在strategies文件夹内运行)
- backesting包含回测引擎和参数优化。其中回测引擎定义了数据载入、委托撮合机制、计算与统计相关盈利指标、结果绘图等函数。 - backesting包含回测引擎和参数优化。其中回测引擎定义了数据载入、委托撮合机制、计算与统计相关盈利指标、结果绘图等函数。
- converter定义了针对上期所品种平今/平昨模式的委托转换模块对于其他品种用户也可以通过可选参数lock切换至锁仓模式。 - converter定义了针对上期所品种平今/平昨模式的委托转换模块对于其他品种用户也可以通过可选参数lock切换至锁仓模式。
- engine定义了CTA策略实盘引擎其中包括RQData客户端初始化和数据载入、策略的初始化和启动、推送Tick订阅行情到策略中、挂撤单操作、策略的停止和移除等。 - engine定义了CTA策略实盘引擎其中包括RQData客户端初始化和数据载入、策略的初始化和启动、推送Tick订阅行情到策略中、挂撤单操作、策略的停止和移除等。
@ -18,35 +18,11 @@ CTA策略模块主要由7部分构成如下图
&nbsp; &nbsp;
## 历史数据 ## 数据加载
### 回测历史数据
在开始策略回测之前必须保证数据库内有充足的历史数据。故vnpy提供了历史数据一键下载的功能。
下载数据功能主要是基于RQData的get_price()函数实现的。
```
get_price(
order_book_ids, start_date='2013-01-04', end_date='2014-01-04',
frequency='1d', fields=None, adjust_type='pre', skip_suspended =False,
market='cn'
)
```
在使用前要保证RQData初始化完毕然后填写以下4个字段信息
- 本地代码:格式为合约品种+交易所如IF88.CFFEX、rb88.SHFE然后在底层通过RqdataClient的to_rq_symbol()函数转换成符合RQData格式对应RQData中get_price()函数的order_book_ids字段。
- K线周期可以填1m、60m、1d对应get_price()函数的frequency字段。
- 开始日期格式为yy/mm/dd如2017/4/21对应get_price()函数的start_date字段。点击窗口右侧箭头按钮可改变日期大小
- 结束日期格式为yy/mm/dd如2019/4/22对应get_price()函数的end_date字段。点击窗口右侧箭头按钮可改变日期大小
填写完字段信息后,点击下方“下载数据”按钮启动下载程序,下载成功如图所示。
![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/cta_backtester/data_loader.png)
### 实盘历史数据
在实盘中RQData通过实时载入数据进行策略的初始化。该功能主要在CTA实盘引擎engine.py内实现。 在实盘中RQData通过实时载入数据进行策略的初始化。该功能主要在CTA实盘引擎engine.py内实现。
下面介绍具体流程: 下面介绍具体流程:
- 配置json文件在用户目录下.vntrader文件夹找到vt_setting.json输入RQData的账号和密码,如图。 - 在菜单栏点击“配置”进入全局配置页面输入RQData账号密码或者直接配置json文件即在用户目录下.vntrader文件夹找到vt_setting.json如图。
![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/cta_strategy/RQData_setting.png "enter image title here") ![](https://vnpy-community.oss-cn-shanghai.aliyuncs.com/forum_experience/yazhang/cta_strategy/RQData_setting.png "enter image title here")
@ -114,7 +90,8 @@ get_price(
&nbsp; &nbsp;
## 策略开发 ## 策略开发
CTA策略模板提供完整的信号生成和委托管理功能用户可以基于该模板自行开发策略。新策略可以放在根目录下vnpy\app\cta_strategy\strategies文件夹内也可以放在用户运行的文件内VN Station模式。注意策略文件命名是以下划线模式如boll_channel_strategy.py而策略类命名采用的是驼峰式如BollChannelStrategy。 CTA策略模板提供完整的信号生成和委托管理功能用户可以基于该模板自行开发策略。新策略可以放在用户运行的文件内推荐如在c:\users\administrator.vntrader目录下创建strategies文件夹可以放在根目录下vnpy\app\cta_strategy\strategies文件夹内。
注意策略文件命名是以下划线模式如boll_channel_strategy.py而策略类命名采用的是驼峰式如BollChannelStrategy。
下面通过BollChannelStrategy策略示例来展示策略开发的具体步骤 下面通过BollChannelStrategy策略示例来展示策略开发的具体步骤
@ -164,7 +141,7 @@ CTA策略模板提供完整的信号生成和委托管理功能用户可以
### 策略的初始化、启动、停止 ### 策略的初始化、启动、停止
通过“CTA策略”组件的相关功能按钮实现。 通过“CTA策略”组件的相关功能按钮实现。
注意函数load_bar(10)代表策略初始化需要载入10个交易日的历史数据。该历史数据可以是Tick数据也可以是K线数据。 注意函数load_bar(10)代表策略初始化需要载入10个交易日的历史数据。该历史数据可以是Tick数据也可以是K线数据。在策略初始化时候会调用K线时间序列管理器计算并缓存相关的计算指标但是并不触发交易。
``` ```
def on_init(self): def on_init(self):
@ -918,6 +895,7 @@ def optimize(
### 初始化策略 ### 初始化策略
- 调用策略类的on_init()回调函数,并且载入历史数据; - 调用策略类的on_init()回调函数,并且载入历史数据;
- 恢复上次退出之前的策略状态; - 恢复上次退出之前的策略状态;
- 从.vntrader/cta_strategy_data.json内读取策略参数最新的技术指标以及持仓数量
- 调用接口的subcribe()函数订阅指定行情信息; - 调用接口的subcribe()函数订阅指定行情信息;
- 策略初始化状态变成True并且更新到日志上。 - 策略初始化状态变成True并且更新到日志上。
@ -999,6 +977,7 @@ def optimize(
- 调用策略类的on_stop()函数停止策略; - 调用策略类的on_stop()函数停止策略;
- 更新策略启动状态为False - 更新策略启动状态为False
- 对所有为成交的委托(市价单/限价单/本地停止单)进行撤单操作; - 对所有为成交的委托(市价单/限价单/本地停止单)进行撤单操作;
- 把策略参数,最新的技术指标,以及持仓数量保存到.vntrader/cta_strategy_data.json内
- 在图形化界面更新策略状态。 - 在图形化界面更新策略状态。
``` ```
@ -1019,6 +998,9 @@ def optimize(
# Cancel all orders of the strategy # Cancel all orders of the strategy
self.cancel_all(strategy) self.cancel_all(strategy)
# Sync strategy variables to data file
self.sync_strategy_data(strategy)
# Update GUI # Update GUI
self.put_strategy_event(strategy) self.put_strategy_event(strategy)
``` ```

View File

@ -5,7 +5,7 @@
- 后台会自动调用行情API接口的suscribe()函数自动订阅行情; - 后台会自动调用行情API接口的suscribe()函数自动订阅行情;
- 行情信息通过database_manager模块的save_bar_data()函数/save_tick_data()函数载入到数据库中。 - 行情信息通过database_manager模块的save_bar_data()函数/save_tick_data()函数载入到数据库中。
注意目前vnpy支持的数据库为SQLite/ MySQL/ PostgreSQL/ MongoDB。若用户使用MongoDB则行情记录数据直接载入到MongoDB中。 注意目前vnpy支持的数据库为SQLite/ MySQL/ PostgreSQL/ MongoDB。其在VnTrader的菜单栏选择“配置”进入“全局配置”界面来选择数据库(默认为SQLite), 或者在用户目录下的.vntrader/vt_setting.json里面直接配置。若用户使用MongoDB则行情记录数据直接载入到MongoDB中。
&nbsp; &nbsp;
@ -53,7 +53,7 @@
下面介绍行情收录的具体原理若无合约记录的历史用户需要先添加行情记录任务如连接CTP接口后记录rb1905.SHFE的tick数据然后调用add_tick_recording()函数执行下面工作: 下面介绍行情收录的具体原理若无合约记录的历史用户需要先添加行情记录任务如连接CTP接口后记录rb1905.SHFE的tick数据然后调用add_tick_recording()函数执行下面工作:
1) 先创建tick_recordings字典 1) 先创建tick_recordings字典
2) 调用接口的suscribe()函数订阅行情; 2) 调用接口的suscribe()函数订阅行情;
3 )保存该tick_recordings字典到json文件上 3) 保存该tick_recordings字典到json文件上
4) 推送行情记录事件。 4) 推送行情记录事件。
``` ```

View File

@ -423,7 +423,7 @@ class CtaEngine(BaseEngine):
self.call_strategy_func(strategy, strategy.on_stop_order, stop_order) self.call_strategy_func(strategy, strategy.on_stop_order, stop_order)
self.put_stop_order_event(stop_order) self.put_stop_order_event(stop_order)
return stop_orderid return [stop_orderid]
def cancel_server_order(self, strategy: CtaTemplate, vt_orderid: str): def cancel_server_order(self, strategy: CtaTemplate, vt_orderid: str):
""" """