← 返回博客列表

【零依赖量化数据实战 #32】沪深公司面补充:财务股东·股本·经营范围

2026年09月01日 15:57 · 智兔数服 · 零依赖量化数据实战

摘要:【零依赖量化数据实战 #32】沪深公司面补充:财务股东·股本·经营范围 系列:《零依赖量化数据实战》|零依赖 · 纯 GET · 不 import 任何 SDK 适用:想用 Pytho

系列:《零依赖量化数据实战》|零依赖 · 纯 GET · 不 import 任何 SDK
适用:想用 Python 补齐沪深公司面里还没覆盖的字段——流通股东、户均、上市天数、业绩预告、股本变化、经营范围——的量化爱好者;数据由智兔数服提供,不依赖任何行情终端。

1. 你将得到什么

  • 6 个官方接口的最小可用封装,分两组:
  • 公司面剩余/hs/gs/*,4,带 {股票代码}):sszs 上市天数、yjyg 业绩预告、gdbh 股本变化、jyfw 经营范围。
  • 财务股东/hs/fin/*,2,带 {股票代码}):flowholder 流通股东、hm 户均(持股户数/户均持股)。
  • 一个对字段名不敏感的排名函数 rank_by:按候选键(如 流通市值/lt_mv/market_cap)降序取前 N。

2. 端点语义表

GET https://api.zhituapi.com/hs/gs/sszs/000001.SZ?token=你的智兔token   -> 上市天数
GET https://api.zhituapi.com/hs/gs/yjyg/000001.SZ?token=你的智兔token   -> 业绩预告
GET https://api.zhituapi.com/hs/gs/gdbh/000001.SZ?token=你的智兔token   -> 股本变化
GET https://api.zhituapi.com/hs/gs/jyfw/000001.SZ?token=你的智兔token   -> 经营范围
GET https://api.zhituapi.com/hs/fin/flowholder/000001.SZ?token=你的智兔token -> 流通股东
GET https://api.zhituapi.com/hs/fin/hm/000001.SZ?token=你的智兔token    -> 户均(持股户数/户均持股)

鉴权:token 走查询参数;{股票代码}路径参数,沪深代码带市场后缀(如 000001.SZ)。数据来自 智兔数服(www.zhituapi.com)。

3. 字段名不固定?用候选键命中

财务股东返回的「流通市值」可能叫 流通市值 / lt_mv / market_cap。统一候选键命中:

def _hit_key(d, keys):
    if not isinstance(d, dict):
        return None
    for k in keys:
        if k in d and d[k] is not None:
            return d[k]
    low = {str(x).lower(): x for x in d.keys()}
    for k in keys:
        kl = k.lower()
        if kl in low:
            return d[low[kl]]
    return None

4. 核心模板函数

import sys, requests

BASE = "https://api.zhituapi.com"
TOKEN = "你的智兔token"  # 占位,换成你申请的真实 token

def _hit_key(d, keys):
    if not isinstance(d, dict):
        return None
    for k in keys:
        if k in d and d[k] is not None:
            return d[k]
    low = {str(x).lower(): x for x in d.keys()}
    for k in keys:
        kl = k.lower()
        if kl in low:
            return d[low[kl]]
    return None

def _to_float(v):
    try:
        return None if v is None else float(v)
    except (TypeError, ValueError):
        return None

def _get(path, params=None):
    p = dict(params or {})
    p["token"] = TOKEN
    try:
        r = requests.get(f"{BASE}{path}", params=p, timeout=10)
    except Exception as e:
        return None, f"网络异常:{e}"
    if r.status_code != 200:
        return None, f"{r.status_code} {r.text.strip()[:140]}"
    try:
        return r.json(), None
    except Exception:
        return None, f"非 JSON:{r.text.strip()[:140]}"

# 公司面剩余字段(/hs/gs/*,带 {股票代码})
def fetch_gs(sub, code):
    return _get(f"/hs/gs/{sub}/{code}")

# 财务股东/户均(/hs/fin/*,带 {股票代码})
def fetch_fin(sub, code):
    return _get(f"/hs/fin/{sub}/{code}")

def rank_by(rows, keys, descending=True, topn=None):
    if not isinstance(rows, list):
        return rows
    def sc(x):
        return _to_float(_hit_key(x, keys)) or 0.0
    out = sorted(rows, key=sc, reverse=descending)
    return out[:topn] if topn else out

def selftest():
    # 合成数据仅逻辑自验,非真实行情
    rows = [
        {"code": "000001.SZ", "流通市值": 100.0},
        {"code": "600000.SH", "lt_mv": 300.0},
        {"code": "300750.SZ", "market_cap": 200.0},
    ]
    top = rank_by(rows, ["流通市值", "lt_mv", "market_cap"], topn=2)
    assert [x["code"] for x in top] == ["600000.SH", "300750.SZ"], top
    for sub in ("sszs", "yjyg", "gdbh", "jyfw"):
        assert sub in ("sszs", "yjyg", "gdbh", "jyfw")
    for sub in ("flowholder", "hm"):
        assert sub in ("flowholder", "hm")
    print("selftest PASS")

if __name__ == "__main__":
    if len(sys.argv) > 1 and sys.argv[1] == "--selftest":
        selftest()
    else:
        for sub in ("sszs", "yjyg", "gdbh", "jyfw"):
            print(f"gs.{sub} ->", fetch_gs(sub, "000001.SZ"))
        for sub in ("flowholder", "hm"):
            print(f"fin.{sub} ->", fetch_fin(sub, "000001.SZ"))

5. 代码自验结果

离线 selftest(合成数据,仅验证逻辑,不含任何真实行情):

selftest PASS

联网实测(占位 token,真实返回):

--- 联网实测(占位 token,预期 404 102:Licence证书不存在)---
gs.sszs -> (None, '404 102:Licence证书(你的智兔token)不存在')
gs.yjyg -> (None, '404 102:Licence证书(你的智兔token)不存在')
gs.gdbh -> (None, '404 102:Licence证书(你的智兔token)不存在')
gs.jyfw -> (None, '404 102:Licence证书(你的智兔token)不存在')
fin.flowholder -> (None, '404 102:Licence证书(你的智兔token)不存在')
fin.hm -> (None, '404 102:Licence证书(你的智兔token)不存在')

TOKEN = "你的智兔token" 换成你申请的真实 token,上述函数即可打印沪深公司面补充字段数据。本文未编造任何真实数值。

6. 坑与注意事项

  1. 102 不代表路径对404 102 是「证书不存在」(鉴权先于路由),路径合法与否要靠客户端白名单自查。
  2. 代码带市场后缀/hs/gs/*/hs/fin/*{股票代码} 要带市场(如 000001.SZ)。
  3. 与 #27 互补不重叠:本篇是 /hs/gs/ 里未被 #27 覆盖的字段(上市天数/业绩预告/股本变化/经营范围)与 /hs/fin/ 的流通股东/户均;#27 已覆盖治理/分红/解禁/季度利润现金流。
  4. 字段名中英文混用:「流通市值」可能叫 流通市值/lt_mv/market_cap,务必候选键命中。

7. 小结与下篇预告

本篇把「沪深公司面补充字段」拧成了 6 个零依赖接口的最小封装,重点解决了代码带市场后缀与 #27 互补不重叠两个坑,配 rank_by 候选键排名即可一行出榜。

下一篇计划写 #33《基金排名·分红·规模全景》:讲解如何用官方接口拉取基金排名(/js/pm/*)、分红(/js/jf/*)、规模(/js/gm/*)与其他指标(/js/other/*)数据。

8. 免责声明

本文仅演示公开数据接口的用法,所有代码示例均以占位 token 自验,未含任何真实数据;文中合成数据仅为逻辑自验用途,不构成投资建议,亦不承诺收益。


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

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

把代码里的 你的智兔token 换成你拿到的真实 token,上面的脚本就能直接打印沪深公司面补充字段数据。

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