Momentum:TRIX(三重指数平滑平均线)技术指标详解
一、TRIX的定义
TRIX(Triple Exponentially Smoothed Average,三重指数平滑平均线) 是由Jack Hutson于1980年代开发的技术分析指标,属于动量震荡指标类型。该指标因其名字前三个字母发音似“Tricks”而被译为“神奇指标”。
核心设计理念
TRIX设计的核心是多重平滑技术。它通过对收盘价计算三次指数移动平均(EMA),然后计算该平均线的变化率,最终得到一个能够滤除市场“噪音”的震荡指标。
TRIX解决的核心问题
| 短期波动干扰明显 | 三重平滑有效过滤“噪音” |
| 金叉/死叉信号频繁 | 减少虚假信号产生 |
| 滞后性影响判断 | 通过计算变化率提升响应速度 |
TRIX的核心特征
| 理论基础 | 三重指数平滑 + 变化率(ROC)计算 |
| 指标类型 | 动量震荡指标 |
| 数值范围 | 无固定范围,围绕0轴波动 |
| 开发者 | Jack Hutson(1980年代) |
| 核心优势 | 过滤噪音、识别中长期趋势 |
TRIX与指数移动平均线(EMA)的关系
TRIX本质上是三次EMA计算结果的变动率。它不像传统EMA那样显示价格本身的位置,而是显示价格变化的速度和动量,因此通常被归类为震荡指标。
二、TRIX的计算方法
1. 核心计算公式
TRIX的计算过程包含四个核心步骤:
第一步:计算第一重EMA
E
M
A
1
=
E
M
A
(
C
l
o
s
e
,
N
)
\\mathrm{EMA}_1 = \\mathrm{EMA}(\\mathrm{Close}, N)
EMA1=EMA(Close,N) 第二步:计算第二重EMA
E
M
A
2
=
E
M
A
(
E
M
A
1
,
N
)
\\mathrm{EMA}_2 = \\mathrm{EMA}(\\mathrm{EMA}_1, N)
EMA2=EMA(EMA1,N) 第三步:计算第三重EMA
E
M
A
3
=
E
M
A
(
E
M
A
2
,
N
)
\\mathrm{EMA}_3 = \\mathrm{EMA}(\\mathrm{EMA}_2, N)
EMA3=EMA(EMA2,N) 第四步:计算TRIX值和信号线
T
R
I
X
=
E
M
A
3
(
t
)
−
E
M
A
3
(
t
−
1
)
E
M
A
3
(
t
−
1
)
×
100
\\mathrm{TRIX} = \\frac{\\mathrm{EMA}_3(t) – \\mathrm{EMA}_3(t – 1)}{\\mathrm{EMA}_3(t – 1)} \\times 100
TRIX=EMA3(t−1)EMA3(t)−EMA3(t−1)×100
TRIX 信号线
=
M
A
(
T
R
I
X
,
M
)
\\text{TRIX 信号线} = \\mathrm{MA}(\\mathrm{TRIX}, M)
TRIX 信号线=MA(TRIX,M)
其中:
-
N
N
N:EMA计算周期(默认值12-18) -
M
M
M:信号线平滑周期(默认值9) -
C
l
o
s
e
\\mathrm{Close}
Close:收盘价序列
2. 三重指数平滑的计算原理
三重指数平滑的实质是将指数移动平均(EMA)运算连续应用三次:
- 第一重EMA:对原始收盘价进行一次平滑
- 第二重EMA:对第一次平滑结果再次平滑
- 第三重EMA:对第二次平滑结果第三次平滑
这一过程显著减少价格“噪音”,保留中长期趋势主线。
3. 参数说明
| length / N | 12 / 15 / 18 | EMA周期 | 控制三重平滑的灵敏度 |
| signal | 9 | 信号线周期 | TRIX值的移动平均周期 |
| scalar | 100 | 缩放因子 | 将结果放大(默认100) |
参数选择说明:在pandas_ta库中,length参数默认为18,signal参数默认为9。部分传统用法中N常用12,M常用20或9。
4. 完整计算示例
假设某股票使用N=12,M=9,计算TRIX值:
数据准备阶段:
| 原始数据 | 收盘价序列 | P₁, P₂, …, P₂₀ |
| 第一重平滑 | EMA₁₂§ | 慢速线1 |
| 第二重平滑 | EMA₁₂(EMA₁₂§) | 慢速线2 |
| 第三重平滑 | EMA₁₂(EMA₁₂(EMA₁₂§)) | 慢速线3 |
最终计算:
| TRIX值 | (EMA₃(t) – EMA₃(t-1)) / EMA₃(t-1) × 100 |
| 信号线 | TRIX值的9周期SMA |
结果解读示例:
EMA₃(今日) = 108.50
EMA₃(昨日) = 106.20
TRIX = (108.50 – 106.20) / 106.20 × 100 = 2.17%
该TRIX值为正值,表明动量向上。
三、TRIX的使用方法
1. 零轴穿越——趋势转换信号
TRIX围绕0轴波动,零轴是最重要的趋势分界线:
| 看涨信号 | TRIX线从下方向上穿越零轴 | 动量从负转正,上升趋势可能开始 | 买入/做多 |
| 看跌信号 | TRIX线从上方向下穿越零轴 | 动量从正转负,下降趋势可能开始 | 卖出/做空 |
信号确认:穿越发生时若有成交量放大配合,信号可靠性显著提升。
2. 金叉与死叉——精确入场信号
这是TRIX指标产生交易信号的最常用方法:
| 金叉(买入) | TRIX线从下方向上穿越信号线 | 短期动量开始强于长期趋势 | 买入入场 |
| 死叉(卖出) | TRIX线从上方向下穿越信号线 | 短期动量开始弱于长期趋势 | 卖出离场 |
信号参考:
| 零轴上方金叉 | 强 | 上涨趋势中的最佳加仓点 |
| 零轴下方金叉 | 中等 | 空头反弹,谨慎参与 |
| 零轴上方死叉 | 中等 | 多头回调,可波段减仓 |
| 零轴下方死叉 | 强 | 空头延续,应及时离场 |
3. 趋势追踪——顺势持仓策略
TRIX在趋势行情中可作为持仓依据:
| TRIX > 0 且持续向上 | 多头动量持续增强 | 坚定持股,不宜轻易离场 |
| TRIX < 0 且持续向下 | 空头动量持续增强 | 持币观望,不宜抄底 |
| TRIX斜率变缓 | 动量开始衰减 | 做好离场准备 |
4. 背离信号——趋势反转预警
TRIX与价格走势的背离是重要的反转预警信号:
| 顶背离 | 价格创出新高 | TRIX未能创出新高(更低高点) | 上涨动能衰竭,卖出信号 |
| 底背离 | 价格创出新低 | TRIX未能创出新低(更高低点) | 下跌动能减弱,买入信号 |
信号增强条件:当背离出现在TRIX的极端值区域(如±20以上)时,反转信号更为可靠。
5. 多指标配合策略
TRIX在单一使用时建议与其他指标配合:
| MACD | 确认趋势方向 | 两个指标信号共振时可靠性更高 |
| RSI | 验证超买超卖 | RSI确认极端区域,避免追高杀低 |
| 成交量 | 验证资金流向 | TRIX信号伴随放量时可信度更高 |
| 移动平均线 | 价格位置确认 | 价格在MA上方时TRIX金叉信号更可靠 |
6. 注意事项与局限性
使用TRIX前需了解以下要点:
| 滞后性问题 | TRIX经过三重平滑,对快速市场变动的反应较慢,入场可能滞后 |
| 震荡市假信号 | 在横盘整理或无明显趋势的市场中,TRIX可能频繁发出错误的交叉信号 |
| 不适用于短线 | TRIX属于中长线指标,不适合短线或日内交易 |
| 波动市场局限性 | 在高波动性条件下,TRIX的表现可能受限 |
适用场景总结:
| 强趋势行情 | 最佳适用 | 趋势市场中信号准确率高 |
| 中长期持仓 | 适合 | 过滤噪音,把握主要趋势 |
| 震荡盘整 | 慎用 | 假信号较多,宜观望 |
| 短线交易 | 不建议 | 信号滞后,不适合短线 |
四、使用pandas_ta计算TRIX(附示例代码)
1. pandas_ta中的TRIX函数
pandas_ta库内置了TRIX指标的完整实现,函数位于momentum模块中。
2. 函数完整参数
pandas_ta.momentum.trix(close, length=None, signal=None, scalar=None, drift=None, offset=None, **kwargs)
参数详解:
| close | pd.Series | 必需 | 收盘价序列 |
| length | int | 18 | 三重EMA计算周期 |
| signal | int | 9 | 信号线(Signal Line)SMA周期 |
| scalar | float | 100 | 缩放因子,将结果放大100倍 |
| drift | int | 1 | 差分时间间隔 |
| offset | int | 0 | 结果偏移周期数 |
返回值:pd.DataFrame——包含两列:
- TRIX_{length}_{signal}_{scalar}_{drift}:TRIX主线
- TRIXs_{length}_{signal}_{scalar}_{drift}:信号线
3. 示例代码
import pandas as pd
import pandas_ta as ta
import numpy as np
import matplotlib.pyplot as plt
# ========== 第一步:准备数据 ==========
np.random.seed(42)
dates = pd.date_range(start='2022-01-01', end='2024-12-31', freq='D')
n = len(dates)
# 生成带趋势和周期波动的价格序列
trend = np.linspace(0, 45, n)
cycle = np.sin(np.linspace(0, 6 * np.pi, n)) * 15
noise = np.random.randn(n) * 3
price_series = 100 + trend + cycle + noise
# 添加趋势变化区间
price_series = price_series.astype(float)
for i in range(300, 450):
price_series[i] = price_series[300] + (i–300) * 0.2 # 强势上涨段
for i in range(450, 600):
price_series[i] = price_series[450] – (i–450) * 0.15 # 强势下跌段
df = pd.DataFrame(index=dates[:n])
df['close'] = price_series[:n]
df['high'] = df['close'] + np.abs(np.random.randn(n)) * 2 + 1
df['low'] = df['close'] – np.abs(np.random.randn(n)) * 2 – 1
df['volume'] = np.random.randint(1000000, 25000000, n)
print("=" * 60)
print("数据预览:")
print(df.head())
print("\\n" + "=" * 60 + "\\n")
# ========== 第二步:计算TRIX(基础用法) ==========
# 使用默认参数 length=18, signal=9, scalar=100
trix_df = ta.trix(df['close'])
# 查看返回的DataFrame结构
print("TRIX返回列名称:")
print(trix_df.columns.tolist())
print("\\n" + "=" * 60 + "\\n")
# 将计算结果添加到原DataFrame
df['TRIX'] = trix_df.iloc[:, 0] # TRIX主线
df['TRIXs'] = trix_df.iloc[:, 1] # 信号线
print("TRIX计算结果(最近10行):")
print(df[['close', 'TRIX', 'TRIXs']].tail(10))
print("\\n" + "=" * 60 + "\\n")
# ========== 第三步:手动验证TRIX计算 ==========
def manual_trix(close, length=18, signal=9, scalar=100):
"""手动计算TRIX验证pandas_ta结果"""
# 计算三重EMA
ema1 = close.ewm(span=length, adjust=False).mean()
ema2 = ema1.ewm(span=length, adjust=False).mean()
ema3 = ema2.ewm(span=length, adjust=False).mean()
# 计算TRIX(百分比变化率)
trix = (ema3 – ema3.shift(1)) / ema3.shift(1) * scalar
trix = trix.fillna(0)
# 计算信号线
signal_line = trix.rolling(window=signal).mean()
return trix, signal_line
df['TRIX_manual'], df['TRIXs_manual'] = manual_trix(df['close'])
# 验证一致性
diff_trix = (df['TRIX'] – df['TRIX_manual']).abs().max()
diff_signal = (df['TRIXs'] – df['TRIXs_manual']).abs().max()
print(f"TRIX主线手动验证最大差异:{diff_trix:.10f}")
print(f"信号线手动验证最大差异:{diff_signal:.10f}")
print("\\n" + "=" * 60 + "\\n")
# ========== 第四步:不同参数的TRIX对比 ==========
# 标准参数 (18,9)
trix_std = ta.trix(df['close'])
df['TRIX_std'] = trix_std.iloc[:, 0]
# 短线参数 (12,9) – 更灵敏
trix_fast = ta.trix(df['close'], length=12, signal=9)
df['TRIX_fast'] = trix_fast.iloc[:, 0]
# 长线参数 (24,12) – 更平滑
trix_slow = ta.trix(df['close'], length=24, signal=12)
df['TRIX_slow'] = trix_slow.iloc[:, 0]
print("不同参数TRIX对比(最近5行):")
print(df[['close', 'TRIX_std', 'TRIX_fast', 'TRIX_slow']].tail())
print("\\n" + "=" * 60 + "\\n")
# ========== 第五步:传统参数模式(N=12, M=20) ==========
# 使用传统参数组合进行计算验证
trix_traditional = ta.trix(df['close'], length=12, signal=20)
df['TRIX_traditional'] = trix_traditional.iloc[:, 0]
df['TRIXs_traditional'] = trix_traditional.iloc[:, 1]
print("传统参数TRIX计算结果(最近10行):")
print(df[['close', 'TRIX_traditional', 'TRIXs_traditional']].tail(10))
print("\\n" + "=" * 60 + "\\n")
# ========== 第六步:零轴穿越信号 ==========
df['TRIX_above_zero'] = df['TRIX'] > 0
df['cross_above_zero'] = (df['TRIX_above_zero'] == True) & (df['TRIX_above_zero'].shift(1) == False)
df['cross_below_zero'] = (df['TRIX_above_zero'] == False) & (df['TRIX_above_zero'].shift(1) == True)
df['zero_signal'] = ''
df.loc[df['cross_above_zero'], 'zero_signal'] = '上穿零轴(买入信号)'
df.loc[df['cross_below_zero'], 'zero_signal'] = '下穿零轴(卖出信号)'
print("零轴穿越信号统计:")
print(f"上穿零轴数量:{df['cross_above_zero'].sum()}")
print(f"下穿零轴数量:{df['cross_below_zero'].sum()}")
print("\\n" + "=" * 60 + "\\n")
# ========== 第七步:金叉死叉信号 ==========
# 金叉:TRIX上穿信号线
df['golden_cross'] = (df['TRIX'] > df['TRIXs']) & (df['TRIX'].shift(1) <= df['TRIXs'].shift(1))
# 死叉:TRIX下穿信号线
df['death_cross'] = (df['TRIX'] < df['TRIXs']) & (df['TRIX'].shift(1) >= df['TRIXs'].shift(1))
# 区分交叉位置
df['strong_golden'] = df['golden_cross'] & (df['TRIX'] > 0)
df['weak_golden'] = df['golden_cross'] & (df['TRIX'] <= 0)
df['strong_death'] = df['death_cross'] & (df['TRIX'] < 0)
df['weak_death'] = df['death_cross'] & (df['TRIX'] >= 0)
df['trade_signal'] = ''
df.loc[df['strong_golden'], 'trade_signal'] = '强势金叉(买入信号)'
df.loc[df['weak_golden'], 'trade_signal'] = '弱势金叉(参考)'
df.loc[df['strong_death'], 'trade_signal'] = '强势死叉(卖出信号)'
df.loc[df['weak_death'], 'trade_signal'] = '弱势死叉(参考)'
print("金叉死叉信号统计:")
print(f"金叉(买入)数量:{df['golden_cross'].sum()}")
print(f" 其中强势金叉(TRIX>0):{df['strong_golden'].sum()}")
print(f"死叉(卖出)数量:{df['death_cross'].sum()}")
print(f" 其中强势死叉(TRIX<0):{df['strong_death'].sum()}")
print("\\n最近15个交易信号:")
signals = df[df['trade_signal'] != ''].tail(15)
if not signals.empty:
print(signals[['close', 'TRIX', 'TRIXs', 'trade_signal']])
print("\\n" + "=" * 60 + "\\n")
# ========== 第八步:背离检测(简化版) ==========
# 计算20日价格变化和TRIX变化
df['price_change_20d'] = df['close'].diff(20)
df['trix_change_20d'] = df['TRIX'].diff(20)
# 检测潜在背离
df['potential_bearish_div'] = (df['price_change_20d'] > 0) & (df['trix_change_20d'] < 0)
df['potential_bullish_div'] = (df['price_change_20d'] < 0) & (df['trix_change_20d'] > 0)
print("潜在背离信号统计(20日尺度):")
print(f"潜在顶背离(价格涨TRIX跌)数量:{df['potential_bearish_div'].sum()}")
print(f"潜在底背离(价格跌TRIX涨)数量:{df['potential_bullish_div'].sum()}")
print("注:完整背离需结合局部高/低点分析,此处为方向对比")
print("\\n" + "=" * 60 + "\\n")
# ========== 第九步:策略回测(零轴穿越策略) ==========
# 策略:TRIX上穿零轴买入,下穿零轴卖出
df['position_zero'] = 0
in_position = False
for i in range(1, len(df)):
if not in_position and df['cross_above_zero'].iloc[i]:
df.loc[df.index[i], 'position_zero'] = 1
in_position = True
elif in_position and df['cross_below_zero'].iloc[i]:
df.loc[df.index[i], 'position_zero'] = 0
in_position = False
else:
df.loc[df.index[i], 'position_zero'] = df['position_zero'].iloc[i–1]
# 策略2:金叉买入,死叉卖出
df['position_cross'] = 0
in_position = False
for i in range(1, len(df)):
if not in_position and df['golden_cross'].iloc[i]:
df.loc[df.index[i], 'position_cross'] = 1
in_position = True
elif in_position and df['death_cross'].iloc[i]:
df.loc[df.index[i], 'position_cross'] = 0
in_position = False
else:
df.loc[df.index[i], 'position_cross'] = df['position_cross'].iloc[i–1]
# 计算收益
df['returns'] = df['close'].pct_change()
df['strategy_zero_returns'] = df['position_zero'].shift(1) * df['returns']
df['strategy_cross_returns'] = df['position_cross'].shift(1) * df['returns']
total_return_buyhold = (1 + df['returns']).prod() – 1
total_return_zero = (1 + df['strategy_zero_returns']).prod() – 1
total_return_cross = (1 + df['strategy_cross_returns']).prod() – 1
print("=" * 60)
print("策略绩效统计(TRIX策略回测):")
print(f"买入持有策略总收益率:{total_return_buyhold:.2%}")
print(f"零轴穿越策略总收益率:{total_return_zero:.2%}")
print(f"金叉死叉策略总收益率:{total_return_cross:.2%}")
print("\\n注意:此为简化回测,仅供参考;TRIX是中长线指标,建议用于日线及以上周期")
print("=" * 60 + "\\n")
# ========== 第十步:趋势强度判断 ==========
def classify_trix_strength(trix):
"""根据TRIX值大小判断趋势强度"""
if trix > 4.0:
return '强势上涨'
elif 1.5 < trix <= 4.0:
return '温和上涨'
elif 0 < trix <= 1.5:
return '弱势上涨'
elif –1.5 <= trix < 0:
return '弱势下跌'
elif –4.0 <= trix < –1.5:
return '温和下跌'
else:
return '强势下跌'
df['strength_signal'] = df['TRIX'].apply(classify_trix_strength)
print("趋势强度分布统计:")
print(df['strength_signal'].value_counts())
print("\\n" + "=" * 60 + "\\n")
# ========== 第十一步:可视化 ==========
plt.figure(figsize=(14, 12))
# 子图1:价格走势
plt.subplot(2, 1, 1)
plt.plot(df.index[–200:], df['close'][–200:], label='Close Price',
linewidth=1.5, color='black')
plt.title('Price Chart (Last 200 days)', fontsize=14)
plt.ylabel('Price')
plt.legend()
plt.grid(True, alpha=0.3)
# 子图2:TRIX指标
plt.subplot(2, 1, 2)
plt.plot(df.index[–200:], df['TRIX'][–200:], label='TRIX主线',
linewidth=1.5, color='blue')
plt.plot(df.index[–200:], df['TRIXs'][–200:], label='信号线',
linewidth=1.5, color='orange', linestyle='–')
plt.axhline(y=0, color='red', linestyle='-', linewidth=1.5, label='零轴')
# 填充零轴上下区域
plt.fill_between(df.index[–200:], 0, df['TRIX'][–200:],
alpha=0.1, color='green', where=(df['TRIX'][–200:] > 0))
plt.fill_between(df.index[–200:], df['TRIX'][–200:], 0,
alpha=0.1, color='red', where=(df['TRIX'][–200:] < 0))
# 标记交叉点
golden_signals = df[df['golden_cross']]
death_signals = df[df['death_cross']]
plt.scatter(golden_signals.index[–25:], golden_signals['TRIX'][–25:],
color='green', marker='^', s=80, label='金叉(买入)', alpha=0.8)
plt.scatter(death_signals.index[–25:], death_signals['TRIX'][–25:],
color='red', marker='v', s=80, label='死叉(卖出)', alpha=0.8)
plt.title('TRIX(三重指数平滑平均线)- 多重平滑与金叉死叉', fontsize=14)
plt.xlabel('Date')
plt.ylabel('TRIX Value (%)')
plt.legend(loc='upper left')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# ========== 第十二步:数据清洗提示 ==========
nan_count = df['TRIX'].isna().sum()
print(f"\\nTRIX初始NaN数量:{nan_count}")
print("原因:TRIX需要至少length个周期的数据才能完成三重EMA计算")
print("处理建议:df_clean = df.iloc[18:].copy()")
print("\\n" + "=" * 60)
print("TRIX使用提示:")
print("1. TRIX是中长线指标,适合日线及以上周期使用")
print("2. 零轴穿越是最基础的信号:上穿买入,下穿卖出")
print("3. 金叉死叉是更精确的入场信号")
print("4. 三重平滑有效过滤噪音,适合趋势跟踪策略")
print("5. 建议与RSI、MACD等指标配合使用,提高信号可靠性")
print("6. 震荡市中TRIX假信号较多,应结合市场环境使用")
print("=" * 60)
五、总结
TRIX(三重指数平滑平均线)是一种通过三重EMA平滑技术过滤市场噪音的动量指标,其核心价值与定位如下:
| 核心创新 | 三重指数平滑 + 变化率计算 |
| 核心公式 | TRIX = (EMA₃ – EMA₃₍ₜ₋₁₎) / EMA₃₍ₜ₋₁₎ × 100 |
| 双线结构 | TRIX主线 + 信号线 |
| 三大核心信号 | 零轴穿越、金叉死叉、顶底背离 |
| 默认参数 | length=18, signal=9 |
| 最佳应用场景 | 中长期趋势识别、趋势跟踪策略、过滤市场噪音 |
| 主要局限 | 滞后性、不适用于震荡市与短线交易 |
实战使用三原则:
最后提醒:TRIX的最大价值在于其多重平滑特性,能够有效滤除市场噪音,帮助交易者聚焦于中长期趋势。它不像其他震荡指标那样频繁发出信号,而是等待真正有价值的趋势转折点才给出提示。然而,这种稳健是有代价的——在短线交易和震荡市场中,TRIX的滞后性可能成为弱点。因此,使用TRIX的关键是明确交易周期和适用场景:将其用作中长线趋势跟踪的辅助工具,与MACD、RSI等指标配合,才能发挥最大效用。



