在使用VNPY时,只有两张表,一个是bar数据,一个是tick,实际使用中,这个数据库文件相当大,检索很费时。并看到有人也遇到了同样的困惑,建议vnpy-2.0.9 用关系型数据库。
于是,我尝试基于vnpy 2.0.8,修改数据为 MongoDB,并将数据保存至指定的 Collection,同时保证当未指定 Collection 时,数据仍保存在原有的数据表中。适用于 tick数据 和 bar 数据。分享出来,如有错误,希望指正。本文也同时发于我的 CSDN 博客。
更改数据库为 MongoDB
注意在MongoDB中需要创建新数据库,如“vnpytest”,然后在全局配置对话框中,修改相关配置(或直接修改vnpy运行目录 .vntrader
下的 vt_setting.json
文件):
"database.driver": "mongodb",
"database.database": "vnpytest",
"database.host": "localhost",
"database.port": 27017,
"database.user": "",
"database.password": "",
"database.authentication_source": ""
注意输入上述内容到配置对话框中时,请忽略引号。修改完毕保存后,请重新启动VN Trader,检查相关配置是否已经修改成功。
保存数据至指定的 mongodb collection
数据来源可以是 csv 文件,也可以从开源数据如 tushare (https://tushare.pro/register?reg=347489) 获取,等等,这里不再给出。
- 新建py文件,写入主函数
from vnpy.trader.database import database_manager
from vnpy.trader.object import BarData
from vnpy.trader.constant import Interval, Exchange
def ts2bar(df, collection_name=None):
bars = []
for i in range(df.shape[0]):
bar = BarData(
symbol=df.ts_code[i].split('.')[0],
exchange=exc,
datetime=df.trade_date[i],
interval=Interval.DAILY,
volume=df.vol[i],
open_price=df.open[i],
high_price=df.high[i],
low_price=df.low[i],
close_price=df.close[i],
gateway_name='DB',
)
bars.append(bar)
collection_name = collection_name
print('Saving data to database ...')
database_manager.save_bar_data(bars, collection_name)
- 修改
vnpy/trader/database/database.py
中的save_bar_data
和save_tick_data
@abstractmethod
def save_bar_data(
self,
datas: Sequence["BarData"],
collection_name: str = None,
):
pass
@abstractmethod
def save_tick_data(
self,
datas: Sequence["TickData"],
collection_name: str = None,
):
pass
- 修改
vnpy/trader/database/database_mongo.py
中的save_bar_data
和save_tick_data
def save_bar_data(self, datas: Sequence[BarData], collection_name: str = None):
for d in datas:
...
if collection_name is None:
(
DbBarData.objects(
symbol=d.symbol, interval=d.interval.value, datetime=d.datetime
).update_one(upsert=True, **updates)
)
else:
with switch_collection(DbBarData, collection_name):
(
DbBarData.objects(
symbol=d.symbol, interval=d.interval.value, datetime=d.datetime
).update_one(upsert=True, **updates)
)
def save_tick_data(self, datas: Sequence[TickData], collection_name: str = None):
for d in datas:
...
if collection_name is None:
(
DbTickData.objects(
symbol=d.symbol, exchange=d.exchange.value, datetime=d.datetime
).update_one(upsert=True, **updates)
)
else:
with switch_collection(DbTickData, collection_name):
(
DbTickData.objects(
symbol=d.symbol, exchange=d.exchange.value, datetime=d.datetime
).update_one(upsert=True, **updates)
)
对于 MySQL 数据库,修改方法应该是类似的。