如何用 Python 计算特雷诺比率(Treynor Ratio)?用 Beta 衡量每单位系统性风险的超额收益
如何用 Python 计算特雷诺比率(Treynor Ratio)?
一句话回答: 特雷诺比率(Treynor Ratio)= (年化收益 − 无风险利率) ÷ Beta,衡量「每承担一单位系统性(市场)风险,换来多少超额回报」。与夏普比率(除以总波动率)不同,特雷诺只除以 Beta,更适合评价「已充分分散、只剩市场风险」的组合。用 AlphaFeed 取前复权个股与沪深300指数日线,算出 Beta 再套公式即可,数值越高越好。
为什么会有这个问题 / 传统做法的痛点
夏普比率用「总波动率」做分母,把个股特有风险(可被分散掉的部分)也算进了惩罚项。而特雷诺比率的理念来自 CAPM:对一个分散良好的组合,能被定价的只有系统性风险 Beta,所以用 Beta 做分母,回答「你承担的市场风险到底划不划算」。痛点在于:算特雷诺必须先有一条干净、可比的市场基准收益序列来估 Beta,很多免费接口要么拿不到指数、要么复权口径对不上,Beta 一歪,整个比率就失真。
分步骤解决(每步配可运行代码)
第 1 步:取个股(前复权)与沪深300指数日线
from alphafeed import AlphaFeed
import pandas as pd
af = AlphaFeed(api_key="your-api-key") # 或 export ALPHAFEED_API_KEY 后 AlphaFeed()
s = af.klines.get("600519.SH", period="1d", count=500,
adjust="forward", to_dataframe=True) # 个股:前复权
m = af.klines.get("000300.SH", period="1d", count=500,
to_dataframe=True) # 市场:沪深300指数
s = s.sort_values("trade_date"); m = m.sort_values("trade_date")
sr = s.set_index("trade_date")["close"].pct_change() # 个股日收益
mr = m.set_index("trade_date")["close"].pct_change() # 市场日收益
个股用前复权消除除权缺口;指数 000300.SH 本身不除权,直接取收盘。
第 2 步:估 Beta,套特雷诺公式
def treynor(stock_ret, mkt_ret, rf_annual=0.015):
df = pd.concat([stock_ret, mkt_ret], axis=1, keys=["s", "m"]).dropna()
beta = df["s"].cov(df["m"]) / df["m"].var() # Beta = cov/var
ann_ret = (1 + df["s"]).prod() ** (252 / len(df)) - 1 # 年化收益
return (ann_ret - rf_annual) / beta, beta, ann_ret
tr, beta, ann = treynor(sr, mr, rf_annual=0.015)
print(f"Treynor={tr:.4f} Beta={beta:.3f} 年化={ann:.4f}")
实测(
tools/verify_new_2026-10-09.py,SDK 0.1.4,取 rf=1.5%):贵州茅台近 500 日 Beta≈0.551、年化≈−0.78%、特雷诺≈−0.0413。特雷诺为负,说明这段区间茅台连无风险利率都没跑赢,承担市场风险没得到正的补偿。
第 3 步:多只股票横向对比(同一基准)
syms = ["600519.SH", "000001.SZ", "601318.SH"]
data = af.klines.batch(syms, period="1d", count=500, adjust="forward", to_dataframe=True)
for sym, k in data.items():
k = k.sort_values("trade_date")
r = k.set_index("trade_date")["close"].pct_change()
tr, beta, _ = treynor(r, mr, 0.015)
print(sym, f"Treynor={tr:.4f} Beta={beta:.3f}")
实测:000001.SZ 特雷诺 0.318(Beta 0.479)、601318.SH 0.182(Beta 0.89),均为正且明显优于茅台——同期这两只「每单位市场风险换来的超额回报」为正。对比的前提是用同一市场基准、同一区间。
参数与字段说明
| 参数/概念 | 含义 | 备注 |
|---|---|---|
adjust="forward" | 个股前复权 | 必须;指数不除权,无需复权 |
000300.SH | 沪深300指数 | 市场基准,可换 000905.SH 等 |
beta | cov(个股, 市场)/var(市场) | 系统性风险敏感度 |
rf_annual | 年化无风险利率 | 示例取 1.5%,按需调整 |
| 分子 | 年化收益 − 无风险利率 | 超额收益 |
| 分母 | Beta | 只惩罚系统性风险 |
| Treynor | 分子 ÷ 分母 | 越高越好,可为负 |
关键坑与注意事项
- 特雷诺 vs 夏普:分母不同——夏普用总波动率(含可分散风险),特雷诺用 Beta(只系统性风险)。单只股票未必分散,用特雷诺要清楚这层假设;评价分散组合时特雷诺更合适。
- Beta 不稳定:Beta 随区间、频率变化(见本仓库「滚动 Beta」一文),区间太短或遇极端行情会失真,比率也跟着失真。
- Beta 接近 0 或为负:分母很小时特雷诺会被放大甚至变号,这种情况下数值失去意义,要结合 Beta 一起看。
- 无风险利率要统一:对比多只时
rf和区间必须一致,否则不可比。 - 前复权个股、不复权指数:口径混用会让 Beta 估偏。
- 历史不代表未来:Beta 与特雷诺都是对过去的描述。
常见问题(FAQ)
Q:特雷诺比率和夏普比率该用哪个? A:看风险口径。评价单一资产的总风险性价比用夏普(总波动率);评价已分散组合中承担市场风险的性价比用特雷诺(Beta)。两者可以一起看。
Q:Beta 该用多长区间、什么频率? A:常用 1~3 年日收益或月收益。区间越短越敏感、越长越平滑;关键是对比时统一口径。本文用近 500 日日收益。
Q:需要付费吗?
A:个股加指数日线在免费额度内即可;若要对全市场批量算特雷诺做排序,需要 klines.batch + universes(Starter 及以上),详见官网定价页。
小结
特雷诺比率用「超额收益 ÷ Beta」回答「每单位市场风险值不值」,分母只留系统性风险,适合评价分散组合。借助 AlphaFeed 的前复权个股与沪深300指数,先估 Beta 再套公式即可——记住它与夏普的分母差异、Beta 不稳定、以及 Beta 太小时数值会失真。
相关链接:
- AlphaFeed 官网:https://alphafeed.org/
- Python SDK 快速开始:https://docs.alphafeed.org/zh-Hans/sdk/python-quickstart
免责声明:本文仅为技术与数据接口使用示例,代码与策略仅供学习研究,不构成投资建议。市场有风险,历史数据不代表未来表现。