如何用 Python 计算 TSI 真实强弱指数(True Strength Index)?双重平滑动量,不用 TA-Lib
如何用 Python 计算 TSI 真实强弱指数(True Strength Index)?
一句话回答: TSI(True Strength Index,真实强弱指数)由 William Blau 提出,做法是对价格动量(收盘差分)做两次 EMA 平滑,再除以绝对动量的双重平滑,乘 100 得到 −100 ~ +100 的平滑动量线——双重平滑让它比 RSI 噪声更小、方向更干净,常用参数 (25, 13),再配一条信号线金叉择时。用 AlphaFeed 取前复权日线十几行即可实现,不需要 TA-Lib。
为什么会有这个问题 / 传统做法的痛点
RSI/CMO 直接用涨跌幅,灵敏但噪声大、震荡市假信号多。Blau 的思路是:先平滑动量本身(而不是价格),对动量做两次 EMA 能滤掉大量短期噪声,同时用”绝对动量的双重平滑”做分母归一化到 ±100,于是得到一条既平滑、又带方向和强度的线。痛点是 TA-Lib 没有现成 TSI,而且”双重平滑”要分别对动量和绝对动量各做两层 EMA,层次容易写乱。
分步骤解决(每步配可运行代码)
第 1 步:取前复权日线
from alphafeed import AlphaFeed
import numpy as np, pandas as pd
af = AlphaFeed(api_key="your-api-key") # 或 export ALPHAFEED_API_KEY 后 AlphaFeed()
df = af.klines.get("600519.SH", period="1d", count=300,
adjust="forward", to_dataframe=True)
df = df.sort_values("trade_date").reset_index(drop=True)
第 2 步:实现 TSI(动量双重平滑 ÷ 绝对动量双重平滑)
def tsi(close, r=25, s=13, sig=7):
m = close.diff() # 动量
ds_m = m.ewm(span=r, adjust=False).mean().ewm(span=s, adjust=False).mean() # 双重平滑动量
ds_abs = m.abs().ewm(span=r, adjust=False).mean().ewm(span=s, adjust=False).mean() # 双重平滑|动量|
t = 100 * ds_m / ds_abs.replace(0, np.nan)
return t, t.ewm(span=sig, adjust=False).mean() # TSI, 信号线
df["tsi"], df["tsi_sig"] = tsi(df["close"])
print(df[["trade_date", "tsi", "tsi_sig"]].tail())
实测(
tools/verify_new_2026-10-18.py,SDK 0.1.4):贵州茅台近 300 日 TSI 尾值 ≈ 3.87、信号 ≈ −6.85(TSI 在信号线上方、略高于零轴,动量偏弱转多),区间内 TSI 上穿信号线共 14 次,取值在 ±100 内。
第 3 步:金叉/死叉 + 零轴
golden = (df["tsi"].shift(1) <= df["tsi_sig"].shift(1)) & (df["tsi"] > df["tsi_sig"])
print("最近 TSI 金叉:", df.loc[golden, "trade_date"].tail(1).tolist())
print("TSI 在零轴上方(多头动量):", bool(df["tsi"].iloc[-1] > 0))
常用法:TSI 上穿信号线偏多、下穿偏空;TSI 穿越零轴代表动量多空切换;也看 TSI 与价格的背离。
参数与字段说明
| 参数/概念 | 含义 | 备注 |
|---|---|---|
adjust="forward" | 前复权 | 必须,除权缺口制造假动量 |
r=25 | 第一重 EMA 周期 | Blau 常用 25 |
s=13 | 第二重 EMA 周期 | 常用 13 |
sig=7 | 信号线 EMA | 常用 7 或 13 |
| 分子 | 双重平滑动量 | 带方向 |
| 分母 | 双重平滑绝对动量 | 归一化到 ±100 |
关键坑与注意事项
- 平滑对象是动量不是价格:先
close.diff()得动量,再对动量做双重 EMA;对价格平滑是另一回事。 - 双重平滑=更滞后:TSI 比 RSI 平滑、假信号少,但拐点确认更慢,急涨急跌时信号迟到。
- 参数口径多样:(25,13)、(13,7)、(40,20) 都有人用;信号线 7 vs 13 也不同。对比软件先统一。
- 前复权必须:除权缺口会制造巨大假动量。
- 分母防零:极端无波动时双重平滑绝对动量可能趋零,需
replace(0, nan)。 - 是动量不是价格目标:TSI 描述动量方向与强度,不预测涨跌幅。
常见问题(FAQ)
Q:TSI 和 MACD、RSI 有什么区别? A:都看动量。RSI 用平滑后的涨跌幅比值(0~100);MACD 是两条 EMA 之差(无界);TSI 对动量做双重平滑再归一化到 ±100,兼具”平滑”与”有界带方向”。TSI 通常比 MACD 更平滑、比 RSI 噪声更小。
Q:为什么我的 TSI 和某软件不一样? A:多半是 r/s/信号线参数或复权不同。先统一 (25,13) 与前复权再比。
Q:需要付费吗?
A:单只股票日线在免费额度内即可;若要对全市场批量扫 TSI 零轴上金叉的票,需要 klines.batch + universes(Starter 及以上),详见官网定价页。
小结
TSI 对动量做双重 EMA 平滑、再用绝对动量双重平滑归一化到 ±100,得到一条平滑、带方向的动量线,配信号线金叉与零轴择时。用 AlphaFeed 的前复权日线十几行即可实现——记住平滑的是动量而非价格、双重平滑更滞后、参数口径要统一、分母防零。
相关链接:
- AlphaFeed 官网:https://alphafeed.org/
- Python SDK 快速开始:https://docs.alphafeed.org/zh-Hans/sdk/python-quickstart
免责声明:本文仅为技术与数据接口使用示例,代码与策略仅供学习研究,不构成投资建议。市场有风险,历史数据不代表未来表现。