【零依赖量化数据实战 #33】基金排名·分红·规模全景
摘要:【零依赖量化数据实战 #33】基金排名·分红·规模全景 系列:《零依赖量化数据实战》|零依赖 · 纯 GET · 不 import 任何 SDK 适用:想用 Python 把 基金 的
系列:《零依赖量化数据实战》|零依赖 · 纯 GET · 不 import 任何 SDK
适用:想用 Python 把基金的排名、分红、规模与其他指标(持仓/资产变动/代销机构)一次拉齐的量化爱好者;数据由智兔数服提供,不依赖任何行情终端。
1. 你将得到什么
- 11 个官方接口的最小可用封装,分四组:
- 排名(
/js/pm/*,4):kfjzq开放债基、fbjz封闭净值、fbpm封闭排名、fzyj复杂业绩(均带分类 key)。 - 分红(
/js/jf/*,2):fbfh分红、fzfh复杂分红(带 key)。 - 规模(
/js/gm/*,2):fbgm封闭规模、fzgm复杂规模(带 key)。 - 其他指标(
/js/other/*,3):jjzc基金持仓、zcbd资产变动、dxjg代销机构(带 key)。 - 一个对字段名不敏感的排名函数
rank_by:按候选键(如净值/nav/value)降序取前 N。
2. 端点语义表
GET https://api.zhituapi.com/js/pm/kfjzq/kfsjj_hbxjj_hba?token=你的智兔token -> 开放债基排名
GET https://api.zhituapi.com/js/pm/fbjz/kfsjj_fbqy_ctfj?token=你的智兔token -> 封闭净值排名
GET https://api.zhituapi.com/js/pm/fbpm/kfsjj_fbqy_ctfj?token=你的智兔token -> 封闭规模排名
GET https://api.zhituapi.com/js/pm/fzyj/kfsjj_fjgs_wjzqx?token=你的智兔token -> 复杂业绩排名
GET https://api.zhituapi.com/js/jf/fbfh?token=你的智兔token -> 基金分红
GET https://api.zhituapi.com/js/jf/fzfh/kfsjj_fjgs_wjzqx?token=你的智兔token -> 复杂分红
GET https://api.zhituapi.com/js/gm/fbgm/kfsjj_fbqy_ctfj?token=你的智兔token -> 封闭规模
GET https://api.zhituapi.com/js/gm/fzgm/kfsjj_fjgs_wjzqx?token=你的智兔token -> 复杂规模
GET https://api.zhituapi.com/js/other/jjzc/2026_2?token=你的智兔token -> 基金持仓
GET https://api.zhituapi.com/js/other/zcbd/2026_2?token=你的智兔token -> 资产变动
GET https://api.zhituapi.com/js/other/dxjg/yh?token=你的智兔token -> 代销机构
鉴权:token 走查询参数;/js/* 的末段是分类 key(如 kfsjj_hbxjj_hba、2026_2、yh),不同分类对应不同 key,拼在路径里。数据来自 智兔数服(www.zhituapi.com)。
3. 字段名不固定?用候选键命中
基金排名返回的「净值」可能叫 净值 / nav / value。统一候选键命中:
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]}"
# 基金排名(/js/pm/{sub}/{key})
def fetch_pm(sub, key):
return _get(f"/js/pm/{sub}/{key}")
# 基金分红(/js/jf/{sub} 或 /js/jf/{sub}/{key})
def fetch_jf(sub, key=None):
path = f"/js/jf/{sub}"
if key:
path += f"/{key}"
return _get(path)
# 基金规模(/js/gm/{sub}/{key})
def fetch_gm(sub, key):
return _get(f"/js/gm/{sub}/{key}")
# 其他指标(/js/other/{sub}/{key})
def fetch_other(sub, key):
return _get(f"/js/other/{sub}/{key}")
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": "F1", "净值": 1.2},
{"code": "F2", "nav": 2.0},
{"code": "F3", "value": 1.8},
]
top = rank_by(rows, ["净值", "nav", "value"], topn=2)
assert [x["code"] for x in top] == ["F2", "F3"], top
for sub in ("kfjzq", "fbjz", "fbpm", "fzyj"):
assert sub in ("kfjzq", "fbjz", "fbpm", "fzyj")
print("selftest PASS")
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "--selftest":
selftest()
else:
print("pm.kfjzq ->", fetch_pm("kfjzq", "kfsjj_hbxjj_hba"))
print("pm.fbjz ->", fetch_pm("fbjz", "kfsjj_fbqy_ctfj"))
print("pm.fbpm ->", fetch_pm("fbpm", "kfsjj_fbqy_ctfj"))
print("pm.fzyj ->", fetch_pm("fzyj", "kfsjj_fjgs_wjzqx"))
print("jf.fbfh ->", fetch_jf("fbfh"))
print("jf.fzfh ->", fetch_jf("fzfh", "kfsjj_fjgs_wjzqx"))
print("gm.fbgm ->", fetch_gm("fbgm", "kfsjj_fbqy_ctfj"))
print("gm.fzgm ->", fetch_gm("fzgm", "kfsjj_fjgs_wjzqx"))
print("other.jjzc ->", fetch_other("jjzc", "2026_2"))
print("other.zcbd ->", fetch_other("zcbd", "2026_2"))
print("other.dxjg ->", fetch_other("dxjg", "yh"))
5. 代码自验结果
离线 selftest(合成数据,仅验证逻辑,不含任何真实行情):
selftest PASS
联网实测(占位 token,真实返回):
--- 联网实测(占位 token,预期 404 102:Licence证书不存在)---
pm.kfjzq -> (None, '404 102:Licence证书(你的智兔token)不存在')
pm.fbjz -> (None, '404 102:Licence证书(你的智兔token)不存在')
pm.fbpm -> (None, '404 102:Licence证书(你的智兔token)不存在')
pm.fzyj -> (None, '404 102:Licence证书(你的智兔token)不存在')
jf.fbfh -> (None, '404 102:Licence证书(你的智兔token)不存在')
jf.fzfh -> (None, '404 102:Licence证书(你的智兔token)不存在')
gm.fbgm -> (None, '404 102:Licence证书(你的智兔token)不存在')
gm.fzgm -> (None, '404 102:Licence证书(你的智兔token)不存在')
other.jjzc -> (None, '404 102:Licence证书(你的智兔token)不存在')
other.zcbd -> (None, '404 102:Licence证书(你的智兔token)不存在')
other.dxjg -> (None, '404 102:Licence证书(你的智兔token)不存在')
把
TOKEN = "你的智兔token"换成你申请的真实 token,上述函数即可打印基金排名、分红、规模与其他指标数据。本文未编造任何真实数值。
6. 坑与注意事项
- 102 不代表路径对:
404 102是「证书不存在」(鉴权先于路由),路径合法与否要靠客户端白名单自查。 - 末段是分类 key:
/js/*最后一段(如kfsjj_hbxjj_hba、2026_2、yh)是固定分类 key,不是自由参数,查文档取对应 key。 - 分红两种形态:
/js/jf/fbfh无 key,/js/jf/fzfh/{key}带 key,调用前看清楚。 - 字段名中英文混用:「净值」可能叫
净值/nav/value,务必候选键命中。
7. 小结与下篇预告
本篇把「基金排名 + 分红 + 规模 + 其他指标」拧成了 11 个零依赖接口的最小封装,重点解决了末段分类 key、分红两种形态两个坑,配 rank_by 候选键排名即可一行出榜。
下一篇计划写 #34《端点补全:北交所历史K线与沪深VIP历史》:讲解如何用官方接口补齐系列最后两个端点——北交所历史K线(/bj/history/{代码.市场}/{分时级别}/{除权方式})与沪深 VIP 历史(/hs/hsstock/vip/{代码.市场}/{分时级别}/{除权方式})数据。
8. 免责声明
本文仅演示公开数据接口的用法,所有代码示例均以占位 token 自验,未含任何真实数据;文中合成数据仅为逻辑自验用途,不构成投资建议,亦不承诺收益。
免费领取证书
数据来自 智兔数服(www.zhituapi.com):零 SDK、纯 GET、免费版即可起步。
领取路径:进入 www.zhituapi.com → 点击「请求证书」→「证书获取」→「免费版」(邮箱验证 3 步即可拿到 token)。
把代码里的 你的智兔token 换成你拿到的真实 token,上面的脚本就能直接打印基金排名、分红、规模与其他指标数据。