做港股量化前,先检查这 8 个数据细节
作者: TickDB Research · 发布: 2026/5/21 · 阅读: 3
标签: Track A, 知乎, 产品介绍型, 港股
引言:港股量化,策略不难,数据难
做港股量化的人,真正花时间的往往不是写策略,而是跟数据格式较劲。
腾讯到底是 0700.HK 还是 700.HK?为什么有些数据源返回的盘口只有 5 档?半日市那天策略为什么下午还在报警?哪些股票是港股通标的,名单在哪更新?
A 股和美股量化生态相对成熟,数据格式形成了事实标准。港股不一样——香港交易所(HKEX)是单一交易所,但不同数据源之间的格式差异反而更大。原因很简单:港股既有内地资金南下、又有国际资金进出,不同数据商对同一只股票的代码、字段、交易时段的处理方式各不相同。
本文从港股量化开发者的实际接入经验出发,把最常见的 8 个数据细节逐一拆解。每个问题给出错误假设和正确处理,代码可直接运行。
声明:本文代码示例基于 TickDB 公开 API 文档的实测结果,可对照 docs.tickdb.ai 独立复现。TickDB 在 GitHub 开源(MIT 协议),具体服务条款以官方公示为准。
>
金融合规提醒:本文仅讨论行情数据接入与工程实现,不构成任何投资建议。
检查项 #1:港股代码无前导零
错误假设:很多从 A 股或 Yahoo Finance 转过来的开发者,习惯写 0700.HK。
实际情况:港股在港交所的标准代码没有前导零。腾讯是 700,不是 0700。部分数据源内部用了前导零格式,导致开发者形成错误认知。
正确处理:
# 正确:无前导零
symbols = "700.HK,9988.HK,3690.HK"
# 不确定代码时,用品种查询接口确认
# GET https://api.tickdb.ai/v1/symbols/available?market=HK&type=stock&keyword=腾讯
| 股票 | 错误写法 | 正确写法 |
|---|---|---|
| 腾讯 | 0700.HK | 700.HK |
| 阿里巴巴 | 9988.HK | 9988.HK(4位码无需补齐) |
| 美团 | 3690.HK | 3690.HK |
| 小米 | 1810.HK | 1810.HK |
| 中国平安 | 2318.HK | 2318.HK |
工程影响:用错代码格式,API 直接返回 2002(品种不存在),策略根本启动不了。
检查项 #2:午间休市导致分钟线断点
错误假设:港股分钟 K 线和 A 股一样,全天连续。
实际情况:港股有午间休市(12:00-13:00)。1 分钟 K 线在 12:00 的最后一根到 13:00 的第一根之间,隔了一个小时。如果策略做分钟线技术指标计算,这个空档会导致指标失真——比如计算 5 分钟移动均线时,可能把午休前后的价格拉到同一根窗口里。
正确处理:
# 拉分钟 K 线时,按上午/下午分段处理,或过滤掉午休后的前几根 K 线
params = {
"symbol": "700.HK",
"interval": "1m",
"start_time": "当日09:30的时间戳",
"end_time": "当日12:00的时间戳"
}
# 下午段单独拉取,避免跨午休计算指标
工程影响:不处理午休空档,分钟级策略的回测结果会与实盘产生系统性偏差。
检查项 #3:半日市识别
错误假设:港股每天都按 9:30-12:00 / 13:00-16:00 交易。
实际情况:港交所在某些节假日(如圣诞节前夕、除夕)只交易半天(9:30-12:00)。如果策略不知道今天是半日市,下午还会继续尝试下单或报警。
正确处理:策略启动时查询当天交易时段,通过时段数量和结束时间判断是否为半日市:
import requests
url = "https://api.tickdb.ai/v1/market/trading-sessions"
headers = {"X-API-Key": "YOUR_API_KEY"}
params = {"market": "HK"}
resp = requests.get(url, headers=headers, params=params)
data = resp.json()
if data["code"] == 0:
sessions = data["data"][0]["trading_sessions"] # 时段数组
if len(sessions) == 1: # 只有一个时段
print(f"注意:今天是半日市,交易时段 {sessions[0]['begin_time']}-{sessions[0]['end_time']}")
# 策略在非交易时段自动休眠
配合交易日历使用:
# 先判断是否交易日
params = {"market": "HK", "beg_day": "20260520", "end_day": "20260520"}
resp = requests.get("https://api.tickdb.ai/v1/market/trade-days",
headers=headers, params=params)
if not resp.json()["data"]["trade_days"]:
print("今天休市")
工程影响:忽略半日市,策略在节假日前夕下午时段的误操作可能导致实际亏损。
检查项 #4:10 档盘口字段拆解
错误假设:港股盘口只有 5 档,所有数据源格式统一。
实际情况:港股支持 10 档深度盘口(Level2)。盘口数据格式因数据源而异——有的每档是 [价格, 数量] 数组,有的用独立字段,有的 bid 从高到低排列,有的反序。
TickDB 格式确认:
url = "https://api.tickdb.ai/v1/market/depth"
headers = {"X-API-Key": "YOUR_API_KEY"}
params = {"symbol": "700.HK"}
resp = requests.get(url, headers=headers, params=params)
data = resp.json()
if data["code"] == 0:
depth = data["data"]
bids = depth["bids"] # [[价格, 数量], ...] 买价从高到低排列
asks = depth["asks"] # [[价格, 数量], ...] 卖价从低到高排列
# 买一(最高买价)
print(f"买一: 价格{bids[0][0]}, 数量{bids[0][1]}")
# 卖一(最低卖价)
print(f"卖一: 价格{asks[0][0]}, 数量{asks[0][1]}")
# 买卖价差
spread = asks[0][0] - bids[0][0]
print(f"买卖价差: {spread}")
策略常用计算:前 5 档买卖盘口不平衡度:
bid_vol_5 = sum(b[1] for b in bids[:5])
ask_vol_5 = sum(a[1] for a in asks[:5])
imbalance = (bid_vol_5 - ask_vol_5) / (bid_vol_5 + ask_vol_5)
print(f"盘口不平衡度: {imbalance:.3f}")
工程影响:盘口档位结构搞错,高频因子直接报废。
检查项 #5:HKD 计价与汇率折算
错误假设:写死汇率(如 1 HKD = 0.92 CNY),直接用港币价格算盈亏。
实际情况:港股以港币计价。如果你的资金是人民币或美元,港币汇率是波动的。写死汇率意味着盈亏计算存在系统性偏差——长期积累可能差出几个百分点。
正确处理:每次查询港股价格时,同时获取实时汇率:
# 同时查询港股价格和港币汇率
params = {"symbols": "700.HK,USDHKD"}
resp = requests.get("https://api.tickdb.ai/v1/market/ticker",
headers=headers, params=params)
data = resp.json()
if data["code"] == 0:
for item in data["data"]:
if item["symbol"] == "700.HK":
price_hkd = float(item["last_price"])
elif item["symbol"] == "USDHKD":
rate = float(item["last_price"])
price_usd = price_hkd / rate
print(f"腾讯: {price_hkd} HKD ≈ {price_usd:.2f} USD")
工程影响:汇率写死 0.92,实际汇率波动到 0.90 时,每 100 万港币仓位的美元净值偏差约 2.2 万港币。
检查项 #6:盘口档位数量因品种而异
错误假设:所有港股都返回 10 档盘口。
实际情况:盘口档位数量因品种和流动性不同。部分小盘股可能只有 5 档甚至更少。写死 bids[9] 取第 10 档会 IndexError。
正确处理:
bids = depth["bids"]
# 安全获取第 n 档
def safe_get_level(arr, level):
return arr[level] if level < len(arr) else None
buy_10 = safe_get_level(bids, 9)
if buy_10:
print(f"买十: {buy_10}")
else:
print(f"该品种仅有 {len(bids)} 档买盘")
工程影响:不检查数组长度,策略在小盘股上直接崩溃。
检查项 #7:恒生指数与市场指标查询
错误假设:需要自己计算恒生指数成分股权重和实时点位。
实际情况:calc-index 端点可直接获取市场指标和估值数据。不同指数代码和品种代码返回的字段不同:
url = "https://api.tickdb.ai/v1/market/calc-index"
headers = {"X-API-Key": "YOUR_API_KEY"}
# 查询恒生指数(HSI)或恒生科技指数(HSTECH)
params = {"symbols": "HSI"}
resp = requests.get(url, headers=headers, params=params)
data = resp.json()
if data["code"] == 0:
index_data = data["data"]
# 返回字段以接口实际返回为准,常见包括估值指标
print(f"恒生指数数据: {index_data}")
# 也可查询个股的市场指标
params = {"symbols": "700.HK"}
resp = requests.get(url, headers=headers, params=params)
data = resp.json()
if data["code"] == 0:
stock_metrics = data["data"]
print(f"腾讯市场指标: {stock_metrics}")
工程影响:不查接口自己算指数,维护成本高且容易出错。
检查项 #8:Ticker 和 K 线字段名体系不同
错误假设:所有接口的价格字段都叫 last_price,时间字段都叫 timestamp。
实际情况:REST 端点之间字段名有差异。这是最容易出错的坑,因为不会报错——你会拿到 None 或 KeyError,而不是明显的错误提示。
字段名对照:
| 数据 | Ticker 端点 | K 线端点 |
|---|---|---|
| 价格 | last_price | close |
| 时间 | timestamp | time |
| 成交量 | volume_24h | volume |
正确代码:
# Ticker 接口
ticker_data = resp.json()["data"]
for item in ticker_data:
print(item["last_price"]) # ✅
# print(item["close"]) # ❌ KeyError
# K 线接口
kline_data = resp.json()["data"]["klines"]
for k in kline_data:
print(k["close"]) # ✅
# print(k["last_price"]) # ❌ KeyError
另一个相关陷阱:参数单复数不同。
| 端点 | 参数名 |
|---|---|
/v1/market/ticker | symbols(复数) |
/v1/market/kline | symbol(单数) |
/v1/market/kline/latest | symbols(复数) |
/v1/market/calc-index | symbols(复数) |
统一接入方案
以上 8 个问题,如果用不同数据源拼凑,需要对接多个 API、处理多套字段名和代码格式。
TickDB 通过"统一 REST + WebSocket 接口、统一字段、统一鉴权",覆盖港股约 4,300 个品种(精确数量以 /v1/symbols/available 接口返回为准),一个 Key 接入全部数据。GitHub 开源,文档可查,代码可跑。
import requests
API_BASE = "https://api.tickdb.ai"
HEADERS = {"X-API-Key": "YOUR_API_KEY"}
class HKMarket:
def get_ticker(self, symbols):
"""检查项 #1 #5: 行情 + 汇率"""
resp = requests.get(f"{API_BASE}/v1/market/ticker",
headers=HEADERS, params={"symbols": symbols})
if resp.status_code == 429: # 3001 限流
retry_after = int(resp.headers.get("Retry-After", 5))
time.sleep(retry_after)
return self.get_ticker(symbols)
if resp.status_code == 401: # 1001 鉴权失败
raise Exception("API Key 无效")
return resp.json()
def get_depth(self, symbol):
"""检查项 #4 #6: 盘口数据"""
resp = requests.get(f"{API_BASE}/v1/market/depth",
headers=HEADERS, params={"symbol": symbol})
return resp.json()
def get_kline(self, symbol, interval, start_time, end_time):
"""检查项 #2 #8: K线数据"""
resp = requests.get(f"{API_BASE}/v1/market/kline",
headers=HEADERS,
params={"symbol": symbol, "interval": interval,
"start_time": start_time, "end_time": end_time})
return resp.json()
def check_trading_session(self):
"""检查项 #3: 半日市识别"""
resp = requests.get(f"{API_BASE}/v1/market/trading-sessions",
headers=HEADERS, params={"market": "HK"})
return resp.json()
def get_market_metrics(self, symbols):
"""检查项 #7: 市场指标"""
resp = requests.get(f"{API_BASE}/v1/market/calc-index",
headers=HEADERS, params={"symbols": symbols})
return resp.json()
# 使用示例
hk = HKMarket()
ticker = hk.get_ticker("700.HK,USDHKD")
print(ticker)
WebSocket 实时推送
import asyncio
import json
import websockets
async def main():
uri = "wss://api.tickdb.ai/v1/realtime?api_key=YOUR_API_KEY"
async with websockets.connect(uri) as ws:
await ws.send(json.dumps({
"cmd": "subscribe",
"data": {"channel": "ticker", "symbols": ["700.HK", "9988.HK"]}
}))
async def heartbeat():
while True:
await ws.send(json.dumps({"cmd": "ping"}))
await asyncio.sleep(30) # 按官方文档推荐频率
asyncio.create_task(heartbeat())
async for message in ws:
msg = json.loads(message)
if msg.get("cmd") == "ticker":
item = msg["data"]
print(f"推送: {item['symbol']} 最新价: {item['last_price']}")
elif msg.get("cmd") == "pong":
pass
asyncio.run(main())
发布前 Checklist
做港股量化策略上线前,逐项检查:
- [ ] 所有港股代码无前导零
- [ ] 分钟线策略已处理午间休市空档
- [ ] 策略启动时查询当天交易时段,识别半日市
- [ ] 盘口档位访问前检查数组长度
- [ ] 汇率通过 API 实时获取,不写死
- [ ] K 线用
close/time,Ticker 用last_price/timestamp - [ ] 参数名单复数按端点区分
错误处理速查
| 错误码 | 含义 | 行动 |
|---|---|---|
| 0 | 成功 | - |
| 1001 | API Key 无效 | 阻断并提示 |
| 2001 | 参数错误 | 核对参数名单复数 |
| 2002 | 品种不存在 | 检查代码是否有前导零 |
| 3001 | 请求频率超限 | Retry-After 头,指数退避 |
| 5000 | 服务器内部错误 | 稍后重试 |
附录:TickDB 港股接入速览
| 项目 | 详情 |
|---|---|
| 港股品种 | 约 4,300 个(以 /v1/symbols/available 返回为准) |
| 交易所 | 香港交易所(HKEX) |
| 代码格式 | 700.HK / 9988.HK(无前导零) |
| REST 端点 | ticker、kline、kline/latest、depth、intraday、stock-info、calc-index、trading-sessions、trade-days、symbols/available |
| WebSocket 频道 | ticker、depth、trade |
| 鉴权方式 | REST: Header X-API-Key;WebSocket: URL 参数 ?api_key= |
| 免费政策 | 7 天免费试用,具体以官网 Pricing 页面为准 |
AI 工具链
TickDB 提供三种 AI 协作方式,遵循"对话用 Skill,编码用 MCP,自动化用 CLI":
- Skill:
npx clawhub@latest install tickdb-market-data,AI 自动获取试用 Key - MCP:端点
https://mcp.tickdb.ai,13 个金融数据工具,支持 Cursor、Windsurf 等客户端 - CLI:
npm install -g tickdb(Node.js >= 18),16 个命令终端查价
你看港股策略时最容易踩的是代码格式、交易日历,还是盘口字段?欢迎在评论区讨论。
通过 TickDB API 获取实时行情数据
一个 API 接入外汇、加密货币、美股、港股、A股、贵金属和全球指数的实时行情。支持 WebSocket 低延迟推送,免费开始使用。
免费领取 API Key查看 API 文档