A股量化数据工程:从 REST 接口到策略信号(第 17 篇):创新高与新低扫描
前言
创新高 / 新低是个股强度最直观的信号:持续新高说明趋势强,密集新低说明杀跌未止。接口 himk/pzxg(盘中创新高)、himk/pzxd(盘中创新低)直接给出标的与「是否创新高」标记,本篇自研新高强度扫描器,把个股强度汇总成市场温度计。
一、接口原始字段梳理
1)盘中创新高个股
接口地址:https://api.biyingapi.com/himk/pzxg/{LICENCE}
| 字段 | 说明 |
|---|---|
| t | 日期 |
| dm | 股票代码 |
| mc | 股票名称 |
| c | 现价 |
| h | 最高 |
| l | 最低 |
| zdf | 涨跌幅 |
| iscq | 是否创新高(1/0) |
| hs | 换手率 |
| zdf5, iscq5 | 5 日涨跌幅 / 是否 5 日新高 |
| zdf10, iscq10 | 10 日 |
| zdf20, iscq20 | 20 日 |
2)盘中创新低个股
接口地址:https://api.biyingapi.com/himk/pzxd/{LICENCE}
| 字段 | 说明 |
|---|---|
| t | 日期 |
| dm | 股票代码 |
| mc | 股票名称 |
| c | 现价 |
| h | 最高 |
| l | 最低 |
| zdf | 涨跌幅 |
| iscq | 是否创新低(1/0) |
| hs | 换手率 |
| zdf5, iscq5 | 5 日 |
| zdf10, iscq10 | 10 日 |
| zdf20, iscq20 | 20 日 |
二、自研衍生统计指标
- 新高强度 :创新高股中
zdf > 5%的占比,越高市场越亢奋。 - 新低恐慌度 :创新低股中
zdf < -5%的占比,越高杀跌越狠。 - 牛熊宽度 :
新高数 − 新低数的绝对值,做市场宽度指标。
标记
iscq为接口原始,占比与宽度为自研二次计算。
三、数据表设计
sql
CREATE TABLE IF NOT EXISTS scan_newhigh (
dm TEXT, t TEXT, c REAL, zdf REAL, hs REAL,
iscq INTEGER, zdf5 REAL, zdf10 REAL, zdf20 REAL,
PRIMARY KEY (dm, t)
);
CREATE TABLE IF NOT EXISTS scan_newlow (
dm TEXT, t TEXT, c REAL, zdf REAL, hs REAL,
iscq INTEGER, zdf5 REAL, zdf10 REAL, zdf20 REAL,
PRIMARY KEY (dm, t)
);
CREATE TABLE IF NOT EXISTS scan_breadth (
t TEXT PRIMARY KEY,
high_strength REAL,
low_panic REAL,
breadth REAL
);
四、完整代码
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):
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(path):
d = biying_api_get_retry(f"{BASE}/himk/{path}/{LICENCE}")
return d.get("data", []) if isinstance(d, dict) else []
def strength(rows):
highs = [r for r in rows if r.get("iscq") == 1]
if not highs:
return 0.0
strong = sum(1 for r in highs if (r.get("zdf") or 0) > 5)
return round(strong / len(highs), 3)
if __name__ == "__main__":
hi = fetch("pzxg"); lo = fetch("pzxd")
con = sqlite3.connect(DB_PATH)
for r in hi:
con.execute(
"INSERT OR REPLACE INTO scan_newhigh(dm,t,c,zdf,hs,iscq,zdf5,zdf10,zdf20)"
"VALUES(?,?,?,?,?,?,?,?,?)",
[r.get("dm"), r.get("t"), r.get("c"), r.get("zdf"), r.get("hs"),
r.get("iscq"), r.get("zdf5"), r.get("zdf10"), r.get("zdf20")])
for r in lo:
con.execute(
"INSERT OR REPLACE INTO scan_newlow(dm,t,c,zdf,hs,iscq,zdf5,zdf10,zdf20)"
"VALUES(?,?,?,?,?,?,?,?,?)",
[r.get("dm"), r.get("t"), r.get("c"), r.get("zdf"), r.get("hs"),
r.get("iscq"), r.get("zdf5"), r.get("zdf10"), r.get("zdf20")])
t = hi[0].get("t") if hi else (lo[0].get("t") if lo else "")
hs_ = strength(hi)
lp_ = strength(lo)
breadth = round((len(hi) - len(lo)), 3)
con.execute(
"INSERT OR REPLACE INTO scan_breadth(t,high_strength,low_panic,breadth)"
"VALUES(?,?,?,?)", (t, hs_, lp_, breadth))
con.commit(); con.close()
print(f"日期 {t} 创新高 {len(hi)} 只(强度{hs_}) 创新低 {len(lo)} 只(恐慌{lp_}) 宽度{breadth}")
五、关键业务说明
iscq是现成标记:接口已判创新高/低,直接用它分桶,不用自己算 N 日高低。- 强度看占比非数量:牛市新高数量天然多,用「强占比」归一才有跨日可比性。
- 宽度是逆向指标 :
breadth极端负值时往往临近情绪底部,但非买卖信号。
六、拓展练习
- 把
scan_breadth按日落库一周,画牛熊宽度序列,找情绪拐点。 - 对创新高股叠加第 5 篇板块映射,看新高是否集中在同一板块(主线确认)。
- 用
zdf20把「20 日新高且涨幅温和」的标的单独成池(仅统计)。
下篇预告
A股量化数据工程:从 REST 接口到策略信号(第 18 篇):放量缩量异动扫描
下一篇用
himk/cjzz/cjzj/lxfl/lxsl拉取成交骤变与连续量能异动,自研「量能温度计」。
免责申明 :本篇全部代码、接口调用仅作为量化编程学习演示,仅为数据演示,不构成投资建议。市场有风险,投资需谨慎。