A股量化数据工程:从 REST 接口到策略信号(第 1 篇):指数列表与实时行情接入
系列说明
- 数据源为 HTTP 接口,接口仅输出原始业务裸字段,不存在预制量化因子、预制打分指标;所有因子、统计逻辑均由代码二次计算实现;
- 所有统计、筛选输出统一标注:仅为数据演示,不构成投资建议;
- A 股行情遵循涨红跌绿展示规则,金额单位使用货币符号 ¥;
- 与开源库对比只陈述客观事实,不做主观褒贬。
前言
做量化的人几乎都从「指数」起步------大盘涨跌、板块强弱、风格切换,全靠指数说话。但很多新手卡在数据接入:要么爬虫不稳定,要么字段对不齐。本篇用一组 REST 接口,把指数列表 和指数实时行情一次性接进来,落进本地库,后续所有因子、信号都从这张表长出来。
本系列定位「数据工程」,每篇聚焦一个真实接口族,给出可运行代码与落库设计,字段均与官方接口文档一一对应。
一、接口原始字段梳理
1)指数列表接口
接口地址:https://api.biyingapi.com/hsindex/list/{LICENCE}
| 字段 | 说明 |
|---|---|
| dm | 指数代码,形如 000001.SH(上证综指)、399001.SZ(深证成指) |
| mc | 指数名称 |
| jys | 交易所标识 |
2)指数实时行情接口
接口地址:https://api.biyingapi.com/hsindex/real/time/{指数代码.市场}/{LICENCE}
| 字段 | 说明 |
|---|---|
| p | 最新价 |
| o | 今开 |
| h | 最高 |
| l | 最低 |
| yc | 昨收 |
| cje | 成交额(元 ¥) |
| v | 成交量(手) |
| pv | 原始成交总量 |
| ud | 涨跌额 |
| pc | 涨跌幅 |
| zf | 振幅 |
| t | 行情时间 |
提示:指数代码带市场后缀(
.SH/.SZ),实时接口路径要拆成指数代码.市场再拼,与股票接口一致。
二、自研衍生统计指标
拿到实时行情后,两个轻量衍生量很有用:
- 强弱分档 :按
pc(涨跌幅)把指数分成 强(>0.5%) / 平(-0.5%~0.5%) / 弱(<-0.5%),用于判断当天风险偏好。 - 振幅异常 :
zf(振幅)显著高于近 20 日均值时,往往对应变盘窗口。
这两个量接口不会直接返回,全部基于原始字段业务代码运算。
三、数据表设计
在 quant.db 新建两张数据表:
sql
CREATE TABLE IF NOT EXISTS index_list (
dm TEXT PRIMARY KEY,
mc TEXT,
jys TEXT
);
CREATE TABLE IF NOT EXISTS index_realtime (
dm TEXT,
t TEXT,
p REAL, o REAL, h REAL, l REAL, yc REAL,
cje REAL, v REAL, pv REAL,
ud REAL, pc REAL, zf REAL,
PRIMARY KEY (dm, t)
);
四、完整代码
python
import requests
import sqlite3
import time
LICENCE = "YOUR_LICENCE" # 替换为你的接口证书
BASE = "https://api.biyingapi.com"
DB_PATH = "quant.db"
def biying_api_get_retry(url, timeout=15, max_retry=3):
"""带重试的接口请求,返回解析后的 json。"""
for i in range(max_retry):
try:
r = requests.get(url, timeout=timeout)
r.raise_for_status()
return r.json()
except Exception as e:
if i == max_retry - 1:
raise
time.sleep(1 + i)
def fetch_index_list():
"""沪深主要指数列表:dm/mc/jys。"""
data = biying_api_get_retry(f"{BASE}/hsindex/list/{LICENCE}")
return data.get("data", []) if isinstance(data, dict) else []
def fetch_index_realtime(code, market):
"""单指数实时行情:p/o/h/l/yc/cje/v/pv/ud/pc/zf/t。"""
url = f"{BASE}/hsindex/real/time/{code}.{market}/{LICENCE}"
data = biying_api_get_retry(url)
return data.get("data", {}) if isinstance(data, dict) else {}
def save_index_list(rows):
con = sqlite3.connect(DB_PATH)
con.executemany(
"INSERT OR REPLACE INTO index_list(dm, mc, jys) VALUES(?,?,?)",
[[r.get("dm"), r.get("mc"), r.get("jys")] for r in rows])
con.commit(); con.close()
def save_index_realtime(row):
cols = ["dm", "t", "p", "o", "h", "l", "yc", "cje", "v", "pv", "ud", "pc", "zf"]
vals = [row.get(c) for c in cols]
con = sqlite3.connect(DB_PATH)
ph = ",".join("?" * len(cols))
con.execute(
f"INSERT OR REPLACE INTO index_realtime({','.join(cols)}) VALUES({ph})", vals)
con.commit(); con.close()
def strength_tag(pc):
"""涨跌幅分档:强 / 平 / 弱。"""
if pc is None:
return "平"
if pc > 0.5:
return "强"
if pc < -0.5:
return "弱"
return "平"
if __name__ == "__main__":
# 1) 拉列表并落库
idx_list = fetch_index_list()
save_index_list(idx_list)
print(f"指数列表共 {len(idx_list)} 条,示例:", idx_list[0] if idx_list else None)
# 2) 逐一对主要指数拉实时行情
for it in idx_list[:5]: # 先取前 5 个演示
dm = it.get("dm", "")
if "." not in dm:
continue
code, market = dm.split(".", 1)
rt = fetch_index_realtime(code, market)
if rt:
rt["dm"] = dm
save_index_realtime(rt)
print(f"{dm} {it.get('mc')} 最新价={rt.get('p')} 涨跌幅={rt.get('pc')} 档位={strength_tag(rt.get('pc'))}")
五、关键业务说明
- 代码后缀别丢 :指数代码带市场后缀(
.SH/.SZ),实时接口路径要拆成code.market再拼,和股票接口一致。 - 证书即鉴权 :所有接口路径末尾带
LICENCE,免费版每天有调用上限,批量拉列表后建议缓存,实时行情再逐个请求。 - 落库主键 :实时表用
(dm, t)复合主键,重复写入自动覆盖,方便定时刷新。
六、拓展练习
- 把
index_list全量落库(去掉[:5]限制),统计各交易所指数数量。 - 用
pc计算全市场「强/弱」指数占比,做一个简单的市场情绪温度计。 - 把实时拉取改成定时任务(如每 3 秒一次),观察
t字段刷新频率。
下篇预告
A股量化数据工程:从 REST 接口到策略信号(第 2 篇):指数分时数据解析与清洗
下一篇用
hsindex/latest与hsindex/history拉取指数分时数据,讲解缺值补齐、按时间排序与分时 MA 回填,把「列表 + 实时」升级成「分时序列」。
免责申明 :本篇全部代码、接口调用仅作为量化编程学习演示,仅为数据演示,不构成投资建议。市场有风险,投资需谨慎。