港股

做港股量化前,先检查这 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.HK700.HK
阿里巴巴9988.HK9988.HK(4位码无需补齐)
美团3690.HK3690.HK
小米1810.HK1810.HK
中国平安2318.HK2318.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_priceclose
时间timestamptime
成交量volume_24hvolume

正确代码

# 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/tickersymbols(复数)
/v1/market/klinesymbol(单数)
/v1/market/kline/latestsymbols(复数)
/v1/market/calc-indexsymbols(复数)

统一接入方案

以上 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成功-
1001API 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":

  • Skillnpx clawhub@latest install tickdb-market-data,AI 自动获取试用 Key
  • MCP:端点 https://mcp.tickdb.ai,13 个金融数据工具,支持 Cursor、Windsurf 等客户端
  • CLInpm install -g tickdb(Node.js >= 18),16 个命令终端查价

你看港股策略时最容易踩的是代码格式、交易日历,还是盘口字段?欢迎在评论区讨论。

通过 TickDB API 获取实时行情数据

一个 API 接入外汇、加密货币、美股、港股、A股、贵金属和全球指数的实时行情。支持 WebSocket 低延迟推送,免费开始使用。

免费领取 API Key查看 API 文档

相关文章