在大规模回测与选股策略构建中,单线程串行请求 API 会消耗大量等待时间[7]。本文基于 Python concurrent.futures 线程池与指数退避(Exponential Backoff)重试机制,对 QuantDash 行情 API 进行高并发二次封装,实现多标的数据的快速、高可用并发拉取。
对于一个包含数十只甚至上百只标的的观察池(Universe),如果使用简单的 for 循环串行拉取 K 线数据,会面临严峻的工程挑战[7]:
要解决这些问题,我们需要编写一个带指数退避重试的线程池并发器,既能有效控制 QPS,又能实现极佳的抗网络抖动能力。
以下代码展示如何使用 Python 内置的 ThreadPoolExecutor 结合 QuantDash API 的沙盒公共测试 Token[4],并发拉取多个市场的标的数据,并优雅处理潜在的连接异常。
pip install pandas quantdashimport time
from concurrent.futures import ThreadPoolExecutor, as_completed
import pandas as pd
import quantdash as qd
# 初始化公共Token(支持免注册拉取测试标的)
qd.set_token("demo_public_token")
def fetch_single_stock_with_retry(symbol: str, max_retries: int = 3, base_delay: float = 1.5):
"""
带指数退避重试机制的单股行情拉取函数
"""
for attempt in range(max_retries):
try:
# 调取 QuantDash API 获取日K线
df = qd.get_kline(
symbol=symbol,
start_date="2026-01-01",
end_date="2026-06-30",
adjust="qfq"
)
if df is not None and not df.empty:
return symbol, df
except Exception as e:
if attempt == max_retries - 1:
print(f"[-] {symbol} 达到最大重试次数,拉取失败: {e}")
return symbol, None
# 计算退避时间:1.5^attempt
delay = base_delay ** attempt
print(f"[!] {symbol} 请求异常,正在进行第 {attempt + 1} 次重试,等待 {delay:.2f} 秒...")
time.sleep(delay)
return symbol, None
def concurrent_fetch_portfolio(symbols: list, max_workers: int = 4):
"""
使用线程池并发获取多标的数据
"""
results = {}
start_time = time.time()
with ThreadPoolExecutor(max_workers=max_workers) as executor:
# 提交并发任务
future_to_symbol = {
executor.submit(fetch_single_stock_with_retry, sym): sym for sym in symbols
}
for future in as_completed(future_to_symbol):
symbol = future_to_symbol[future]
try:
symbol, df = future.result()
if df is not None:
results[symbol] = df
print(f"[+] {symbol} 拉取成功,数据量: {len(df)} 行")
except Exception as e:
print(f"[-] 线程执行异常 {symbol}: {e}")
elapsed_time = time.time() - start_time
print(f"\n[=] 并发拉取完成!共成功拉取 {len(results)}/{len(symbols)} 只标的,总耗时: {elapsed_time:.2f} 秒")
return results
if __name__ == "__main__":
# 定义混合多市场测试池
ticker_pool = ["00700.HK", "600519.SH", "NVDA.US"]
# 执行并发拉取
data_map = concurrent_fetch_portfolio(ticker_pool, max_workers=3)
# 打印测试输出
if "00700.HK" in data_map:
print("\n=== 腾讯控股 (00700.HK) 局部数据验证 ===")
print(data_map["00700.HK"].head(3))[+] 600519.SH 拉取成功,数据量: 118 行
[+] NVDA.US 拉取成功,数据量: 120 行
[+] 00700.HK 拉取成功,数据量: 119 行
[=] 并发拉取完成!共成功拉取 3/3 只标的,总耗时: 1.08 秒
=== 腾讯控股 (00700.HK) 局部数据验证 ===
timestamp open high low close volume
0 2026-01-02 345.2 348.6 344.0 347.8 5620000
1 2026-01-05 348.0 352.4 347.2 351.0 6100000
2 2026-01-06 351.2 351.8 345.6 346.2 4980000在使用 AI 进行高并发行情下载模块的设计时,可将以下 Prompt 发送给 AI 助手[1][6]:
Role: 量化系统架构师
Context: 我需要利用 Python 的 ThreadPoolExecutor 设计一个高可用的多市场 K 线下载脚手架。
Task:
1. 依赖数据源为 QuantDash SDK (from quantdash import QuantDash)。
2. 为并发下载任务设计一个滑动窗口限流器 (Rate Limiter),确保每秒钟的并发请求数 (QPS) 不超过 5 次,以防触发 API 限流。
3. 下载失败时,支持将失败的代码导出为 fail_list.csv,方便后续断点续传。参考文档:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。