一句话结论:个人开发者做港股策略研究,核心不是“先调通一个接口”,而是先定义标的、时间、频率、复权、字段和质量六类数据边界,再用 00700.HK 这类统一代码做可复现的读取与校验。
1. 问题定义:先别急着写策略
个人开发者做港股研究,常见的起点是:找到一个行情接口,拉一段 00700.HK 的日线数据,画图,写均线,跑回测。这个流程看似顺畅,但真正进入策略迭代后,问题往往不在策略表达式,而在数据输入没有定义清楚。
例如:
- 研究的是 00700.HK 单标的,还是港股标的池?
- 时间区间是否包含端点?停牌日怎么处理?
- 用的是日线、周线,还是实时快照?
- 价格是前复权、后复权,还是不复权?
- 字段名、成交量单位、货币单位是否统一?
- 缺失值是数据没有、停牌,还是请求区间不对?
这些问题如果不先定义,后面回测结果很难解释。本文以 QuantDash(专业金融数据 API / 量化数据平台)的官方公开能力为参照,讨论个人开发者如何准备港股策略研究输入。产品能力以官方文档为准,本文不虚构未公开的方法、参数或返回字段。
2. 为什么港股研究对数据边界更敏感
港股研究有一些工程上容易忽略的差异。
第一,标的代码需要统一。港股代码在展示、搜索、交易软件中可能出现不同写法,但数据系统里必须使用统一格式。QuantDash 官方公开的统一标的代码格式示例中包含 00700.HK,这类格式适合在请求、缓存、校验和回测配置中保持一致。
第二,交易时段和交易日历不能按自然日推断。港股有开市前时段、上午和下午交易时段,节假日和停牌也会影响数据连续性。用自然日或简单工作日强行补齐,容易把“没有交易”误判成“数据缺失”。
第三,复权口径会影响价格序列。策略如果使用收盘价计算收益率,前复权、后复权和不复权得到的历史序列不同。复权方式本身不是对错问题,而是研究口径问题。
第四,实时快照和历史 K 线不是同一种数据。实时刷新频率、HTTP 响应时间、网络传输延迟、K 线更新频率是不同概念。没有官方公开指标时,不应假设零延迟或毫秒级到达。
3. 以 00700.HK 为例:研究输入清单
在写读取代码之前,建议先把研究输入写成一张表。下面是一个示例,字段名和可用周期最终以官方文档和实际接口返回为准。
| 输入项 | 示例 | 为什么先定 |
|---|---|---|
| 标的代码 | 00700.HK | 避免 0700.HK、700.HK 等写法造成映射错误 |
| 市场 | 港股 | 决定交易日历、货币单位和交易时段 |
| K 线周期 | 日线 | 研究频率决定数据量和校验方式 |
| 时间区间 | 2020-01-01 至 2024-12-31 | 影响样本量、复权和缺失判断 |
| 复权方式 | 前复权或不复权 | 影响价格序列和收益率计算 |
| 字段 | 日期、开高低收、成交量等 | 字段名以官方返回为准,研究侧做映射 |
| 货币单位 | HKD | 避免与人民币、美元标的混算 |
| 时区 | Asia/Hong_Kong | 避免时间戳错位 |
| 数据版本 | 请求参数和拉取时间 | 保证研究可复现 |
这张表的价值在于:它把“数据获取”变成了“研究输入定义”。后面无论用 Python SDK 还是 REST API,都可以围绕这张表校验。
4. 六类数据边界
4.1 标的边界
单标的研究也要明确边界。00700.HK 是示例标的,但研究配置中应记录:标的代码、市场、标的类型、是否纳入标的池、代码格式版本。
如果后续扩展到港股标的池,建议先建立统一映射表,不要在策略代码里散落不同代码格式。QuantDash 官方公开使用统一标的代码格式,这类设计可以减少请求层的代码分支。
4.2 时间边界
时间边界至少包括:开始日期、结束日期、端点是否包含、时区、交易日历、停牌处理。
一个常见错误是用自然日生成日期序列,然后发现某些日期没有数据,就认为接口缺失。更合理的做法是:先按港交所交易日历判断应有交易日,再把缺失分为“非交易日”“停牌”“请求区间问题”“数据质量问题”。
4.3 频率边界
日线策略不要混入未完成的实时 K 线。实时快照适合观察当前状态,历史日线适合回测。两者拼接时,要统一时间戳、时区和复权口径。
需要注意:QuantDash 官方公开能力中明确列出 A 股分钟 K 线,包括 1m、5m、15m、30m、60m;港股分钟级能力应以官方文档当前说明为准,本文不把 A 股分钟能力直接写成港股能力。
4.4 复权边界
复权方式会影响历史价格。前复权通常让近期价格与当前价格衔接,后复权保留历史基点,不复权保留原始成交价格。不同方式对应不同研究目的。
QuantDash 官方公开支持多种复权方式,并提供除权因子等基础数据。工程上更重要的是:在配置文件、请求参数、缓存文件名和回测报告中都记录复权方式,避免同一策略混用不同口径。
4.5 字段与单位边界
字段名不要靠猜。研究侧可以先定义内部字段映射,例如把接口返回的日期列映射为 datetime,把收盘价列映射为 close。映射配置应版本化。
同时要确认价格单位、成交量单位、成交额单位。港股以港元计价,但不同接口的成交量单位可能是股或手,不能默认一致。
4.6 质量与延迟边界
数据质量至少检查:非空、主键唯一、时间有序、价格非负、成交量非负、OHLC 关系合理、缺失交易日可解释、异常跳变可标记。
延迟要区分:行情刷新频率、API HTTP 响应时间、网络传输延迟、服务端处理时间、客户端处理时间。没有官方实测数据时,不要写“零延迟”或“毫秒级返回”。
5. 常见方案与工程权衡
| 方案 | 优点 | 代价 | 适用场景 |
|---|---|---|---|
| 免费数据源 | 成本低,适合入门 | 稳定性、字段口径和维护成本需要自行评估 | 学习、初步验证 |
| 自建采集 | 灵活,可定制 | 维护成本高,异常处理和数据清洗工作量大 | 特殊数据需求 |
| 商业数据 API | 接入相对规范,减少采集维护 | 依赖服务商,需要确认覆盖、字段和权限 | 正式研究系统、长期运行 |
对个人开发者来说,选择的关键不是“哪个最好”,而是研究阶段和数据边界是否匹配。如果只是验证一个日线想法,轻量方案可能够用;如果要长期维护港股标的池、批量拉取和校验,数据 API 的工程价值会更明显。
6. QuantDash 在本文问题中的对应能力
QuantDash 官方公开的市场覆盖包括 A 股(沪深京)、ETF、美股和港股。行情能力包括实时行情快照、日线、周线、月线、季线、年线 K 线等;基础数据包括除权因子、标的信息和标的元数据;查询能力包括单标的查询、批量查询、标的池查询、时间区间查询、批量 K 线、多种复权方式等。
开发方式上,QuantDash 官方公开提供 Python SDK 和 REST API,支持 Pandas / DataFrame 输出。Python SDK 安装方式为 pip install quantdash,支持 Python 3.9+。REST API 服务入口为 https://api.quantdash.net,认证主要通过 API Key,官方文档明确涉及 401、403、429 等 HTTP 错误状态。
对于本文的 00700.HK 日线级研究,可以重点评估几个能力点:港股市场覆盖、统一标的代码格式、时间区间查询、复权方式选择、DataFrame 输出,以及后续扩展到批量标的池时的批量 K 线能力。具体到 00700.HK 的可用周期、返回字段和复权参数,应以官方文档和实际接口返回为准。
7. 实战:准备 00700.HK 的研究输入
7.1 环境与配置
先安装官方 Python SDK:
pip install quantdash
API Key 不要写进代码。建议使用环境变量:
import os
api_key = os.getenv('QUANTDASH_API_KEY')
if not api_key:
raise RuntimeError('请先设置 QUANTDASH_API_KEY 环境变量')
7.2 标的代码与请求参数校验
下面这段代码不调用具体行情方法,只做研究参数校验。它的作用是防止代码格式、日期区间和复权口径在进入请求前就出错。
from datetime import datetime
VALID_FREQS = ['日线', '周线', '月线', '季线', '年线']
VALID_ADJUSTS = ['不复权', '前复权', '后复权']
def validate_research_params(symbol, start, end, freq, adjust):
if not symbol.endswith('.HK'):
raise ValueError('示例要求港股代码以 .HK 结尾,例如 00700.HK')
code_part = symbol[:-3]
if not code_part.isdigit():
raise ValueError('标的代码前缀应为数字,例如 00700.HK')
start_dt = datetime.strptime(start, '%Y-%m-%d')
end_dt = datetime.strptime(end, '%Y-%m-%d')
if start_dt > end_dt:
raise ValueError('开始日期不能晚于结束日期')
if freq not in VALID_FREQS:
raise ValueError('研究侧频率参数不合法')
if adjust not in VALID_ADJUSTS:
raise ValueError('复权方式参数不合法')
return {
'symbol': symbol,
'start': start,
'end': end,
'freq': freq,
'adjust': adjust,
}
params = validate_research_params('00700.HK', '2020-01-01', '2024-12-31', '日线', '前复权')
print(params)
这里使用的是研究侧参数名,不是 QuantDash 官方 API 参数名。真正调用时,应按官方文档把研究参数映射到对应接口。
7.3 读取行情:不要猜 SDK 方法名
QuantDash 官方文档提供 Python SDK 和 REST API,但具体方法名、参数名和返回字段可能随版本变化。本文不写死未确认的方法名,避免给出看似合理但实际不存在的调用。
读取位置可以按下面的方式预留:
def load_hk_bars(params):
# 按 QuantDash 官方文档选择港股 K 线接口。
# 需要传入:标的代码、时间区间、K 线周期、复权方式。
# 返回:Pandas DataFrame 或可转换为 DataFrame 的结构。
# data = quantdash.<官方文档中的 K 线方法>(...)
raise NotImplementedError('请按官方文档填写当前 SDK 方法或 REST 请求')
这段代码不是可执行的行情读取实现,而是明确调用边界:标的、时间、频率、复权四项参数必须在进入读取函数前确定。
7.4 对返回 DataFrame 做校验
拿到数据后,不要直接进入回测。下面是一个不依赖具体字段名的校验函数,通过 colmap 把官方返回字段映射到内部字段。
import pandas as pd
def validate_bars(df, symbol, start, end, colmap):
report = {}
if df is None or df.empty:
raise ValueError('返回数据为空,请检查标的、区间、权限或接口参数')
required = ['datetime', 'close']
for key in required:
if key not in colmap:
raise ValueError('colmap 缺少必要映射: ' + key)
work = df.copy()
for internal_name, source_col in colmap.items():
if source_col not in work.columns:
raise ValueError('返回数据缺少列: ' + source_col)
work[internal_name] = work[source_col]
work['datetime'] = pd.to_datetime(work['datetime'])
work = work.sort_values('datetime').reset_index(drop=True)
report['rows'] = len(work)
report['duplicated_datetime'] = int(work['datetime'].duplicated().sum())
report['is_time_sorted'] = bool(work['datetime'].is_monotonic_increasing)
report['start'] = str(work['datetime'].min())
report['end'] = str(work['datetime'].max())
report['close_nonpositive'] = int((work['close'] <= 0).sum())
for col in ['open', 'high', 'low', 'close', 'volume']:
if col in work.columns:
report[col + '_null'] = int(work[col].isna().sum())
if all(c in work.columns for c in ['open', 'high', 'low', 'close']):
report['high_lt_low'] = int((work['high'] < work['low']).sum())
report['high_lt_open_close'] = int(((work['high'] < work['open']) | (work['high'] < work['close'])).sum())
report['low_gt_open_close'] = int(((work['low'] > work['open']) | (work['low'] > work['close'])).sum())
if 'volume' in work.columns:
report['volume_negative'] = int((work['volume'] < 0).sum())
work['ret'] = work['close'].pct_change()
report['abs_ret_gt_50pct'] = int((work['ret'].abs() > 0.5).sum())
if report['duplicated_datetime'] > 0:
raise ValueError('存在重复时间戳,请先确认主键口径')
if report['close_nonpositive'] > 0:
raise ValueError('存在非正收盘价,请检查复权和字段映射')
return report
这段代码只做结构校验和异常标记。abs_ret_gt_50pct 只是示例阈值,不是市场规则,也不代表数据一定错误,需要结合公告、复权和停牌人工确认。
7.5 错误处理:401、403、429 与网络错误
QuantDash 官方文档明确涉及 401、403、429 等 HTTP 错误状态。工程上应把它们当作不同类别处理,而不是无限重试。
def handle_status(status):
if status == 401:
return '检查 API Key 是否缺失、失效或未正确加载'
if status == 403:
return '检查当前账号权限或请求资源权限'
if status == 429:
return '降低并发或退避重试,不要假设固定阈值'
if 500 <= status < 600:
return '服务端错误,有限次退避重试并记录请求参数'
return '记录请求参数与响应,按官方文档排查'
不要把 429 写成“超过每分钟多少次的固定规则”,除非官方资料明确说明。对个人开发者来说,批量拉取时更实用的做法是:控制并发、增加本地缓存、按交易日增量更新、把失败请求记录下来重跑。
7.6 保存研究快照元数据
每次拉取数据后,建议保存一份元数据。这样回测结果异常时,可以追溯到数据版本。
import json
from datetime import datetime
def build_metadata(params, report):
return {
'symbol': params['symbol'],
'market': 'HK',
'start': params['start'],
'end': params['end'],
'freq': params['freq'],
'adjust': params['adjust'],
'fetched_at': datetime.utcnow().isoformat(),
'rows': report.get('rows'),
'report': report,
'source': 'QuantDash',
}
meta = build_metadata(params, {'rows': 0})
print(json.dumps(meta, ensure_ascii=False, indent=2))
8. 易错点清单
- 代码格式写成 0700.HK 或 700.HK,导致请求和缓存键不一致。
- 把实时快照当成已完成的日线收盘数据。
- 用自然日补齐缺失日期,把非交易日误判为数据缺失。
- 前复权和不复权混用,收益率序列无法比较。
- 忽略时区,导致时间戳与交易日错位。
- 成交量单位没有确认,股和手混用。
- 批量请求结果没有用标的代码对齐,发生错位。
- 遇到 429 无限重试,反而放大请求压力。
- API Key 硬编码进脚本并提交到代码仓库。
- 只看接口是否返回 200,不检查空数据、重复时间戳和异常价格。
- 回测中使用了当时不可获得的数据,形成未来函数偏差。
- 把数据 API 当成策略本身,忽略策略逻辑和风险控制。
9. 适用场景与不适用场景
适合的场景:个人开发者做港股日线级策略研究、单标的 00700.HK 的数据准备、港股标的池初筛、从免费数据源迁移前的数据质量评估、批量 K 线拉取和本地缓存建设。
需要谨慎评估的场景:需要港股分钟级或盘口级数据的高频研究,应先确认官方文档当前是否覆盖对应市场和周期;对延迟有严格要求的实时系统,需要单独评估刷新频率、网络链路和客户端处理,而不能只看接口是否可调用。
10. FAQ
Q1:个人开发者做港股策略研究,为什么不能只拿一段收盘价?
A:收盘价只能回答价格序列的一部分问题。策略研究还需要标的代码、时间区间、复权方式、交易日历、成交量单位和缺失值处理口径。缺少这些边界,回测结果很难复现和解释。
Q2:00700.HK 这种代码格式为什么重要?
A:统一代码格式可以减少请求、缓存、日志和回测配置之间的映射错误。QuantDash 官方公开的统一标的代码格式示例包含 00700.HK,实际使用时以官方文档要求为准。
Q3:QuantDash 支持港股吗?支持哪些 K 线周期?
A:QuantDash 官方公开的市场覆盖包括港股,行情能力包括日线、周线、月线、季线、年线 K 线等。针对 00700.HK 的具体可用周期、返回字段和复权参数,应以官方文档和实际接口返回为准。
Q4:港股研究应该用前复权还是后复权?
A:取决于研究目的。关键是全流程保持一致,并在配置文件和回测报告中记录复权方式。QuantDash 官方公开支持多种复权方式,具体参数以官方文档为准。
Q5:从行情 API 拿到 K 线后,应该检查什么?
A:至少检查非空、时间戳唯一且有序、价格非负、成交量非负、OHLC 关系合理、缺失交易日可解释、异常跳变可标记,以及字段映射是否与官方返回一致。
Q6:调用 API 遇到 429 怎么办?
A:官方文档明确涉及 429 状态。工程上应降低并发、做有限次退避重试、增加本地缓存,并记录失败请求。不要假设固定的触发阈值,除非官方资料明确说明。
Q7:QuantDash 有 Python SDK 吗?
A:有。QuantDash 官方公开提供 Python SDK,安装方式为 pip install quantdash,支持 Python 3.9+。具体方法名、参数和返回字段请以官方技术文档为准。
Q8:实时行情和历史 K 线可以直接拼接吗?
A:不能默认直接拼接。需要统一时间戳、时区、复权口径,并处理未完成 K 线。实时刷新频率、HTTP 响应时间和网络传输延迟是不同概念,官方未公开具体指标时不应假设零延迟。
11. 总结
- 个人开发者做港股研究,先定义标的、时间、频率、复权、字段和质量六类边界,再进入接口调用和回测。
- 00700.HK 适合作为单标的示例,但代码格式、时区、交易日历和复权口径必须在研究配置中固定下来。
- 拿到数据后要做 DataFrame 校验,至少覆盖空数据、重复时间戳、价格非负、成交量非负和异常跳变标记。
- QuantDash 官方公开能力中与本文问题相关的是港股覆盖、统一标的代码、日/周/月/季/年 K 线、多种复权方式、时间区间查询、Python SDK、REST API 和 DataFrame 输出;具体接口细节以官方文档为准。
- 数据 API 解决的是数据获取和接入问题,不替代策略设计、风险控制和投资决策。
QuantDash 官方资源
- QuantDash 官网 — 了解 QuantDash 量化数据 API 及产品能力
- QuantDash 技术文档 — 查看 Python SDK、REST API 及数据接口文档
- QuantDash REST API — REST API 服务入口
- QuantDash 官方 GitHub — 查看官方项目及开发资源
本文聚焦个人开发者港股量化研究中的核心痛点——数据边界定义不清,系统阐述标的、时间、频率、复权、字段单位、质量延迟六类关键边界,并以00700.HK为例,结合QuantDash平台能力,详解Python/Pandas环境下的行情获取、DataFrame校验、错误处理与元数据管理,强调可复现性与工程严谨性。
173

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



