A股量化数据工程:从 REST 接口到策略信号(第 7 篇):盈利能力因子:毛利率、净利率与 ROE
前言
价格与资金维度跑完,进入基本面。盈利是公司质量的底盘:毛利率看生意模式,净利率看管控,ROE 看为股东赚钱的效率。接口 hicw/yl 一次性给出这三个核心值,本篇把它们落库,并自研截面 z-score 打分,得到第一个可横比的基本面因子。
一、接口原始字段梳理
1)盈利能力接口
接口地址:https://api.biyingapi.com/hicw/yl/{LICENCE}
| 字段 | 说明 |
|---|---|
| dm | 股票代码 |
| mc | 股票名称 |
| jzcsy | 净资产收益率(ROE,接口原始字段) |
| jll | 净利率 |
| mll | 毛利率 |
| jlr | 净利润 |
| mgsy | 每股收益 |
| yysr | 营业收入 |
| mgzysr | 每股主营业务收入 |
| y | 年 |
| q | 季 |
| yq | 年季标识 |
二、自研衍生统计指标
- 截面 z-score :对
mll / jll / jzcsy在全市场做标准化,消除量纲,得三个子分。 - 综合盈利因子 :
z(mll) + z(jll) + z(jzcsy)等权合成,越大约强。 - 异常过滤 :
mll < 0或jzcsy为空的公司直接剔除,避免失真。
字段全部来自接口原始值,z-score 为自研二次计算,接口不返回排名。
三、数据表设计
sql
CREATE TABLE IF NOT EXISTS fin_yl (
dm TEXT,
yq TEXT,
mc TEXT,
mll REAL,
jll REAL,
jzcsy REAL,
jlr REAL,
mgsy REAL,
yysr REAL,
PRIMARY KEY (dm, yq)
);
CREATE TABLE IF NOT EXISTS factor_profit (
dm TEXT,
yq TEXT,
z_mll REAL,
z_jll REAL,
z_roe REAL,
score REAL,
PRIMARY KEY (dm, yq)
);
四、完整代码
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_yl():
data = biying_api_get_retry(f"{BASE}/hicw/yl/{LICENCE}")
return data.get("data", []) if isinstance(data, dict) else []
def zscore(vals):
xs = [v for v in vals if v is not None]
if len(xs) < 2:
return {}
mu = sum(xs) / len(xs)
var = sum((x - mu) ** 2 for x in xs) / len(xs)
sd = var ** 0.5 or 1
return {v: round((v - mu) / sd, 3) for v in xs}
def build_factor(rows):
valid = [r for r in rows if r.get("mll") is not None
and r.get("jll") is not None and r.get("jzcsy") is not None]
zm = zscore([r["mll"] for r in valid])
zj = zscore([r["jll"] for r in valid])
zr = zscore([r["jzcsy"] for r in valid])
out = []
for r in valid:
mll, jll, roe = r["mll"], r["jll"], r["jzcsy"]
score = round(zm.get(mll, 0) + zj.get(jll, 0) + zr.get(roe, 0), 3)
out.append((r["dm"], r["yq"], zm.get(mll, 0),
zj.get(jll, 0), zr.get(roe, 0), score))
return out
if __name__ == "__main__":
rows = fetch_yl()
con = sqlite3.connect(DB_PATH)
con.executemany(
"INSERT OR REPLACE INTO fin_yl"
"(dm,yq,mc,mll,jll,jzcsy,jlr,mgsy,yysr) VALUES(?,?,?,?,?,?,?,?,?)",
[[r.get("dm"), r.get("yq"), r.get("mc"), r.get("mll"), r.get("jll"),
r.get("jzcsy"), r.get("jlr"), r.get("mgsy"), r.get("yysr")]
for r in rows])
con.commit()
fac = build_factor(rows)
con.executemany(
"INSERT OR REPLACE INTO factor_profit"
"(dm,yq,z_mll,z_jll,z_roe,score) VALUES(?,?,?,?,?,?)", fac)
con.commit(); con.close()
top = sorted(fac, key=lambda x: x[5], reverse=True)[:5]
print("盈利因子 Top5:")
for dm, yq, a, b, c, s in top:
print(f" {dm} 综合分={s} (毛利z={a} 净利z={b} ROEz={c})")
五、关键业务说明
- 字段以接口为准 :
mll/jll/jzcsy为接口返回的盈利字段,具体会计口径以官方文档说明为准,代码不做重算。 - 截面才有可比性:z-score 必须同行业或全市场同窗口算,单只孤立看无意义。
- 负值剔除:毛利为负多为商业模式异常,因子合成前先过滤。
六、拓展练习
- 把 z-score 改成「行业内 z-score」(按
sshy行业分组),消除行业结构差异。 - 用
factor_profit与前几篇价格因子做相关性,看盈利因子是否有独立增量信息。 - 回测「盈利因子 Top 50」等权组合的历史收益(仅统计演示)。
下篇预告
A股量化数据工程:从 REST 接口到策略信号(第 8 篇):成长能力因子:营收与利润增速
下一篇用
hicw/cz拉取营收、净利、净资产、每股增速,自研成长因子,捕捉高景气公司。
免责申明 :本篇全部代码、接口调用仅作为量化编程学习演示,仅为数据演示,不构成投资建议。市场有风险,投资需谨慎。