Momentum:SQUEEZE(挤压动量指标)技术指标详解

Momentum:SQUEEZE(挤压动量指标)技术指标详解

一、SQUEEZE的定义

SQUEEZE(挤压动量指标,全称TTM Squeeze) 是由知名交易员John Carter在其著作《Mastering the Trade》(第11章)中正式推出的一种高级波动率与动量复合指标。该指标通过结合**布林带(Bollinger Bands)肯特纳通道(Keltner Channels)**的特性,精准捕捉趋势启动前的蓄势阶段,旨在识别波动率收缩之后的爆发性行情。

核心思想

在海啸来临之前,最前端的波浪会短暂退潮,海面看似风平浪静,实则正暗中积蓄力量。挤压动量指标的核心理念正源于此------当市场进入低波动率"挤压"状态时,往往是重大趋势行情爆发的前奏。

具体而言,SQUEEZE指标的判断逻辑基于两类通道的相对位置:

  • 布林带:基于标准差构建,波动增强时变宽,波动减弱时收窄
  • 肯特纳通道:基于平均真实波幅(ATR)构建,反映价格的实际波动范围

当市场波动率降低至极低水平时,布林带的上下轨会完全收窄至肯特纳通道的内部------此时即为"挤压开启"(Squeeze On)状态,表明多空双方处于短暂均衡,价格随时可能因资金或消息驱动而突破平衡区间,引发强趋势行情。当布林带重新张开并突破肯特纳通道的边界时,说明"挤压解除"(Squeeze Off),市场进入动量释放阶段。

SQUEEZE的核心特征

特征 说明
理论基础 波动率收缩-扩张周期理论(类似"弹簧压缩"效应)
核心组件 布林带 + 肯特纳通道 + 动量震荡柱
指标类型 波动率/动量复合型指标
开发者 John Carter(TTM Squeeze)
TradingView排名 点赞数最多的技术指标

SQUEEZE的三大组成部分

SQUEEZE指标由三部分协同构成,分别反映不同维度的市场信息:

组成部分 名称 表现形式 功能描述
SQZ_ON/SQZ_OFF 挤压状态指示灯 零轴线上的红色/绿色圆点 红灯(挤压开启)=低波动率蓄势;绿灯(挤压解除)=高波动率爆发
动量柱(Momentum Histogram) 挤压动量值 围绕零轴波动的柱状图 正值=多头动能,负值=空头动能,绝对值越大动能越强
SQZ_NO 无挤压状态 无声区 市场处于正常波动,两通道未完全重叠

同一根K线只会满足上述三种挤压状态中的一种------SQZ_ON、SQZ_OFF或SQZ_NO在单根K线上最多只有一个为1,其余两个为0。

二、SQUEEZE的计算方法

SQUEEZE的计算逻辑分为三个核心步骤:布林带与肯特纳通道的构建、挤压状态判断、动量值的平滑处理。

1. 布林带(Bollinger Bands)的计算

设周期 n=20n=20n=20,标准差倍数为 k=2k=2k=2:

中轨(SMA线):

BB_MIDt=SMA20(Close)t \mathrm{BB\_MID}t = \mathrm{SMA}{20}(\mathrm{Close})t BB_MIDt=SMA20(Close)t

上轨和下轨:

BB_HIGHt=BB_MIDt+k×σtBB_LOWt=BB_MIDt−k×σt \begin{aligned} \mathrm{BB\_HIGH}_t &= \mathrm{BB\_MID}_t + k \times \sigma_t \\ \mathrm{BB\_LOW}_t &= \mathrm{BB\_MID}_t - k \times \sigma_t \end{aligned} BB_HIGHtBB_LOWt=BB_MIDt+k×σt=BB_MIDt−k×σt

其中 σt\sigma_tσt 为过去20日收盘价的标准差。当市场波动增强时,标准差增大,布林带变宽;波动减弱时,布林带收窄。

2. 肯特纳通道(Keltner Channels)的计算

肯特纳通道以指数移动平均线(EMA)为中轴,基于平均真实波幅(ATR)构建通道宽度:

中轨(EMA线):

KC_MIDt=EMA20(Close)t \mathrm{KC\_MID}t = \mathrm{EMA}{20}(\mathrm{Close})_t KC_MIDt=EMA20(Close)t

首先计算真实波幅(True Range, TR):

TRt=max⁡(Ht−Lt,∣Ht−Ct−1∣,∣Lt−Ct−1∣) \mathrm{TR}t = \max(H_t - L_t, |H_t - C{t-1}|, |L_t - C_{t-1}|) TRt=max(Ht−Lt,∣Ht−Ct−1∣,∣Lt−Ct−1∣)

对 TR\mathrm{TR}TR 取 202020 周期 EMA 得到 ATR 值:

ATR20,t=EMA20(TR)t \mathrm{ATR}{20,t} = \mathrm{EMA}{20}(\mathrm{TR})_t ATR20,t=EMA20(TR)t

上轨和下轨(乘数为 m=1.5m = 1.5m=1.5):

KC_HIGHt=KC_MIDt+m×ATR20,tKC_LOWt=KC_MIDt−m×ATR20,t \begin{aligned} \mathrm{KC\_HIGH}_t &= \mathrm{KC\_MID}t + m \times \mathrm{ATR}{20,t} \\ \mathrm{KC\_LOW}_t &= \mathrm{KC\_MID}t - m \times \mathrm{ATR}{20,t} \end{aligned} KC_HIGHtKC_LOWt=KC_MIDt+m×ATR20,t=KC_MIDt−m×ATR20,t

ATR基于真实波幅计算,不仅考虑了当日的价格波动,也将跳空缺口的剧烈波动纳入衡量范围,因此肯特纳通道对极端价格跳变更为敏感。

3. 挤压状态的数学判定

挤压状态的判定通过比较布林带与肯特纳通道的相对位置实现:

挤压开启(SQZ_ON = 1)

SQZ_ONt=1{BB_HIGHt<KC_HIGHt∧BB_LOWt>KC_LOWt} \mathrm{SQZ\_ON}t = \mathbf{1}{\{\mathrm{BB\_HIGH}_t < \mathrm{KC\_HIGH}_t \land \mathrm{BB\_LOW}_t > \mathrm{KC\_LOW}_t\}} SQZ_ONt=1{BB_HIGHt<KC_HIGHt∧BB_LOWt>KC_LOWt}

即布林带的上轨低于 肯特纳上轨,且布林带的下轨高于肯特纳下轨时,表明布林带被完全"套在"肯特纳通道内部,波动率处于极低水平。

挤压解除(SQZ_OFF = 1)

SQZ_OFFt=1{BB_HIGHt>KC_HIGHt∨BB_LOWt<KC_LOWt} \mathrm{SQZ\_OFF}t = \mathbf{1}{\{\mathrm{BB\_HIGH}_t > \mathrm{KC\_HIGH}_t \lor \mathrm{BB\_LOW}_t < \mathrm{KC\_LOW}_t\}} SQZ_OFFt=1{BB_HIGHt>KC_HIGHt∨BB_LOWt<KC_LOWt}

即布林带上轨高于肯特纳上轨,或布林带下轨低于肯特纳下轨时,表明布林带已突破肯特纳通道边界,波动率扩张,行情即将爆发。

无挤压状态(SQZ_NO = 1)

SQZ_NOt=1{−SQZ_ON∧−SQZ_OFF} \mathrm{SQZ\_NO}t = \mathbf{1}{\{-\mathrm{SQZ\_ON} \land -\mathrm{SQZ\_OFF}\}} SQZ_NOt=1{−SQZ_ON∧−SQZ_OFF}

即不属于SQZ_ON也不属于SQZ_OFF的"中间态"------两通道交错但未完全重叠,市场处于正常波动状态。

4. 动量柱(Momentum Histogram)的计算

动量柱的计算过程为:

第一步:计算价格动量

MOM=Close−REF(Close,mom_length−1) \mathrm{MOM} = \mathrm{Close} - \mathrm{REF}(\mathrm{Close}, \mathrm{mom\_length} - 1) MOM=Close−REF(Close,mom_length−1)

其中mom_length为动量周期(默认12)。

第二步:对MOM取平滑

mamode == "ema"

SQZ=EMA(MOM,mom_smooth) \mathrm{SQZ=EMA(MOM,mom\_smooth)} SQZ=EMA(MOM,mom_smooth)

mamode == "sma"

SQZ=SMA(MOM,mom_smooth) \mathrm{SQZ = SMA(MOM, mom\_smooth)} SQZ=SMA(MOM,mom_smooth)

其中mom_smooth为动量平滑周期(默认6)。

第三步:输出动量柱

动量柱即是平滑后的SQZ值。正值 表示收盘价相对于过去12日持续走高、买盘增强,未来上涨动能概率较大;负值表示收盘价走低、卖盘增强,未来下跌动能概率较大。柱子的高度反映动能大小。

5. 参数说明(标准版)

参数 默认值 说明
bb_length 20 布林带计算周期
bb_std 2.0 布林带标准差倍数
kc_length 20 肯特纳通道计算周期
kc_scalar 1.5 肯特纳通道ATR乘数
mom_length 12 动量计算周期
mom_smooth 6 动量平滑周期
use_tr True 是否使用真实波幅(否则用High-Low)
lazybear False 是否使用LazyBear版本算法

三、SQUEEZE的使用方法

1. 三阶段交易法------核心用法

SQUEEZE指标的使用遵循一套系统的流程:识别挤压 → 等待解除 → 跟随动量。

阶段 指标状态 市场含义 操作策略
① 挤压开启 SQZ_ON = 1(红点) 波动率收缩至低点,多空力量平衡,正在积蓄能量 关注预警,准备交易计划
② 挤压解除 SQZ_OFF = 1(绿点) 波动率扩张,突破即将发生 准备建仓,等待方向确认
③ 方向确认 动量柱为正/为负 多方/空方开始主导市场 执行顺势交易

挤压开启阶段------市场处于低波动蓄势期,此时不宜提前入场,而应将此阶段视为预警信号。当红点出现后,需耐心等待"点火"信号的到来。

2. 动量柱的方向与强度判断

动量柱(Momentum Histogram)是判断趋势方向和动能强度的核心工具:

动量柱状态 市场含义 操作倾向
正值且持续扩大(绿色) 多头动能增强,买方主导 做多为主,顺势持仓
正值但持续缩小 多头动能减弱,上涨乏力 考虑减仓、锁定利润
负值且持续扩大(红色) 空头动能增强,卖方主导 做空为主,顺势持仓
负值但持续缩小 空头动能减弱,下跌放缓 考虑空头平仓、关注反弹
绝对值极大 极端动能释放 趋势加速,但需警惕物极必反

动量柱的横截面还可以反映多空力量的对比:上穿零轴(从负转正)是多头信号,下穿零轴(从正转负)是空头信号。

3. 完整的四步交易流程

步骤一:识别挤压状态(SQZ_ON = 1)

当图表上出现连续的红点(挤压开启)时,意味着市场进入低波动蓄势阶段,应保持高度警惕。

步骤二:等待挤压解除(SQZ_OFF = 1)

挤压开启状态的终结,往往以突然的一根"放大K线"为标志。此时布林带突破肯特纳通道,红点转变为绿点(挤压解除)。

步骤三:跟随动量柱方向

  • 若挤压解除时动量柱为正值(绿色),预示着向上突破------买入
  • 若挤压解除时动量柱为负值(红色),预示着向下突破------卖出

步骤四:持仓管理与离场

只要动量柱保持同向(正值维持正值,负值维持负值),趋势大概率会延续。当动能减弱(柱子高度明显缩小或由正转负)时,应考虑平仓。

4. 多周期信号共振增强

SQUEEZE在较高时间框架(如日线、4小时)上识别出的挤压突破,往往比小周期(如15分钟)的信号更具持续性和可靠性。可以结合多周期共振确认:

共振类型 确认方式 信号含义
大周期(日线)+ 小周期(4H)同时SQZ_OFF 双重挤压解除 信号可靠性大幅提升
大周期动量柱为正值 + 小周期同步 多周期动量共振 趋势加速概率增加

5. 常见误区与实战技巧

误区一:在挤压开启时提前入场

许多初学者见到"挤压开启"信号就急于买入,认为波动即将爆发。但这只是蓄势的开始,挤压状态可能持续数周。在没有确认突破方向之前提前入场,可能面临长时间的资金占用甚至被"假突破"来回洗盘。

误区二:忽视挤压解除时的动量柱方向

挤压解除本身只代表波动率将扩张,但扩张方向并不确定。必须结合动量柱的颜色来判断方向:红点转绿点时若动量柱为正做多,为负做空

误区三:在强趋势中频繁交易

挤压动量策略本质上是趋势跟踪策略,在强趋势行情中应减少不必要的开仓频率,待趋势确立后顺势持仓。

6. 适用品种与局限性

最佳适用品种:在周期性较为明确、趋势延续性强的品种上,SQUEEZE表现出较高的准确率,例如:

  • 主流货币对(如EUR/USD)
  • 指数(如标普500、纳斯达克)
  • 大宗商品(如黄金、原油)

局限性

  • 在价格经常快速反转、震荡频繁且缺乏明显趋势的品种上,挤压可能被反复触发,导致假突破信号较多
  • 在高频交易(如15分钟级别)中,手续费成本可能严重影响策略的净利润,即使信号准确率高也可能因频繁开仓而亏损
  • 信号具有滞后性:当挤压解除确认信号在图表上出现时,价格往往已启动一段距离,可能导致在局部高位追入、随后面临回调

改善措施:建议引入ADX指标(趋势强度指数)作为过滤器------当ADX > 25时再考虑交易,避免在震荡市中因频繁开仓消耗本金。

四、使用pandas_ta计算SQUEEZE(附示例代码)

1. pandas_ta中的SQUEEZE函数

pandas_ta库内置了SQUEEZE指标的完整实现,函数位于momentum模块中。该库是基于Pandas DataFrame的Python技术分析库,提供130多个指标和实用程序函数。

2. 函数完整参数

python 复制代码
pandas_ta.momentum.squeeze(
    high, low, close,
    bb_length=None, bb_std=None,
    kc_length=None, kc_scalar=None,
    mom_length=None, mom_smooth=None,
    use_tr=None, mamode=None,
    offset=None, **kwargs
)

参数详解

参数 类型 默认值 说明
high pd.Series 必需 最高价序列
low pd.Series 必需 最低价序列
close pd.Series 必需 收盘价序列
bb_length int 20 布林带计算周期
bb_std float 2.0 布林带标准差倍数
kc_length int 20 肯特纳通道计算周期
kc_scalar float 1.5 肯特纳通道ATR乘数
mom_length int 12 动量计算周期
mom_smooth int 6 动量平滑周期
use_tr bool True 是否使用真实波幅(否则用High-Low)
mamode str "ema" 移动平均类型('ema'或'sma')
lazybear bool False 是否使用LazyBear版本
offset int 0 结果偏移周期数

返回值pd.DataFrame------包含以下列:

  • SQZ_{bb_length}_{bb_std}_{kc_length}_{kc_scalar}:挤压动量值(动量柱)
  • SQZ_ON:挤压开启状态(1=开启,0=未开启)
  • SQZ_OFF:挤压解除状态(1=解除,0=未解除)
  • SQZ_NO:无挤压状态(1=无挤压,0=有挤压)

3. 示例代码

python 复制代码
import pandas as pd
import pandas_ta as ta
import numpy as np
import matplotlib.pyplot as plt
import yfinance as yf  # 可选:用于获取真实数据

# ========== 第一步:准备数据 ==========
# 方式一:使用yfinance获取真实数据
# df = yf.download("BTC-USD", start="2023-01-01", end="2024-12-31")

# 方式二:生成示例数据(演示用)
np.random.seed(42)
dates = pd.date_range(start='2023-01-01', end='2024-12-31', freq='D')
n = len(dates)

# 生成带趋势和周期波动的价格序列(包含低波动区间)
trend = np.linspace(0, 35, n)
cycle = np.sin(np.linspace(0, 4 * np.pi, n)) * 12
noise = np.random.randn(n) * 2
price_series = 100 + trend + cycle + noise

# 添加一个低波动率区间(模拟挤压状态)
low_vol_start = 300
low_vol_end = 400
price_series[low_vol_start:low_vol_end] = price_series[low_vol_start] + np.random.randn(low_vol_end - low_vol_start) * 1

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(5000000, 30000000, n)

print("=" * 60)
print("数据预览:")
print(df.head())
print("\n" + "=" * 60 + "\n")

# ========== 第二步:计算SQUEEZE(基础用法) ==========
# 使用默认参数
squeeze_df = ta.squeeze(df['high'], df['low'], df['close'])

# 查看返回的DataFrame结构
print("SQUEEZE返回列名称:")
print(squeeze_df.columns.tolist())
print("\n" + "=" * 60 + "\n")

# 将计算结果添加到原DataFrame
# 动量值列名通常为 SQZ_{bb_length}_{bb_std}_{kc_length}_{kc_scalar}
momentum_col = [col for col in squeeze_df.columns if col.startswith('SQZ_') and not col.endswith('_ON') and not col.endswith('_OFF') and not col.endswith('_NO')]
sqz_on_col = [col for col in squeeze_df.columns if col.endswith('_ON')]
sqz_off_col = [col for col in squeeze_df.columns if col.endswith('_OFF')]
sqz_no_col = [col for col in squeeze_df.columns if col.endswith('_NO')]

df['SQZ'] = squeeze_df[momentum_col[0]] if momentum_col else squeeze_df.iloc[:, 0]
df['SQZ_ON'] = squeeze_df[sqz_on_col[0]] if sqz_on_col else squeeze_df.iloc[:, 1]
df['SQZ_OFF'] = squeeze_df[sqz_off_col[0]] if sqz_off_col else squeeze_df.iloc[:, 2]
df['SQZ_NO'] = squeeze_df[sqz_no_col[0]] if sqz_no_col else squeeze_df.iloc[:, 3]

print("SQUEEZE计算结果(最近10行):")
print(df[['close', 'SQZ', 'SQZ_ON', 'SQZ_OFF', 'SQZ_NO']].tail(10))
print("\n" + "=" * 60 + "\n")

# ========== 第三步:不同参数对比 ==========
# 标准参数(默认)
squeeze_std = ta.squeeze(df['high'], df['low'], df['close'])
df['SQZ_std'] = squeeze_std.iloc[:, 0]

# 短线参数(更敏感)
squeeze_fast = ta.squeeze(df['high'], df['low'], df['close'], 
                          bb_length=10, kc_length=10, mom_length=8, mom_smooth=4)
df['SQZ_fast'] = squeeze_fast.iloc[:, 0]

# 长线参数(更平滑)
squeeze_slow = ta.squeeze(df['high'], df['low'], df['close'], 
                          bb_length=30, kc_length=30, mom_length=14, mom_smooth=8)
df['SQZ_slow'] = squeeze_slow.iloc[:, 0]

print("不同参数SQUEEZE对比(最近5行):")
print(df[['close', 'SQZ_std', 'SQZ_fast', 'SQZ_slow']].tail())
print("\n" + "=" * 60 + "\n")

# ========== 第四步:手动验证SQUEEZE核心逻辑 ==========
def manual_squeeze(high, low, close, bb_length=20, bb_std=2.0, 
                   kc_length=20, kc_scalar=1.5, mom_length=12, mom_smooth=6):
    """手动验证SQUEEZE核心计算逻辑"""
    
    # 1. 计算布林带
    sma = close.rolling(window=bb_length).mean()
    std = close.rolling(window=bb_length).std()
    bb_high = sma + bb_std * std
    bb_low = sma - bb_std * std
    
    # 2. 计算肯特纳通道
    ema = close.ewm(span=kc_length, adjust=False).mean()
    # 计算ATR
    tr1 = high - low
    tr2 = abs(high - close.shift(1))
    tr3 = abs(low - close.shift(1))
    tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
    atr = tr.ewm(span=kc_length, adjust=False).mean()
    kc_high = ema + kc_scalar * atr
    kc_low = ema - kc_scalar * atr
    
    # 3. 判断挤压状态
    sqz_on = ((bb_high < kc_high) & (bb_low > kc_low)).astype(int)
    sqz_off = ((bb_high > kc_high) | (bb_low < kc_low)).astype(int)
    sqz_no = ((sqz_on == 0) & (sqz_off == 0)).astype(int)
    
    # 4. 计算动量
    mom = close - close.shift(mom_length - 1)
    sqz_momentum = mom.ewm(span=mom_smooth, adjust=False).mean()
    
    return sqz_momentum, sqz_on, sqz_off, sqz_no

df['SQZ_manual'], df['SQZ_ON_manual'], df['SQZ_OFF_manual'], df['SQZ_NO_manual'] = manual_squeeze(
    df['high'], df['low'], df['close']
)

# 验证一致性
diff_sqz = (df['SQZ'] - df['SQZ_manual']).abs().max()
print(f"pandas_ta与手动计算动量值的最大差异:{diff_sqz:.10f}")
print("\n" + "=" * 60 + "\n")

# ========== 第五步:生成交易信号 ==========
# 定义交易信号:挤压解除 + 动量柱方向确认
# 买入信号:SQZ_OFF = 1 且 SQZ > 0(动量柱为正)
df['buy_signal'] = (df['SQZ_OFF'] == 1) & (df['SQZ'] > 0)
# 卖出信号:SQZ_OFF = 1 且 SQZ < 0(动量柱为负)
df['sell_signal'] = (df['SQZ_OFF'] == 1) & (df['SQZ'] < 0)

# 动量趋势强度分类
df['momentum_strength'] = ''
df.loc[df['SQZ'] > 2, 'momentum_strength'] = '强多头动能'
df.loc[(df['SQZ'] > 0) & (df['SQZ'] <= 2), 'momentum_strength'] = '弱多头动能'
df.loc[(df['SQZ'] < 0) & (df['SQZ'] >= -2), 'momentum_strength'] = '弱空头动能'
df.loc[df['SQZ'] < -2, 'momentum_strength'] = '强空头动能'

print("挤压状态统计:")
print(f"挤压开启(蓄势)天数:{df['SQZ_ON'].sum()}")
print(f"挤压解除(爆发)天数:{df['SQZ_OFF'].sum()}")
print(f"无挤压状态天数:{df['SQZ_NO'].sum()}")

print("\n交易信号统计:")
print(f"买入信号(挤压解除+多头动量)数量:{df['buy_signal'].sum()}")
print(f"卖出信号(挤压解除+空头动量)数量:{df['sell_signal'].sum()}")

print("\n最近10个交易信号:")
signals = df[df['buy_signal'] | df['sell_signal']].tail(10)
if not signals.empty:
    for idx, row in signals.iterrows():
        signal_type = "买入" if row['buy_signal'] else "卖出"
        print(f"{idx.date()} - {signal_type}信号 - SQZ: {row['SQZ']:.2f} - 状态: {row['SQZ_OFF']}")
print("\n" + "=" * 60 + "\n")

# ========== 第六步:策略回测(挤压突破策略) ==========
# 策略:当买入信号出现时买入,持有至卖出信号或动量转弱
df['position'] = 0
in_position = False
entry_price = 0

for i in range(1, len(df)):
    if not in_position and df['buy_signal'].iloc[i]:
        df.loc[df.index[i], 'position'] = 1
        in_position = True
        entry_price = df['close'].iloc[i]
    elif in_position and (df['sell_signal'].iloc[i] or df['momentum_strength'].iloc[i] == '弱多头动能'):
        df.loc[df.index[i], 'position'] = 0
        in_position = False
    else:
        df.loc[df.index[i], 'position'] = df['position'].iloc[i-1]

# 计算收益
df['returns'] = df['close'].pct_change()
df['strategy_returns'] = df['position'].shift(1) * df['returns']

total_return_buyhold = (1 + df['returns']).prod() - 1
total_return_strategy = (1 + df['strategy_returns']).prod() - 1
win_rate = (df['strategy_returns'] > 0).sum() / (df['strategy_returns'] != 0).sum() if (df['strategy_returns'] != 0).sum() > 0 else 0

print("=" * 60)
print("策略绩效统计(SQUEEZE挤压突破策略回测):")
print(f"买入持有策略总收益率:{total_return_buyhold:.2%}")
print(f"SQUEEZE策略总收益率:{total_return_strategy:.2%}")
print(f"策略胜率:{win_rate:.2%}")
print("\n注意:此为简化回测,仅供参考;实盘需考虑手续费、滑点等因素")
print("=" * 60 + "\n")

# ========== 第七步:可视化 ==========
plt.figure(figsize=(14, 12))

# 子图1:价格走势 + 挤压状态标记
plt.subplot(3, 1, 1)
plt.plot(df.index[-200:], df['close'][-200:], label='Close Price', 
         linewidth=1.5, color='black')
# 标记挤压开启区域(红点位置)
squeeze_on_points = df[df['SQZ_ON'] == 1]
plt.scatter(squeeze_on_points.index[-200:], squeeze_on_points['close'][-200:], 
            color='red', s=20, label='Squeeze On(挤压开启)', alpha=0.7)
plt.title('Price Chart with Squeeze Signals (Last 200 days)', fontsize=14)
plt.ylabel('Price')
plt.legend()
plt.grid(True, alpha=0.3)

# 子图2:挤压状态(SQZ_ON/SQZ_OFF)
plt.subplot(3, 1, 2)
# 挤压开启用红色点表示,挤压解除用绿色点表示
plt.plot(df.index[-200:], df['SQZ_ON'][-200:], 'ro', markersize=3, label='Squeeze On(蓄势)', alpha=0.7)
plt.plot(df.index[-200:], df['SQZ_OFF'][-200:], 'go', markersize=3, label='Squeeze Off(爆发)', alpha=0.7)
plt.ylim(-0.1, 1.1)
plt.title('Squeeze State: Red=Squeeze On (Low Volatility), Green=Squeeze Off (Breakout)', fontsize=12)
plt.ylabel('State')
plt.legend()
plt.grid(True, alpha=0.3)

# 子图3:动量柱(SQZ值)
plt.subplot(3, 1, 3)
# 动量柱:正值绿色,负值红色
colors = ['green' if val >= 0 else 'red' for val in df['SQZ'][-200:]]
plt.bar(df.index[-200:], df['SQZ'][-200:], color=colors, alpha=0.7, width=0.8)
plt.axhline(y=0, color='gray', linestyle='-', linewidth=1)
plt.title('Squeeze Momentum Histogram: Green=向上动能, Red=向下动能', fontsize=12)
plt.xlabel('Date')
plt.ylabel('SQZ Momentum')
plt.grid(True, alpha=0.3)

# 标记买入/卖出信号
buy_signals = df[df['buy_signal']]
sell_signals = df[df['sell_signal']]
plt.scatter(buy_signals.index[-20:], [0.5] * min(20, len(buy_signals)), 
            color='green', marker='^', s=80, label='Buy Signal', alpha=0.8)
plt.scatter(sell_signals.index[-20:], [0.5] * min(20, len(sell_signals)), 
            color='red', marker='v', s=80, label='Sell Signal', alpha=0.8)

plt.tight_layout()
plt.show()

# ========== 第八步:数据清洗提示 ==========
nan_count = df['SQZ'].isna().sum()
print(f"\nSQUEEZE初始NaN数量:{nan_count}")
print("原因:SQUEEZE需要至少max(bb_length, kc_length, mom_length)个周期的数据")
print("处理建议:df_clean = df.iloc[20:].copy()")
print("\n" + "=" * 60)
print("SQUEEZE使用提示:")
print("1. SQZ_ON(红点)= 低波动蓄势 → 保持警惕,不盲目进场")
print("2. SQZ_OFF(绿点)+ 动量柱为正 → 多头突破信号")
print("3. SQZ_OFF(绿点)+ 动量柱为负 → 空头突破信号")
print("4. 建议结合ADX指标过滤震荡市假信号")
print("5. 多周期共振可显著提高信号可靠性")
print("=" * 60)

五、总结

SQUEEZE(挤压动量指标)是一种将波动率收缩周期与动量爆发相结合的复合型技术指标,其核心价值与定位如下:

维度 特点
核心创新 结合布林带与肯特纳通道,量化"波动率压缩 → 爆发"的完整周期
核心公式 SQZ_ON:BB完全落入KC内部;动量柱:平滑MOM值
三组件系统 挤压指示灯(红/绿点)+ 动量柱(红/绿柱)+ 状态标识
三大核心信号 挤压开启(预警)、挤压解除(方向确认)、动量柱(动能验证)
默认参数 (20,2,20,1.5,12,6)
最佳应用场景 趋势明确的品种、波动率周期性明显的市场、中长期交易
主要局限 震荡市假信号多、手续费敏感、信号有滞后性

实战使用三原则

  1. 挤压开启预警,挤压解除执行:SQZ_ON提示蓄势阶段,不急于入场;SQZ_OFF出现后再结合动量柱方向确认开仓方向
  2. 动量柱决定方向:挤压解除时动量柱为正值做多,为负值做空;动量柱的绝对值反映趋势强度
  3. 引入ADX过滤器:在ADX < 20的震荡市中,SQUEEZE产生的假信号较多。建议仅当ADX > 25(趋势明确)时才启用此策略

最后提醒 :SQUEEZE指标的核心价值在于帮助交易者找到"波动率压缩后即将爆发"的关键窗口。它回答了交易中最核心的两个问题:什么时候可能有大行情?方向是什么? 然而,如John Carter本人所强调,SQUEEZE不是"圣杯"------它本质上是滞后指标,挤压解除信号出现时价格往往已启动一段距离,可能面临局部回调的风险。因此,建议配合多周期分析、ADX趋势强度过滤以及严格的风控管理,同时务必注意交易成本(尤其是在高频交易场景中)对净利润的侵蚀。将SQUEEZE作为完整交易系统中的一个组件,而非唯一的决策依据,才能发挥其最大价值。

相关推荐
千瓜2 小时前
运动生活方式洞察 | 从“动起来”到“活过来”
大数据·人工智能·数据分析·生活·新媒体
一晌小贪欢2 小时前
第22节:相关性分析——协方差、相关系数与热力图解读
开发语言·python·数据分析·pandas·数据可视化
郑洁文17 小时前
音乐数据分析研究与应用
大数据·数据挖掘·数据分析·音乐数据分析
陆水A20 小时前
【实时数仓·3】Flink多表JOIN状态爆炸——Event Time Temporal JOIN + TTL分层治理
大数据·数据仓库·数据分析·flink·数据库开发·bigdata
2601_9604638321 小时前
FPG财盛国际:把多语言支持做扎实,更谨慎的使用者更容易感受到的逻辑
金融
babe小鑫21 小时前
2026会计专业学数据分析的价值
数据挖掘·数据分析
brycegao3211 天前
金融交易App客户端架构实战 | 模块化、WebSocket治理、多线路容灾全解
websocket·金融·组件化·android架构·客户端模块化·移动端稳定性·多线路网络
镜舟科技1 天前
镜舟科技出席 HPE 新品发布会,携手打造“Lakehouse + AI”智能数据底座
starrocks·数据分析·ai agent·lakehouse·hpe
Aloudata1 天前
传统 BI 指标向语义层迁移实操指南与避坑详解
数据分析·agent·bi·语义层·语义编织