← 返回博客列表

【跨市场数据实战 #05】港股财报全景:9个接口从业绩预告到现金流量表

2026年09月16日 08:19 · 智兔数服 · 跨市场数据实战

摘要:【跨市场数据实战 #05】港股财报全景:9个接口从业绩预告到现金流量表 系列:《跨市场数据实战》|连载项目 · 纯 GET 取数 · 仅依赖 requests 适用:想做「港股年报横向对比 / 财报质量筛查」、但

系列:《跨市场数据实战》|连载项目 · 纯 GET 取数 · 仅依赖 requests
适用:想做「港股年报横向对比 / 财报质量筛查」、但被一堆 /hicw 财务端点绕晕的读者;数据由智兔数服提供。本篇给 /hicw(盈利能力、运营能力、成长能力、偿债能力、现金流量、业绩报表/快报/预告、利润细分)共 9 个端点的分组地图、一套字段容错归一化代码、以及一个把「盈利 / 现金流 / ROE 类」指标横向拉平做对比排序的实战模板,全部只依赖 requests,所有示例均为演示数据,不构成收益承诺。

1. 你将得到什么

读完这一篇,你能拿走四样东西:

  1. 一张分组地图/hicw 9 个财务端点,知道「盈利能力 / 营运能力 / 成长能力 / 偿债能力 / 现金流量」和「业绩报表 / 快报 / 预告 / 利润细分」分别敲哪个门;
  2. 一套字段容错代码:财报字段名极其分散,_hit_key + _to_float 带候选键兜底,换只股票也能抽;
  3. 一个横向对比模板:用 benchmark 把多只港股的净利润 / ROE / 经营现金流一次性拉平排序;
  4. 五个真实踩坑点,尤其是 /hicw/* 那个「年份_季度」路径参数(年从 1989 起、季度 1/2/3/4 对应一季报/中报/三季报/年报)。

代码全部自包含,复制进 .py 直接能跑,不依赖 numpy / pandas。

2. 本篇取数约定

  • 全部接口都是 GET + query 参数,token 放在查询串里(?token=xxx),不放 header;
  • 统一基址 https://api.zhituapi.com
  • 代码块里的 你的智兔token 是占位符,换成你的 token 即可;
  • 8 个汇总类端点(yl/yy/cz/cznl/xj/yjbb/yjyg/yjkb)走路径参数 /{年}/{季度}年可选 1989~当前年份,季度 1=一季报 / 2=中报 / 3=三季报 / 4=年报,如 /hicw/yl/2023/4 表示 2023 年报;/hicw/lr(利润细分)无年/季参数;
  • 所有接口路径均取自官方文档。
  • 数据来自 智兔数服(www.zhituapi.com):零 SDK、纯 GET、免费版即可起步。

3. 9 个端点一组看

/hicw 全系列都是「按年份_季度」的财务汇总,先建立地图。

端点 用途 路径参数
/hicw/yl/{年}/{季度} 盈利能力汇总 年份_季度
/hicw/yy/{年}/{季度} 运营能力汇总 年份_季度
/hicw/cz/{年}/{季度} 成长能力汇总 年份_季度
/hicw/cznl/{年}/{季度} 偿债能力汇总 年份_季度
/hicw/xj/{年}/{季度} 现金流量汇总 年份_季度
/hicw/yjbb/{年}/{季度} 业绩报表汇总 年份_季度
/hicw/yjyg/{年}/{季度} 业绩预告汇总 年份_季度
/hicw/yjkb/{年}/{季度} 业绩快报汇总 年份_季度
/hicw/lr 利润细分汇总(无年/季参数)

年份_季度举例:2023_4 = 2023 年报、2024_1 = 2024 一季报。注意文档描述里出现的「年份_季度」在路径上以斜杠分隔(/hicw/yl/2023/4),别写成下划线拼进路径。

4. 核心模板函数

import requests, time

BASE = "https://api.zhituapi.com"
TOKEN = "你的智兔token"

# ---------- 1. 字段容错与类型归一 ----------
def _hit_key(d, *cands, default=None):
    if not isinstance(d, dict):
        return default
    for c in cands:
        if c in d and d[c] not in (None, "", "-", "null"):
            return d[c]
    low = {str(k).lower(): v for k, v in d.items()}
    for c in cands:
        v = low.get(str(c).lower())
        if v not in (None, "", "-", "null"):
            return v
    return default


def _to_float(v, default=None):
    try:
        if v in (None, "", "-", "null", "None"):
            return default
        return float(v)
    except (TypeError, ValueError):
        return default


# ---------- 2. 统一请求 ----------
def _get(path, params=None, timeout=10, retries=2, backoff=0.6, default=None):
    q = {"token": TOKEN}
    if params:
        q.update(params)
    last = ""
    for i in range(retries + 1):
        try:
            r = requests.get(BASE + path, params=q, timeout=timeout)
            if r.status_code == 200:
                try:
                    return r.json()
                except ValueError:
                    return default
            last = "HTTP %s %s" % (r.status_code, (r.text or "").strip()[:80])
        except Exception as e:
            last = "%s: %s" % (type(e).__name__, e)
        if i < retries:
            time.sleep(backoff * (i + 1))
    return {"_error": last}


# ---------- 3. 财务汇总归一:抽 代码/名称 + 其余字段归档为指标字典 ----------
def norm_cw(rows):
    out = []
    for r in rows or []:
        if not isinstance(r, dict):
            continue
        code = _hit_key(r, "dm", "code", default="-")
        name = _hit_key(r, "mc", "name", default="-")
        metrics = {}
        for k, v in r.items():
            if str(k).lower() in ("dm", "code", "mc", "name"):
                continue
            metrics[k] = _to_float(v, v)   # 能转浮点转,否则保留原值
        out.append({"代码": code, "名称": name, "指标": metrics})
    return out


def _metric(m, *cands, default=None):
    """从某只股票的指标字典里按候选键抽一个值"""
    for c in cands:
        if c in m and m[c] not in (None, "", "-"):
            return m[c]
    return default


# ---------- 4. 取数封装 ----------
def fetch_cw(kind="yl", year=2023, quarter=4):
    """kind: yl/yy/cz/cznl/xj/yjbb/yjyg/yjkb"""
    return _get("/hicw/%s/%d/%d" % (kind, year, quarter), default=[])


def fetch_lr():
    return _get("/hicw/lr", default=[])


# ---------- 5. 实战:横向对比多只港股的盈利/现金流/ROE ----------
def benchmark(year=2023, quarter=4, codes=None, top=10):
    yl = {x["代码"]: x["指标"] for x in norm_cw(fetch_cw("yl", year, quarter))}
    xj = {x["代码"]: x["指标"] for x in norm_cw(fetch_cw("xj", year, quarter))}
    cz = {x["代码"]: x["指标"] for x in norm_cw(fetch_cw("cz", year, quarter))}
    names = {x["代码"]: x["名称"] for x in norm_cw(fetch_cw("yl", year, quarter))}
    rows = []
    for code in (codes or list(yl)):
        m = yl.get(code, {})
        rows.append({
            "代码":   code,
            "名称":   names.get(code, "-"),
            "净利润": _metric(m, "jlr", "净利润", "np"),
            "ROE":    _metric(m, "roe", "ROE", "fzx"),
            "经营现金流": _metric(xj.get(code, {}), "jyxjll", "经营现金流"),
            "营收增速": _metric(cz.get(code, {}), "yysrzz", "营收增长", "yysr"),
        })
    rows.sort(key=lambda x: _to_float(x["净利润"]) or -1e18, reverse=True)
    return rows[:top]


# ---------- 6. 校验 ----------
def run_check():
    global fetch_cw
    assert _hit_key({"DM": "00700", "mc": "腾讯"}, "dm") == "00700"
    assert _to_float("-") is None and _to_float("12.5") == 12.5

    fake = [{"dm": "00700", "mc": "腾讯", "jlr": "1156.0", "roe": "21.3", "jyxjll": "1234.5"}]
    nc = norm_cw(fake)
    assert nc[0]["代码"] == "00700" and nc[0]["指标"]["jlr"] == 1156.0

    # 无网环境:用假数据模拟 benchmark 归并与排序
    def _fake(kind, year, quarter):
        return [{"dm": "00700", "mc": "腾讯", "jlr": "1156", "roe": "21", "jyxjll": "1200", "yysr": "6000"},
                {"dm": "09988", "mc": "阿里", "jlr": "800", "roe": "12", "jyxjll": "900", "yysr": "8000"}]
    _orig = fetch_cw
    fetch_cw = _fake
    bm = benchmark(2023, 4)
    fetch_cw = _orig
    assert bm[0]["代码"] == "00700" and bm[0]["净利润"] == 1156.0

    print("校验通过")


if __name__ == "__main__":
    run_check()
    print("-" * 62)
    for name, path in [("盈利能力", "/hicw/yl/2023/4"),
                       ("营运能力", "/hicw/yy/2023/4"),
                       ("成长能力", "/hicw/cz/2023/4"),
                       ("偿债能力", "/hicw/cznl/2023/4"),
                       ("现金流量", "/hicw/xj/2023/4"),
                       ("业绩报表", "/hicw/yjbb/2023/4"),
                       ("业绩预告", "/hicw/yjyg/2023/4"),
                       ("业绩快报", "/hicw/yjkb/2023/4"),
                       ("利润细分", "/hicw/lr")]:
        data = _get(path, default=[])
        if isinstance(data, dict) and "_error" in data:
            print("%-10s %-22s -> %s" % (name, path, data["_error"][:52]))
        else:
            print("%-10s %-22s -> %d 条" % (name, path, len(data)))

5. 跑通示例

把上面的代码复制到本地,填入你的 token 即可直接运行:它会请求对应接口、拉取真实数据,并输出归一化后的结构化字典(各字段含义见前文各小节)。

6. 坑与注意事项

坑 1:/hicw/* 的「年份_季度」是路径参数,不是查询参数。
/hicw/yl/2023/4 才对;写成 /hicw/yl?year=2023&quarter=4 会 404。年报用季度 4,一季报用 1

坑 2:年份范围很宽(1989~当前),但缺失年份直接空返回。
很多港股早期年份没有财务汇总,调用老年份大概率返回空列表,别当成报错。benchmarkcodes or list(yl) 兜底,空列表不会崩。

坑 3:利润细分 /hicw/lr 不带年/季参数。
它是一份「利润细分汇总」快照,不要给它拼 /2023/4,否则路径不对。

坑 4:财报字段极度异构,单位/口径要自己统一。
yl 的 ROE 是百分比、jlr 净利润可能是「万元 / 亿元」视上游,跨端点做对比前务必先确认单位。norm_cw 只做容错抽取,不替你换算单位,排序前建议在调用层统一。

坑 5:yjyg(业绩预告)与 yjbb(业绩报表)不是一回事。
预告是「预计」,报表是「实际」;做财报质量筛查时两者要分开看,别拿预告当已实现的利润排序。

7. 小结与下篇预告

本篇把 /hicw 9 个财务端点打通,给出 norm_cw(抽代码/名称 + 指标字典)与 benchmark(跨股票横向对比净利润/ROE/经营现金流)两个核心函数。年份_季度 走路径参数、年份范围宽但缺失即空、利润细分无年季参数,是这套财报接口最容易踩错的地方。

下一篇计划写 #06《港股通融资融券:7个接口追踪杠杆资金》:用 /hitc(今日交易提示、融资融券总量/明细、大宗交易、解禁限售、打新收益、历史分红)追踪杠杆资金对某只港股通标的的加减速。

8. 免责声明

本文仅演示港股财报类接口的取数与归一化方法,所有代码示例均为演示数据,未含任何真实财务数值,不构成投资建议,亦不承诺收益。


免费领取证书
数据来自 智兔数服(www.zhituapi.com):零 SDK、纯 GET、免费版即可起步。

领取路径:进入 www.zhituapi.com → 点击「请求证书」→「证书获取」→「免费版」(邮箱验证 3 步即可拿到 token)。

把代码里的 你的智兔token 换成你拿到的真实 token,上面的脚本就能直接打印港股多只股票的盈利/现金流横向对比表。

想亲自试一下?免费获取证书