VeighNa量化社区
你的开源社区量化交易平台
Member
avatar
加入于:
帖子: 420
声望: 173

1. 问题的发现

1.1 问题代码

在jupyter notebook中,我编写了下面的一段下载合约K线数据的代码:

from datetime import datetime,date,timedelta
from vnpy.trader.utility import extract_vt_symbol
from vnpy.trader.constant import Exchange,Interval
from vnpy.trader.object import HistoryRequest
from vnpy.trader.database import get_database
from vnpy.trader.datafeed import get_datafeed

df = get_datafeed()

end = datetime.now()
start = end.replace(month=11)
start,end

req = HistoryRequest(symbol='rb2201',exchange=Exchange.SHFE,start=start,end=end,interval=Interval.DAILY)

# 语句1
bars = df.query_bar_history(req)

# 语句2
db.save_bar_data(bars)

# 语句3
for bar in bars: 
    print(bar)

1.2 问题描述:

执行上面代码,当执行到语句3的时候,提示:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-11-f72a667896f4> in <module>
      1 for bar in bars:
----> 2     print(bar)

D:\ProgramFiles\vnstudio\lib\dataclasses.py in __repr__(self)

AttributeError: 'BarData' object has no attribute 'gateway_name'

如果把语句2注释掉,执行语句3的时候有没有任何问题,可以把从米筐接口读取的rb2201.SHFE的bar全部打印出来。

2. 错误的解决方法

由于本人使用的是mysql数据库,所以需要对vnpy_mysql目录下的mysql_database.py进行修改,使用其他数据库的用户其实也有同样的问题。解决方法也是一样的,不再每个都说。
方法:
打开vnpy_mysql\mysql_database.py,在文件头部添加下面的语句:

import copy     # hxxjava

对下面两个函数进行如下的修改,save_bar_data()和save_tick_data()都有同样的问题,修改之处语句在函数中注明了,错误原因是在遍历保存bars和ticks的过程中,因为数据库的要求,改变了每个bar和tick的 __dict__ 字典,保存动作做完了以后,列表bars和列表ticks的每个bar和tick已经被改得面目全非了,里面的gateway_name已经没有了。
修改过的代码后面有 # hxxjava change注释标记。
修改后的代码如下:

    def save_bar_data(self, bars: List[BarData]) -> bool:
        """保存K线数据"""
        # 读取主键参数
        bar = bars[0]
        symbol = bar.symbol
        exchange = bar.exchange
        interval = bar.interval

        # 将BarData数据转换为字典,并调整时区
        data = []

        for bar in bars:                           
            bar.datetime = convert_tz(bar.datetime)

            d = copy.copy(bar.__dict__)     # hxxjava change
            d["exchange"] = d["exchange"].value
            d["interval"] = d["interval"].value
            d.pop("gateway_name")
            d.pop("vt_symbol")
            data.append(d)

        # 使用upsert操作将数据更新到数据库中
        with self.db.atomic():
            for c in chunked(data, 50):
                DbBarData.insert_many(c).on_conflict_replace().execute()

        # 更新K线汇总数据
        overview: DbBarOverview = DbBarOverview.get_or_none(
            DbBarOverview.symbol == symbol,
            DbBarOverview.exchange == exchange.value,
            DbBarOverview.interval == interval.value,
        )

        if not overview:
            overview = DbBarOverview()
            overview.symbol = symbol
            overview.exchange = exchange.value
            overview.interval = interval.value
            overview.start = bars[0].datetime
            overview.end = bars[-1].datetime
            overview.count = len(bars)
        else:
            overview.start = min(bars[0].datetime, overview.start)
            overview.end = max(bars[-1].datetime, overview.end)

            s: ModelSelect = DbBarData.select().where(
                (DbBarData.symbol == symbol)
                & (DbBarData.exchange == exchange.value)
                & (DbBarData.interval == interval.value)
            )
            overview.count = s.count()

        overview.save()

        return True

    def save_tick_data(self, ticks: List[TickData]) -> bool:
        """保存TICK数据"""
        # 将TickData数据转换为字典,并调整时区
        data = []

        for tick in ticks:            
            tick.datetime = convert_tz(tick.datetime)

            d = copy.copy(tick.__dict__) # hxxjava change
            d["exchange"] = d["exchange"].value
            d.pop("gateway_name")
            d.pop("vt_symbol")
            data.append(d)

        # 使用upsert操作将数据更新到数据库中
        with self.db.atomic():
            for c in chunked(data, 50):
                DbTickData.insert_many(c).on_conflict_replace().execute()

        return True
Administrator
avatar
加入于:
帖子: 4502
声望: 321

感谢分享!精华送上

Member
avatar
加入于:
帖子: 7
声望: 0

MongoDB保存数据那个又怎么改,老是在缓存bar数据哪里出错,研究了一会儿,没弄明白哪里的问题,可以指导一下吗
Traceback (most recent call last):
File "F:\project_file\vnpy_single_plus\apps_plus\data_recorder_plus\ui\widget.py", line 157, in process_exception_event
raise exc_info[1].with_traceback(exc_info[2])
File "F:\project_file\vnpy_single_plus\apps_plus\data_recorder_plus\engine.py", line 85, in run
self.database.save_bar_data(data)
File "F:\project_file\vnpy_single_plus\apps_plus\database\mongodb\database_mongo_plus.py", line 135, in save_bar_data
self.overview_collection.update(filter, overview, upsert=True)
File "E:\vnstudio_2.8.1\lib\site-packages\pymongo\collection.py", line 2587, in call
self.__name.split(".")[-1])
TypeError: 'Collection' object is not callable. If you meant to call the 'update' method on a 'Collection' object it is failing because no such method exists.

Member
avatar
加入于:
帖子: 716
声望: 62

请麻烦贴一下具体报错信息

Member
avatar
加入于:
帖子: 716
声望: 62

pymongo在4.0版本后升级了api,把update这些api都删除了。将pymongo版本降到3.12.3就可以了。

Member
avatar
加入于:
帖子: 7
声望: 0

不用降版本,问题已解决,将代码改成一下代码就行
else:
overview["start"] = min(bars[0].datetime, overview["start"])
overview["end"] = max(bars[-1].datetime, overview["end"])

        overview["count"] = self.bar_collection.count_documents(filter)
    self.overview_collection.update_one(filter, {'$set': overview}, upsert=True)
© 2015-2022 上海韦纳软件科技有限公司
备案服务号:沪ICP备18006526号

沪公网安备 31011502017034号

【用户协议】
【隐私政策】
【免责条款】