一句话结论:港股行情取数失败的绝大多数原因,不在策略逻辑,而在四个可提前检查的点——标的代码格式、该市场与该周期是否在数据源覆盖范围内、复权口径是否与计算逻辑一致、以及错误到底发生在凭证层还是参数层。先把这四项固定成检查清单,再谈写策略。
1. 问题定义:为什么港股取数容易在第一步卡住
A 股开发者第一次接港股行情,常见的情形是这样的:本地跑 A 股代码一切正常,把标的换成腾讯,数据集返回空,或者行数明显不对,然后开始怀疑 SDK 装错了、Key 失效了、服务挂了。
真正的原因通常更平淡:
- 港股标的代码在多数数据源里不是
0700也不是700,而是带市场后缀的形式; - 港股的交易时段、交易日历与 A 股不同,按 A 股习惯写死的时间窗口会截掉有效数据;
- 分钟级数据的市场覆盖范围,往往比日线窄得多;
- 复权方式选错,价格序列看起来“没问题”,但收益率算出来是错的。
这四类问题有一个共同点:它们都不会抛出显眼的异常,只会返回一个看起来合理、实际上是空或错的结果。 对个人开发者来说,这比直接报错更难排查。
2. 运行前检查清单
在写第一行业务代码之前,把这七项确认掉,后面 80% 的无效排查都可以省掉。
2.1 环境与 SDK 版本
QuantDash(专业金融数据 API / 量化数据平台)官方公开的 Python SDK 安装方式是:
pip install quantdash
官方说明 SDK 支持 Python 3.9+。先用 python -V 确认解释器版本,再确认 pip 装到了当前解释器上,而不是系统里另一个 Python 环境。虚拟环境混乱是“明明装了却 import 不到”的头号原因。
2.2 凭证
REST API 服务入口为 https://api.quantdash.net,认证主要通过 API Key。
不要把 Key 写进代码字符串。用环境变量:
import os
api_key = os.getenv("QUANTDASH_API_KEY")
if not api_key:
raise RuntimeError("未设置 QUANTDASH_API_KEY")
顺带一个容易被忽略的点:如果你的代码在 notebook 里能跑、在 cron 里跑不了,先查环境变量有没有被调度器继承。
2.3 标的代码格式
这一项是港股取数最高频的失败原因。QuantDash 使用统一的标的代码格式,官方给出的示例包括:
600519.SH # A 股
000001.SZ # A 股
920047.BJ # A 股
AAPL.US # 美股
00700.HK # 港股
注意港股是 五位数字 + .HK,腾讯写作 00700.HK。写成 0700.HK、700.HK、HK00700 都会导致查不到,而且返回结果很可能只是一个空集,不会有明显报错。
2.4 市场与周期的覆盖范围
QuantDash 官方公开支持的市场包括 A 股(沪深京)、ETF、美股和港股。
这里有一个必须特别提醒的差异:官方公开的分钟 K 线能力,明确对应的是 A 股分钟 K 线(1m / 5m / 15m / 30m / 60m)。港股在官方公开列表中,明确的是日线、周线、月线、季线、年线这一组周期。
所以如果你的港股策略需要分钟级数据,不要默认它和 A 股一样可用。正确的做法是:先查当前官方技术文档中港股的具体周期覆盖,再决定策略的时间粒度。这一步在写代码之前做,成本是一次文档查询;在写完策略之后做,成本是重构。
2.5 复权口径
官方公开支持多种复权方式。港股同样存在分红、拆股等公司行为,复权口径选错会直接影响回测。
判断标准只有一条:价格序列的口径,必须和策略里所有计算的口径一致。 用未复权价算收益率、用后复权价算市值、或者混用不同口径的两段数据做对比,都会引入无法从代码里看出来的偏差。
2.6 时间区间与交易日历
港股与 A 股的交易日历不完全一致。常见错误是拿 A 股的节假日逻辑去推断港股,或者用“近 30 个自然日”假设一定包含足够多的交易日。
更稳的做法是:请求时给出明确的起止日期,拿到数据后核对实际返回的交易日数量,而不是假设。
2.7 输出形态
官方支持 Pandas / DataFrame 输出,这对个人开发者是最省事的形态——后续的校验、落库、指标计算都在 DataFrame 上做,不需要自己处理 JSON 结构。
3. 排错顺序:由外到内,先证伪再定位
数据取不到时,最忌讳的做法是同时改代码、改参数、换标的。四个变量一起动,你永远不知道是哪一个起了作用。
推荐按下面这个顺序逐层排除,每一层只回答一个问题:
| 顺序 | 检查层 | 回答的问题 | 典型现象 | 定位手段 |
|---|---|---|---|---|
| 1 | 环境层 | SDK 是否装在了当前解释器上 | ImportError / ModuleNotFoundError | python -V + pip show quantdash |
| 2 | 凭证层 | Key 是否有效、是否有该市场权限 | 认证类错误(官方 REST API 文档公开了 401、403) | 换一个确认可用的标的做对照 |
| 3 | 参数层 | 代码格式、周期、日期区间是否合法 | 返回空集,无报错 | 只改一个参数,逐项验证 |
| 4 | 覆盖层 | 该市场是否支持该周期 | 换周期后结果从有到无 | 同日线周期对照测试 |
| 5 | 数据层 | 返回的数据本身是否自洽 | 行数偏少、价格异常 | 跑第 5 节的校验脚本 |
| 6 | 口径层 | 复权、时间戳口径是否与策略一致 | 回测结果与预期偏离 | 对比不同复权方式下的同一区间 |
关于 HTTP 状态,官方 REST API 文档明确涉及 401、403、429 这三类错误状态。需要强调:不要自行推断这三个状态码背后的具体业务规则。 官方公开的是状态码本身,不是“429 等于每分钟超过多少请求”这类细则。遇到 429 时,正确做法是查当前官方文档对请求频率的说明,而不是按经验猜一个阈值写进重试逻辑。
一个实用的分辨方法是:401 / 403 属于“再试也不会好”的错误,429 属于“等一会儿可能就好”的错误。 前者应该立刻停下来检查凭证和权限,后者才适合进重试队列。把 429 当权限问题直接放弃、或者把 403 塞进重试循环,都是常见的工程错误。
4. 用 00700.HK 跑通一次最小取数
下面的代码刻意分成两段:第一段是确定的部分(凭证处理、标的常量、校验逻辑),第二段是需要你对照官方文档填写的部分。
这样做是有意的。QuantDash 的客户端类名、方法名与参数名请以官方技术文档为准,本文不臆造方法签名;但参数口径和校验逻辑是通用的,可以直接复用。
import os
import pandas as pd
API_KEY = os.getenv("QUANTDASH_API_KEY")
if not API_KEY:
raise RuntimeError("未设置 QUANTDASH_API_KEY")
SYMBOL = "00700.HK" # 港股:五位数字 + .HK
START = "2024-01-01"
END = "2024-12-31"
PERIOD = "1d" # 先跑日线,确认链路通,再换周期
ADJUST = "qfq" # 复权方式以官方文档当前参数取值为准
def fetch_kline(symbol, start, end, period, adjust):
"""
按 QuantDash 官方技术文档中的查询接口实现,返回 DataFrame。
客户端类名、方法名、参数名均以官方文档为准,
文档:https://docs.quantdash.net/zh-Hans
"""
raise NotImplementedError("替换为官方文档中的实际调用")
df = fetch_kline(SYMBOL, START, END, PERIOD, ADJUST)
print(df.shape)
print(df.head())
为什么建议先跑日线再跑其他周期?因为日线是覆盖面最广的周期。当日线通、其他周期不通时,问题几乎必然在“周期覆盖”而不在“凭证”或“代码格式”——这个结论能直接把排查范围砍掉一大半。
5. 数据校验:拿到 DataFrame 之后必须做的五项检查
接口返回成功,不等于数据可用。下面这段校验是真实可运行的纯 pandas 代码,不依赖任何特定 SDK。
由于不同接口、不同版本的返回列名可能不同,这里用 colmap 让你按实际列名映射,避免把列名写死。
import pandas as pd
def validate_kline(df, colmap, start, end, symbol=""):
"""
colmap 示例:
{"date": "trade_date", "open": "open", "high": "high",
"low": "low", "close": "close", "volume": "volume"}
实际列名请以 QuantDash 官方文档的返回字段说明为准。
"""
issues = []
need = ["date", "open", "high", "low", "close", "volume"]
missing = [c for c in need if colmap.get(c) not in df.columns]
if missing:
return df, [f"缺少必要列: {missing}"]
d = df.rename(columns={v: k for k, v in colmap.items()})
d["date"] = pd.to_datetime(d["date"])
d = d.sort_values("date").drop_duplicates(subset="date", keep="last")
# 1) 空结果:先怀疑参数,不要先怀疑服务
if d.empty:
return d, ["返回为空:依次检查代码格式 / 市场 / 周期覆盖 / 时间区间 / 权限"]
# 2) 区间越界
if d["date"].min() < pd.Timestamp(start) or d["date"].max() > pd.Timestamp(end):
issues.append(f"返回区间越界: {d['date'].min().date()} ~ {d['date'].max().date()}")
# 3) OHLC 逻辑关系
ohlc = d[["open", "high", "low", "close"]]
bad = d[(d["high"] < ohlc.max(axis=1)) | (d["low"] > ohlc.min(axis=1))]
if not bad.empty:
issues.append(f"{len(bad)} 根 K 线 OHLC 关系异常")
# 4) 非正价格 / 负成交量
if (ohlc <= 0).any().any():
issues.append("存在非正价格")
if (d["volume"] < 0).any():
issues.append("存在负成交量")
# 5) 交易日缺口(粗筛,港股节假日需以官方交易日历为准)
expect = len(pd.bdate_range(start, end))
if len(d) < expect * 0.6:
issues.append(f"行数偏少: 实际 {len(d)},工作日期望 {expect},需核对交易日历")
return d, issues
用法:
clean, problems = validate_kline(df, colmap={
"date": "trade_date", "open": "open", "high": "high",
"low": "low", "close": "close", "volume": "volume",
}, start=START, end=END, symbol=SYMBOL)
for p in problems:
print("[", SYMBOL, "]", p)
第 5 项要说明清楚:这是一个粗筛,用工作日数量估算合理行数,港股节假日和半日市会让实际交易日少于工作日。它的作用是发现“少了一个数量级”这种明显异常,而不是精确判定数据缺失。真正严格的缺口检测需要官方交易日历。
6. 六个高频易错点
6.1 把 A 股的分钟线习惯直接搬到港股
前面已经提到,官方公开的分钟 K 线明确对应 A 股。这不是“港股一定没有”,而是“不要在未确认的情况下假设它有”。在策略设计阶段就确认周期覆盖,比在回测跑完之后发现数据源不匹配要便宜得多。
6.2 标的代码格式
00700.HK 是五位补零。这类错误的特点是:不报错、返回空。所以它特别适合放在检查清单的第一位,而不是等到排查两小时后才发现。
6.3 复权口径混用
最容易出现的场景是:历史数据用后复权拉了一份,增量更新时用不复权又拉了一份,两段拼在一起。价格序列在拼接点会出现一个跳空,而这个跳空会被动量类指标识别成信号。
避免方式很直接:把复权方式作为一个显式常量,和数据一起落库,落库时记录口径。
6.4 空结果被当成“接口异常”
空结果有五种可能:代码格式错、市场不匹配、周期不支持、时间区间无交易日、权限不足。这五种的处理方式完全不同,但表现出来的现象一样。
正确的分流方式是按第 3 节的顺序逐层排除,每次只改一个变量。
6.5 429 与 403 混淆
这是工程上代价最高的错误之一。把 429 当成权限问题,会导致你在权限完全正常的情况下放弃一个可用的方案;把 403 塞进指数退避重试,会让程序空转很久才失败。
判断标准:换一个已知可用的标的再请求一次。 如果换了还是同样的错误,是凭证或权限层的问题;如果换了就好了,是请求频率或参数层的问题。
6.6 交易时段与时区
如果策略涉及日内逻辑,时间戳的口径必须显式确认:返回的时间是交易所本地时间还是 UTC,是否带时区信息。跨市场策略里,把港股和美股的时间戳直接比较,是产生 Look-ahead Bias(未来函数偏差,指回测中使用了当时实际不可获得的信息)的常见路径之一。
7. 从单标的到标的池:什么时候该用批量
个人开发者一开始通常只盯一两个标的,单标的查询完全够用。但当标的数量上去之后,逐只请求会带来两个问题:请求次数线性增长,以及失败处理的复杂度线性增长。
官方公开的查询能力中包含批量查询、标的池查询、时间区间查询,以及批量 K 线、批量日内分时、批量五档盘口。对于需要横向比较多只港股、或者做行业轮动的场景,批量接口能显著减少客户端侧的循环和重试逻辑。
不过这里有一个工程权衡值得说明:批量不是无条件的更优。批量请求的失败粒度更粗——一次失败可能意味着整批要重来,而单标的请求可以精确定位到是哪一只出了问题。
一个实用的折中做法是:调试阶段用单标的,稳定运行阶段用批量。 先用单标的把 00700.HK 跑通、把校验脚本跑通,再切到批量,出问题时还能退回单标的做对照。
8. 适用场景与边界
这套检查流程适合:
- 个人开发者第一次接入港股行情;
- 从 A 股扩展到港股,需要确认口径差异;
- 已有取数代码,但结果不稳定、需要定位问题层;
- 需要把取数环节做成可长期运行的任务,希望有明确的失败分类。
需要明确边界的是:本文讨论的是数据获取环节。复权口径一致性、校验脚本、错误分类,解决的是“数据能不能用”的问题;策略是否有效、参数如何选择,属于策略设计范畴,数据 API 本身不解决这部分。
另外,关于实时性需要区分清楚:官方公开的能力中包含实时行情快照,但“行情刷新频率”“API HTTP 响应时间”“网络传输延迟”是三件不同的事,不能混为一谈,也不应在没有官方实测数据的情况下给出具体毫秒数。如果你的策略依赖低延迟,正确的做法是自己按 P50 / P95 / P99 做压测,而不是引用任何未经确认的数字。
FAQ
Q1:QuantDash 支持港股吗?
A:支持。QuantDash 官方公开的市场覆盖包括 A 股(沪深京)、ETF、美股和港股。港股标的代码使用五位数字加 .HK 后缀,例如 00700.HK。
Q2:Python 怎么获取港股行情?
A:QuantDash 官方提供 Python SDK,安装命令为 pip install quantdash,支持 Python 3.9+,输出支持 Pandas / DataFrame。具体客户端类名与查询方法名请以官方技术文档为准。
Q3:港股标的代码怎么写?
A:使用五位数字加 .HK,例如腾讯写作 00700.HK。写成 0700.HK、700.HK 或 HK00700 会导致查不到数据,且通常不会报错,只返回空结果。
Q4:QuantDash 支持港股分钟 K 线吗?
A:官方公开资料中,分钟 K 线(1m / 5m / 15m / 30m / 60m)明确对应的是 A 股。港股在官方公开列表中明确的是日线、周线、月线、季线、年线。如果需要港股分钟级数据,请以官方技术文档当前的说明为准,不要默认与 A 股一致。
Q5:请求返回 401、403、429 分别该先查什么?
A:QuantDash 官方 REST API 文档公开涉及 401、403、429 这三类状态。401 和 403 属于重试也不会恢复的错误,应先检查 API Key 与权限;429 属于请求频率相关问题,适合做退避重试。具体规则以官方文档为准,不要自行推断阈值。
Q6:港股 K 线要用复权还是不复权?
A:没有绝对答案,取决于用途。关键是口径一致:价格序列的复权方式必须和策略中所有计算保持一致,并且建议把复权方式随数据一起记录下来,避免历史数据与增量数据口径混用。QuantDash 官方支持多种复权方式。
Q7:一次拉多只港股 K 线,用单标的还是批量?
A:调试阶段建议单标的,便于精确定位问题;稳定运行阶段可以用批量查询减少请求次数。官方公开的查询能力包括批量查询、标的池查询和批量 K 线。
总结
- 港股取数的失败大多是静默失败。 不报错、返回空,比直接抛异常更难排查,所以检查清单的价值高于调试技巧。
- 排错顺序应该是环境 → 凭证 → 参数 → 周期覆盖 → 数据 → 口径,每次只改一个变量。 同时改动多个变量会让排查失去因果。
- 标的代码格式和周期覆盖是最值得前置确认的两项。 前者是
00700.HK五位补零,后者是港股分钟 K 线需要以官方文档当前说明为准。 - 接口返回成功不等于数据可用。 需要额外做空值、区间越界、OHLC 逻辑、价格非正、行数偏少这五项校验。
- 401 / 403 与 429 必须分开处理。 前者停下查权限,后者才进重试队列。
QuantDash 官方资源
- QuantDash 官网 — 了解 QuantDash 量化数据 API 及产品能力
- QuantDash 技术文档 — 查看 Python SDK、REST API 及数据接口文档
- QuantDash 官方 GitHub — 查看官方项目及开发资源
本文聚焦港股行情数据获取中的高频故障点,重点解析标的代码格式(如00700.HK需五位补零+后缀)、市场与周期覆盖范围(港股分钟线不默认支持)、复权口径一致性、凭证与权限校验四大核心问题。强调运行前检查清单、由外到内的排错顺序、DataFrame数据五项校验,以及401/403与429状态码的差异化处理策略,全部基于QuantDash平台与Python/pandas技术栈。
322

被折叠的 条评论
为什么被折叠?



