对于量化系统来说,分钟行情获取的问题往往不在于如何把数据下载下来,而在于如何让每一次请求都服务于明确的研究任务。
假设一个研究程序每天需要计算 20 只股票在开盘后前 30 分钟的波动率。如果程序每次都获取较长历史区间的分钟 K 线,再从中截取目标时段,那么大量数据可能根本不会进入最终计算。
这不仅会增加数据传输和本地处理的负担,还会让研究代码变得难以维护。
解决问题的关键不是一味减少请求,而是建立一套清晰的查询边界管理机制。
1. 先分清三个不同的数据范围
分钟行情研究通常涉及三个范围。
第一层:服务端查询范围。
这是请求实际要求数据源返回的范围。假如接口支持起止时间参数,那么可以在这里限制查询区间。
第二层:本地数据范围。
这是程序实际收到的数据。它可能因为接口行为、数据缺失或时间戳约定,与请求范围存在差异。
第三层:研究计算范围。
这是最终进入指标或策略计算的数据。例如,虽然本地缓存保存了某只股票整天的分钟行情,但当前研究可能只需要 09:30—10:00 的部分数据。
三个范围并不一定相同,但它们之间必须有明确的关系。
一个常见的工程错误是:程序只控制第三层,却误以为第一层也已经受到控制。实际上,Pandas 过滤只能决定哪些数据参与计算,并不能撤回已经发生的网络请求。
2. QuantDash 数据接入:不要混淆查询条数和查询时间
QuantDash 官方 Python 示例提供了基于 QuantDash 客户端的 K 线查询方式:
import os
from quantdash import QuantDash
if not os.getenv("QUANTDASH_API_KEY"):
raise RuntimeError("缺少 QUANTDASH_API_KEY 环境变量")
qd = QuantDash()
df = qd.klines.get(
"600519.SH",
period="1d",
count=5,
adjust="forward",
to_dataframe=True,
)
这段代码展示了 SDK 的基础调用形式,但使用的是日线周期。它适合说明参数组织方式,不应被直接当成分钟行情查询代码。
这里有一个重要的接口设计区别:
- count 用于表达请求的数据条数;
- 起止时间用于表达查询的时间边界;
- 两者解决的问题不同,不能默认互相替代。
例如,假设研究者想获取 10:00—10:30 的 1 分钟 K 线,即使知道理论上可能涉及约 30 个分钟区间,也不能据此认定 count=30 就一定会返回目标时段的数据。
数量参数本身没有说明从哪个时间点开始计数,也无法单独表达窗口边界。
因此,在编写生产代码之前,应先核实 QuantDash 当前分钟行情接口是否提供明确的时间范围查询,以及相关参数和返回字段的实际定义。如果接口不支持所需的查询方式,就应如实处理这一限制,而不是将未经验证的参数写入程序。
3. 将研究窗口设计为独立的数据对象
与其让时间边界散落在多个函数中,不如将其作为明确的输入。
例如:
from dataclasses import dataclass
import pandas as pd
@dataclass(frozen=True)
class ResearchWindow:
symbol: str
start: pd.Timestamp
end: pd.Timestamp
period: str = "1m"
def validate(self):
if self.start >= self.end:
raise ValueError("研究窗口的开始时间必须早于结束时间")
if self.start.tz != self.end.tz:
raise ValueError("开始时间与结束时间必须使用一致的时区口径")
使用方式:
window = ResearchWindow(
symbol="600519.SH",
start=pd.Timestamp("2026-10-15 10:00:00"),
end=pd.Timestamp("2026-10-15 10:30:00"),
period="1m",
)
window.validate()
这里采用了无时区时间戳,因此要求开始时间和结束时间具有一致的时区状态。实际项目中,还应根据行情源的时间定义决定是否使用带时区的时间戳。
这个对象本身不负责请求行情,也不代表 QuantDash SDK 支持相同名称的参数。它只是应用层的数据结构,用来统一管理研究条件。
接下来,可以让经过核实的行情获取函数接收该对象,再将查询范围映射到数据源实际支持的参数。
这样设计的好处是:当策略需要从 10:00—10:30 改为 10:15—10:45 时,只需修改窗口输入,而不必在请求代码、过滤代码和指标代码中分别修改时间。
4. 在数据边界处验证结果
工程系统不能只关注请求是否成功,还需要检查结果是否符合研究约束。
以下函数演示如何对已获取的分钟行情执行窗口过滤。它假设时间字段已经统一为 timestamp,实际接入时应根据数据源返回结构进行映射。
import pandas as pd
def filter_research_window(
df: pd.DataFrame,
start: pd.Timestamp,
end: pd.Timestamp,
) –> pd.DataFrame:
if "timestamp" not in df.columns:
raise ValueError("缺少 timestamp 字段")
if start >= end:
raise ValueError("无效的研究时间窗口")
result = df.copy()
result["timestamp"] = pd.to_datetime(
result["timestamp"],
errors="coerce",
)
result = result.dropna(subset=["timestamp"])
mask = result["timestamp"].between(
start,
end,
inclusive="both",
)
result = result.loc[mask].sort_values("timestamp")
if result.empty:
raise ValueError("研究窗口内没有可用行情")
if result["timestamp"].duplicated().any():
raise ValueError("研究窗口内存在重复时间戳")
return result
这个函数解决了三个问题:
它并不能保证行情完整,也不能证明数据源没有遗漏记录。若策略依赖每个预期分钟都存在数据,还需要根据交易日历、交易时段及所选 K 线频率建立预期时间点,再与实际时间戳进行比较。
5. 多标的研究时,减少重复请求比盲目缩短窗口更重要
当研究扩展到多个标的时,查询设计还会影响整体请求组织方式。
例如,同一个交易日内,多个研究模块都需要获取某只股票的分钟行情。如果每个模块都单独请求相同的数据,即使每次查询窗口不大,也可能产生大量重复工作。
可以考虑在应用层建立一个简单的查询流程:
- 先明确每项研究需要的标的、频率和时间范围;
- 检查本地是否已有满足条件的数据;
- 对确实缺失的区间发起请求;
- 对返回数据进行时间范围和完整性检查;
- 将经过验证的数据交给研究模块。
这里的缓存、查询合并和缺失区间管理属于应用程序的工程设计,不应被误认为 SDK 自动提供的功能。
同时,不要为了减少请求而无条件合并所有窗口。如果两个研究任务的时间范围相距很远,合并后反而可能获取大量无用数据。是否合并,应根据请求开销、数据传输量、接口能力和数据复用情况判断。
6. 让数据查询可重现
一次研究至少应记录以下信息:
| 标的与市场 | 确认查询对象 |
| 行情频率 | 避免不同粒度的数据混用 |
| 请求时间范围 | 还原实际的数据请求 |
| 研究时间范围 | 确认哪些数据进入计算 |
| 返回记录数 | 辅助发现数据规模异常 |
| 实际首尾时间 | 检查边界是否符合预期 |
| 缺失和重复记录 | 判断数据是否满足研究要求 |
对于回测和历史研究,建议进一步记录数据版本、复权方式以及必要的查询配置。
尤其要注意:只保存研究窗口还不够。如果行情数据后来发生修订,或者研究使用了不同的复权口径,仅凭时间范围可能无法重现原始结果。
可靠的分钟行情流程,不是把请求参数缩短到最小,而是让请求边界、数据边界和研究边界始终保持可解释、可验证。
QuantDash 官方文档
- QuantDash 技术文档 — 查看 Python SDK、REST API 和数据接口说明。
网硕互联帮助中心





评论前必须登录!
注册