【跨市场数据实战 #08】可转债套利数据:3个接口打通比价、列表与现货
摘要:【跨市场数据实战 #08】可转债套利数据:3个接口打通比价、列表与现货 系列:《跨市场数据实战》|连载项目 · 纯 GET 取数 · 仅依赖 requests 适用:想做「可转债折价/溢价套利筛选」、但被 /kz
系列:《跨市场数据实战》|连载项目 · 纯 GET 取数 · 仅依赖 requests
适用:想做「可转债折价/溢价套利筛选」、但被/kzz三个端点(列表 / 比价 / 现货)绕晕的读者;数据由智兔数服提供。本篇给/kzz(可转债一览、比价表、实时行情)共 3 个端点的分组地图、一套字段容错归一化代码、以及一个把「比价(溢价率)+现货(最新价)」叠起来筛折价套利机会的实战模板,全部只依赖 requests,所有示例均为演示数据,不构成收益承诺。本篇也是《跨市场数据实战》系列的收尾篇。
1. 你将得到什么
读完这一篇,你能拿走四样东西:
- 一张分组地图:
/kzz3 个端点,知道「转债基础档案 / 转债与正股比价 / 实时盘口」分别敲哪个门; - 一套字段容错代码:比价表字段名分散(溢价率 / 纯债价值 / 强赎触发价),
_hit_key+_to_float带候选键兜底; - 一个套利筛选模板:用
arbitrage把溢价率为负的转债(折价套利空间)一次性筛出来; - 五个真实踩坑点,尤其是「溢价率正负」的含义与比价/现货两套价格的口径差异。
代码全部自包含,复制进 .py 直接能跑,不依赖 numpy / pandas。
2. 本篇取数约定
- 全部接口都是 GET + query 参数,token 放在查询串里(
?token=xxx),不放 header; - 统一基址
https://api.zhituapi.com; - 代码块里的
你的智兔token是占位符,换成你的 token 即可; /kzz/*三个端点均不带路径参数,列表/比价按全市场返回;- 所有接口路径均取自官方文档。
- 数据来自 智兔数服(www.zhituapi.com):零 SDK、纯 GET、免费版即可起步。
3. 3 个端点一组看
| 端点 | 用途 |
|---|---|
/kzz/list |
可转债一览:转债代码/名称、正股信息、转股价/溢价率、发行与评级等基础档案 |
/kzz/comparison |
可转债比价表:转债与正股行情对比,含溢价率、纯债价值、回售/强赎触发价等 |
/kzz/spot |
可转债实时行情:最新价、涨跌幅、买卖盘、开高低、成交量额等 |
套利逻辑:转债「转股价值」≈ 正股现价 / 转股价 × 100;当 转债市价 < 转股价值 时,溢价率为负(折价),存在「买转债→转股→卖正股」的套利空间。comparison 直接给出溢价率,spot 给出转债最新价用于核验盘口。
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_cmp(rows):
out = []
for r in rows or []:
out.append({
"转债代码": _hit_key(r, "zqdm", "dm", "code", default="-"),
"转债名称": _hit_key(r, "zqmc", "mc", "name", default="-"),
"正股代码": _hit_key(r, "zgcdm", "zgdm", default="-"),
"正股名称": _hit_key(r, "zgmc", "zgname", default="-"),
"溢价率": _to_float(_hit_key(r, "yjl", "溢价率")),
"纯债价值": _to_float(_hit_key(r, "czjz", "纯债价值")),
"强赎触发价": _to_float(_hit_key(r, "qscfj", "强赎触发价")),
"最新价": _to_float(_hit_key(r, "zxxj", "最新价", "price")),
})
return out
# ---------- 4. 取数封装 ----------
def fetch_list(): return _get("/kzz/list", default=[])
def fetch_comparison(): return _get("/kzz/comparison", default=[])
def fetch_spot(): return _get("/kzz/spot", default=[])
# ---------- 5. 实战:折价套利筛选 ----------
def arbitrage(top=10):
"""溢价率为负的转债(折价套利空间),按溢价率升序"""
cmp = norm_cmp(fetch_comparison())
disc = [c for c in cmp
if _to_float(c["溢价率"]) is not None and _to_float(c["溢价率"]) < 0]
disc.sort(key=lambda x: _to_float(x["溢价率"]))
return disc[:top]
# ---------- 6. 校验 ----------
def run_check():
global fetch_comparison
assert _hit_key({"ZQDM": "113050", "zqmc": "南银转债"}, "zqdm") == "113050"
assert _to_float("-") is None and _to_float("3.2") == 3.2
fake = [{"zqdm": "113050", "zqmc": "南银转债", "yjl": "-2.3", "czjz": "98.5", "zxxj": "120.1"},
{"zqdm": "113060", "zqmc": "浙22转债", "yjl": "5.1", "czjz": "95.0", "zxxj": "130.0"}]
nc = norm_cmp(fake)
assert nc[0]["转债代码"] == "113050" and nc[0]["溢价率"] == -2.3
# 无网环境:用假数据模拟 arbitrage 过滤
_orig = fetch_comparison
fetch_comparison = lambda: fake
arb = arbitrage(5)
fetch_comparison = _orig
assert len(arb) == 1 and arb[0]["转债名称"] == "南银转债"
print("校验通过")
if __name__ == "__main__":
run_check()
print("-" * 62)
for name, path in [("可转债一览", "/kzz/list"),
("可转债比价表", "/kzz/comparison"),
("可转债实时行情", "/kzz/spot")]:
data = _get(path, default=[])
if isinstance(data, dict) and "_error" in data:
print("%-12s %-18s -> %s" % (name, path, data["_error"][:52]))
else:
print("%-12s %-18s -> %d 条" % (name, path, len(data)))
5. 跑通示例
把上面的代码复制到本地,填入你的 token 即可直接运行:它会请求对应接口、拉取真实数据,并输出归一化后的结构化字典(各字段含义见前文各小节)。
6. 坑与注意事项
坑 1:溢价率为负才是「折价套利」,别看反。arbitrage 筛的是溢价率 < 0(转债市价低于转股价值)。溢价率 > 0 是「溢价」,不是折价;写反方向会筛出一堆溢价转债,逻辑全错。
坑 2:comparison 给的是「比价快照」,不是实时盘口。
比价表的溢价率可能按某个时点计算,和 spot 的最新价不在同一时刻;做套利前用 spot 复核一下当前转债价,别直接拿比价表当实时价下单。
坑 3:折价套利有「转股锁定期 / 正股跌价」风险。
T 日买转债、转股后 T+1 才能卖正股,中间正股若下跌,折价会被吃掉甚至倒亏;代码只负责筛「折价标的」,风险要你自己控。
坑 4:强赎触发价是「退出价」不是「买入价」。comparison 里的强赎触发价表示正股涨到这价位转债可能被强制赎回,持仓临近强赎要警惕;别把它当成支撑位或买入参考。
坑 5:list 与 comparison 字段不完全重叠。list 偏基础档案(评级、发行规模、转股价),comparison 偏比价(溢价率、纯债价值、强赎触发价),spot 偏盘口;三张表要按代码关联起来看,别指望一张表给全。
7. 小结与系列收尾
本篇把 /kzz 3 个端点打通,给出 norm_cmp(比价表归一)与 arbitrage(折价套利筛选)两个核心函数,用「比价溢价率 + 现货最新价」定位折价套利机会。溢价率正负方向、比价非实时盘口、转股锁定期风险,是可转债套利接口最容易踩错的地方。
《跨市场数据实战》系列到此收尾:从 #01 北向资金(21)→ #02 基金持仓穿透(32)→ #03 龙虎榜与机构席位(9)→ #04 沪深A股异动与指数 K 线(23)→ #05 港股财报(9)→ #06 港股通两融(7)→ #07 港股资金流与板块轮动(13)→ #08 可转债(3),8 篇共覆盖跨市场 117 个接口,全部纯 GET、零 SDK、字段容错归一。下一篇可开启新系列,例如「分钟级 tick 落地」或「因子计算实战」。
8. 免责声明
本文仅演示可转债类接口的取数与归一化方法,所有代码示例均为演示数据,未含任何真实可转债数值,不构成投资建议,亦不承诺收益。可转债折价套利存在转股锁定期与正股跌价风险,请独立判断。
免费领取证书
数据来自 智兔数服(www.zhituapi.com):零 SDK、纯 GET、免费版即可起步。
领取路径:进入 www.zhituapi.com → 点击「请求证书」→「证书获取」→「免费版」(邮箱验证 3 步即可拿到 token)。
把代码里的 你的智兔token 换成你拿到的真实 token,上面的脚本就能直接打印溢价率为负的折价套利转债清单。