🚀 AI 一键生成 qmt 策略代码
立即体验
👉 AI 生成代码 👈

为什么 QMT 的 download_history_data2 是异步执行?如何正确获取最新数据?

qmt | 发布时间: 2026/5/27
以下内容由 EasyQuant 生成。

问题描述

为什么文档显示xtdata.download_history_data2是同步执行,但实际上却是异步执行呢

我先调用了xtdata.download_history_data2(stock_list, '1d', end_time=today, callback=lambda data: print(data),
incrementally=None)
然后再调用xtdata.get_market_data_ex([], stocks, period='1d', count=11)
但是获取的数据却没有最新的数据,这是为什么呢?
或者大家都是怎么获取最新的数据的呢?

解决方案

在 QMT (迅投) 量化平台中,遇到 download_history_data2 表现为异步执行,导致紧接着调用 get_market_data_ex 获取不到最新数据,这是一个非常典型的数据同步问题。以下是详细的原因分析及解决方案:

一、 为什么会变成异步执行?

根本原因在于你传入了 callback 参数

在 QMT 的底层设计中,数据下载涉及到与服务器的网络通信。为了防止主线程被长时间阻塞(特别是在下载大量数据时导致界面卡死),API 提供了异步回调机制:

  1. 异步模式(非阻塞):当你传入了 callback 参数(如 callback=lambda data: print(data)),函数会立即返回,并在后台线程进行数据下载。下载完成或有进度时,会触发你提供的回调函数。因此,紧接着执行的 get_market_data_ex 会在数据真正下载到本地之前运行,自然获取不到最新数据。
  2. 同步模式(阻塞):如果你不传入 callback 参数(或者将其设为 None),函数通常会以同步阻塞的方式运行,直到数据完全下载到本地硬盘后才会执行下一行代码。

二、 如何解决获取不到最新数据的问题?

根据你的需求,有以下几种解决方案:

方法 1:强制同步下载(推荐用于盘前/盘后数据准备)

去掉 callback 参数,让程序阻塞等待下载完成,然后再读取数据。

import xtdata

# 1. 同步下载数据(不传 callback)
xtdata.download_history_data2(stock_list, '1d', end_time=today, incrementally=None)

# 2. 下载完成后,再从本地读取数据
data = xtdata.get_market_data_ex([], stocks, period='1d', count=11)
print(data)

方法 2:在回调函数中获取数据(适用于需要异步不阻塞主线程的场景)

如果你希望保持异步下载,必须将获取数据的逻辑写在回调函数内部,确保在下载完成后才去读取。

import xtdata

def on_download_finish(download_info):
    print("下载完成:", download_info)
    # 在回调中获取最新数据
    data = xtdata.get_market_data_ex([], stocks, period='1d', count=11)
    print(data)

# 启动异步下载
xtdata.download_history_data2(stock_list, '1d', end_time=today, callback=on_download_finish, incrementally=None)

三、 大家都是怎么获取最新数据的?(最佳实践)

在实际的量化交易中,获取最新数据的方式取决于你所处的场景(盘中实时 vs 盘后分析):

1. 盘中实时获取最新数据(订阅机制)

在盘中交易时,不建议频繁调用 download_history_data2,因为这会产生大量的网络请求延迟。正确的做法是使用订阅机制

在 QMT 内置策略中,get_market_data_ex 默认带有 subscribe=True 参数(在 xtdata 中也有类似机制或使用 subscribe_quote)。订阅后,终端会自动在后台维护最新数据,你直接读取即可:

# 订阅实时行情(以 QMT 内置 ContextInfo 为例)
# ContextInfo.subscribe_quote(stock_code, period='1d', callback=on_quote)

# 或者在获取时开启订阅(如果 API 支持)
data = xtdata.get_market_data_ex([], stocks, period='1d', count=11, subscribe=True)

2. 获取最新的全推 Tick 数据

如果你需要的是最新的切片数据(如最新价、买卖五档),直接使用 get_full_tick 接口,它会直接从内存中读取终端接收到的最新快照,速度极快,不需要下载历史 K 线:

# 获取最新分笔快照数据
tick_data = xtdata.get_full_tick(stocks)
print(tick_data)

总结

  • 同步变异步的原因:传入了 callback 参数。
  • 解决办法:移除 callback 实现同步阻塞,或在 callback 内部执行读取逻辑。
  • 盘中最佳实践:盘前一次性下载历史数据,盘中通过订阅 (subscribe)Tick 快照 (get_full_tick) 获取最新动态,避免盘中频繁调用下载接口。