找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1167

积分

0

好友

167

主题
发表于 4 天前 | 查看: 26| 回复: 0

顾比均线(Gary Moving Average,GMMA)由交易大师戴若·顾比(Daryl Guppy)提出,是基于多周期移动平均的趋势分析工具。其核心在于通过“短期+长期两组均线群”的分离与粘合状态,来识别市场的趋势方向、强弱以及潜在的反转信号,兼具趋势跟踪和资金行为分析的双重属性。与单一均线相比,顾比均线能更清晰地刻画“短期投机资金”和“长期机构资金”之间的博弈,因此更适用于趋势市以及趋势反转阶段的判断。

以下将从核心原理、实战应用规则、Python完整实现、风险控制四个维度,系统性地拆解顾比均线的落地逻辑。

一、顾比均线核心原理

1. 指标本质:双组均线群的资金行为解读

顾比均线将移动平均线分为“短期组”和“长期组”,分别对应市场中两类不同资金主体的交易行为:

  • 短期均线群(3/5/8/10/12/15日):反映短期投机者(如散户、短线游资)的交易行为,对价格波动反应敏感。
  • 长期均线群(30/35/40/45/50/60日):反映长期投资者(如机构、主力资金)的持仓成本与行为,趋势更为稳定。

2. 核心计算公式

顾比均线采用指数移动平均(EMA)而非简单移动平均(SMA),因为EMA对近期价格赋予更高权重,能更贴合资金的最新动向。

  • 指数移动平均(EMA)公式:EMA_today = (Price_today * (2/(N+1))) + (EMA_yesterday * (1 - (2/(N+1)))),其中 N 为均线周期。
  • 均线分组详情:
均线分组 周期(日线) 计算方式 资金行为解读
短期组 3, 5, 8, 10, 12, 15 各周期EMA值构成均线群 短期投机资金的成本区间
长期组 30, 35, 40, 45, 50, 60 各周期EMA值构成均线群 长期机构资金的成本区间

3. 核心判断逻辑

顾比均线的精髓不在于“单根均线的交叉”,而在于观察两组均线群的相对位置关系和整体形态

形态特征 资金行为解读 趋势判断
短期组在长期组上方,且两组分离 短期资金推动上涨,机构资金锁仓,做多力量强劲 多头趋势延续
短期组在长期组下方,且两组分离 短期资金持续抛售,机构资金离场,做空力量强劲 空头趋势延续
两组均线粘合交织 多空资金博弈激烈,方向不明 震荡市/趋势反转酝酿期
短期组上穿长期组并开始分离 短期资金积极入场,机构资金开始托底 多头趋势可能启动
短期组下穿长期组并开始分离 短期资金加速出逃,机构资金开始抛售 空头趋势可能启动

二、顾比均线实战应用规则

1. 核心交易信号

(1)买入信号(优先级从高到低)
  1. 趋势启动买入:短期均线群从粘合状态向上突破长期均线群,且长期均线群开始向上倾斜 → 确认多头趋势启动,可考虑分批建仓。
  2. 回调加仓买入:在明确的多头趋势中,短期均线群回调至长期均线群上方但未下穿,同时成交量出现缩量 → 表明机构资金支撑有效,是加仓时机。
  3. 震荡转势买入:两组均线长期粘合后,短期组连续3个交易日站稳在长期组上方,且收盘价突破粘合区间上沿 → 预示趋势可能反转,可试探性建仓。
(2)卖出信号(优先级从高到低)
  1. 趋势反转卖出:短期均线群从粘合状态向下跌破长期均线群,且长期均线群开始向下倾斜 → 确认空头趋势启动,应立即清仓或考虑做空。
  2. 反弹减仓卖出:在空头趋势中,短期均线群反弹至长期均线群下方但未能上穿,同时成交量异常放大 → 表明压力位有效,是减仓信号。
  3. 震荡转势卖出:两组均线粘合后,短期组连续3个交易日位于长期组下方,且收盘价跌破粘合区间下沿 → 预示趋势可能向下反转,应果断清仓。

2. 不同市场环境的应用策略

(1)趋势市(核心适配场景)
  • 操作逻辑:严格跟随两组均线的分离方向。短期组在长期组上方则坚定持有,在下方则保持空仓。
  • 风控设置:将止损位设在长期均线群的下沿(多头趋势)或上沿(空头趋势),避免趋势反转时亏损扩大。
  • 示例:当某板块龙头股处于上升趋势时,其短期均线群会始终运行在长期组上方,可持有至短期组明确下穿长期组为止。
(2)震荡市
  • 操作逻辑:当两组均线处于粘合状态时,应保持空仓,不参与无序震荡,耐心等待明确的突破信号。
  • 过滤机制:当粘合区间的宽度小于近期平均波动幅度的10%时,可判定为震荡市,暂停交易。
  • 核心风险:避免在粘合阶段试图“高抛低吸”,容易在真突破时被套。
(3)趋势反转阶段
  • 操作逻辑:等待“两组均线出现分离”且得到“成交量确认”(突破时放量),不主观预判。
  • 信号验证:突破发生后,需连续2-3个交易日收盘价稳定在突破方向,方可确认反转信号有效,用以过滤假突破。

3. 实战示例(以A股日线数据为例)

时间节点 均线状态 成交量特征 交易信号 操作动作
启动初期 短期组粘合后上穿长期组,长期组开始上倾 突破时放量 趋势启动买入 建仓30%,止损设于长期组下沿
趋势中途 短期组回调至长期组上方,未下穿 回调时缩量 回调加仓买入 加仓20%,总仓位至50%
趋势延续 短期组与长期组分离,同步向上 上涨时温和放量 持有 将止损位上移至最新长期组下沿
趋势末端 短期组下穿长期组,长期组开始下倾 下穿时放量下跌 趋势反转卖出 清仓全部50%仓位

三、Python完整实现(含信号生成与可视化)

以下代码完整实现了顾比均线的计算、交易信号生成、策略回测及可视化,适用于A股、期货等日线级别的数据分析。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')

# ---------------------- 1. 数据准备(模拟/真实数据源) ----------------------
def get_stock_data(stock_code='300750.SZ', start_date='2022-01-01', end_date='2023-12-31'):
    """
    获取股票日线数据(模拟数据,实盘可替换为Tushare/akshare)
    :param stock_code: 股票代码
    :param start_date: 开始日期
    :param end_date: 结束日期
    :return: 包含date/high/low/close/volume的DataFrame
    """
    # 生成模拟数据(实盘替换为:df = ts.pro_bar(ts_code=stock_code, start_date=start_date, end_date=end_date))
    dates = pd.date_range(start=start_date, end=end_date, freq='D')
    dates = dates[dates.dayofweek < 5]  # 剔除非交易日
    n_days = len(dates)

    # 模拟股价趋势(先震荡→上涨→下跌)
    np.random.seed(42)
    base_price = 200
    # 第一阶段:震荡(前100天)
    trend1 = np.cumsum(np.random.randn(100)*2 - 0.5)[:100] if n_days>100 else np.cumsum(np.random.randn(n_days)*2 - 0.5)
    # 第二阶段:上涨(100-200天)
    trend2 = np.cumsum(np.random.randn(min(100, n_days-100))*3 + 2)[:min(100, n_days-100)] if n_days>100 else []
    # 第三阶段:下跌(200天后)
    trend3 = np.cumsum(np.random.randn(max(0, n_days-200))*3 - 3)[:max(0, n_days-200)] if n_days>200 else []

    trend = np.concatenate([trend1, trend2, trend3])[:n_days]
    close = base_price + trend
    high = close + np.random.uniform(0, 10, n_days)  # 最高价
    low = close - np.random.uniform(0, 10, n_days)   # 最低价
    volume = np.random.randint(500000, 2000000, n_days)  # 成交量

    df = pd.DataFrame({
        'date': dates,
        'high': high,
        'low': low,
        'close': close,
        'volume': volume
    })
    return df

# ---------------------- 2. 顾比均线计算核心函数 ----------------------
def calculate_guppy_ma(df):
    """
    计算顾比均线(短期组+长期组)
    :param df: 包含close的DataFrame
    :return: 新增顾比均线列的DataFrame
    """
    df = df.copy()

    # 定义顾比均线周期
    short_periods = [3, 5, 8, 10, 12, 15]  # 短期均线群
    long_periods = [30, 35, 40, 45, 50, 60]  # 长期均线群

    # 计算短期EMA均线
    for period in short_periods:
        df[f'ema_short_{period}'] = df['close'].ewm(span=period, adjust=False).mean()

    # 计算长期EMA均线
    for period in long_periods:
        df[f'ema_long_{period}'] = df['close'].ewm(span=period, adjust=False).mean()

    # 计算短期/长期均线群的均值(简化趋势判断)
    df['short_ma_mean'] = df[[f'ema_short_{p}' for p in short_periods]].mean(axis=1)
    df['long_ma_mean'] = df[[f'ema_long_{p}' for p in long_periods]].mean(axis=1)

    # 计算均线群分离度(反映趋势强弱:分离度越大,趋势越强)
    df['separation'] = (df['short_ma_mean'] - df['long_ma_mean']) / df['long_ma_mean'] * 100

    return df

# ---------------------- 3. 交易信号生成 ----------------------
def generate_trade_signals(df):
    """
    基于顾比均线生成买卖信号
    :param df: 包含顾比均线列的DataFrame
    :return: 新增信号列的DataFrame
    """
    df = df.copy()
    df['signal'] = 0  # 0=无信号,1=买入,-1=卖出
    df['position'] = 0  # 持仓状态:0=空仓,1=持仓

    # 定义判断条件
    # 1. 趋势启动买入:短期均值上穿长期均值,且长期均值向上
    df['long_ma_up'] = df['long_ma_mean'] > df['long_ma_mean'].shift(1)  # 长期均线向上
    df['short_cross_long'] = (df['short_ma_mean'] > df['long_ma_mean']) & (df['short_ma_mean'].shift(1) <= df['long_ma_mean'].shift(1))  # 短期上穿长期
    buy_cond1 = df['short_cross_long'] & df['long_ma_up']

    # 2. 回调加仓买入:多头持仓中,短期均值回调至长期均值上方,缩量
    df['volume_ma20'] = df['volume'].rolling(window=20).mean()
    df['volume_shrink'] = df['volume'] < 0.8 * df['volume_ma20']  # 缩量
    df['short_above_long'] = df['short_ma_mean'] > df['long_ma_mean']  # 短期在长期上方
    buy_cond2 = (df['position'] == 1) & df['short_above_long'] & df['volume_shrink']

    # 3. 趋势反转卖出:短期均值下穿长期均值,且长期均值向下
    df['long_ma_down'] = df['long_ma_mean'] < df['long_ma_mean'].shift(1)  # 长期均线向下
    df['short_cross_long_down'] = (df['short_ma_mean'] < df['long_ma_mean']) & (df['short_ma_mean'].shift(1) >= df['long_ma_mean'].shift(1))  # 短期下穿长期
    sell_cond1 = df['short_cross_long_down'] & df['long_ma_down']

    # 4. 反弹减仓卖出:空头趋势中,短期均值反弹至长期均值下方,放量
    df['volume_expand'] = df['volume'] > 1.2 * df['volume_ma20']  # 放量
    df['short_below_long'] = df['short_ma_mean'] < df['long_ma_mean']  # 短期在长期下方
    sell_cond2 = (df['position'] == 1) & df['short_below_long'] & df['volume_expand']

    # 赋值信号(避免重复信号)
    df.loc[buy_cond1 | buy_cond2, 'signal'] = 1
    df.loc[sell_cond1 | sell_cond2, 'signal'] = -1

    # 计算持仓状态(信号触发后持仓,直到反向信号)
    for i in range(1, len(df)):
        if df['signal'].iloc[i] == 1:
            df['position'].iloc[i] = 1
        elif df['signal'].iloc[i] == -1:
            df['position'].iloc[i] = 0
        else:
            df['position'].iloc[i] = df['position'].iloc[i-1]

    return df

# ---------------------- 4. 策略回测 ----------------------
def backtest_strategy(df):
    """
    回测顾比均线策略收益
    :param df: 含信号和持仓的DataFrame
    :return: 回测结果字典
    """
    # 计算每日收益率
    df['daily_return'] = df['close'].pct_change()
    # 策略收益率(仅持仓时收益)
    df['strategy_return'] = df['daily_return'] * df['position'].shift(1)
    # 累计收益率
    df['cum_market_return'] = (1 + df['daily_return']).cumprod() - 1
    df['cum_strategy_return'] = (1 + df['strategy_return']).cumprod() - 1

    # 回测指标
    total_trades = len(df[df['signal'] != 0])
    total_return = df['cum_strategy_return'].iloc[-1]
    annual_return = (1 + total_return) ** (252 / len(df)) - 1  # 年化收益率
    max_drawdown = (df['cum_strategy_return'] - df['cum_strategy_return'].cummax()).min()  # 最大回撤
    win_rate = len(df[(df['strategy_return'] > 0) & (df['position'].shift(1) == 1)]) / len(df[df['position'].shift(1) == 1]) if len(df[df['position'].shift(1) == 1])>0 else 0

    return {
        '总交易次数': total_trades,
        '总收益率': round(total_return * 100, 2),
        '年化收益率': round(annual_return * 100, 2),
        '最大回撤': round(max_drawdown * 100, 2),
        '胜率': round(win_rate * 100, 2)
    }

# ---------------------- 5. 可视化顾比均线 ----------------------
def plot_guppy_ma(df):
    """
    绘制顾比均线+股价+交易信号+分离度
    """
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 中文显示
    plt.rcParams['axes.unicode_minus'] = False
    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(18, 12))

    # 子图1:股价+顾比均线群
    ax1.plot(df['date'], df['close'], label='收盘价', color='black', linewidth=1.5)
    # 绘制短期均线群(红色系,浅色调)
    short_periods = [3, 5, 8, 10, 12, 15]
    colors_short = ['#FF6B6B', '#FF8E8E', '#FFB3B3', '#FFD1D1', '#FFE8E8', '#FFF2F2']
    for i, period in enumerate(short_periods):
        ax1.plot(df['date'], df[f'ema_short_{period}'], color=colors_short[i], linewidth=1, alpha=0.7, label=f'短期{period}日' if i==0 else "")
    # 绘制长期均线群(绿色系,深色调)
    long_periods = [30, 35, 40, 45, 50, 60]
    colors_long = ['#006400', '#228B22', '#32CD32', '#90EE90', '#98FB98', '#F0FFF0']
    for i, period in enumerate(long_periods):
        ax1.plot(df['date'], df[f'ema_long_{period}'], color=colors_long[i], linewidth=1, alpha=0.7, label=f'长期{period}日' if i==0 else "")

    # 标记买入/卖出信号
    buy_signals = df[df['signal'] == 1]
    sell_signals = df[df['signal'] == -1]
    ax1.scatter(buy_signals['date'], buy_signals['close'], marker='^', color='red', s=100, label='买入信号')
    ax1.scatter(sell_signals['date'], sell_signals['close'], marker='v', color='green', s=100, label='卖出信号')

    ax1.set_title('顾比均线群与股价', fontsize=14)
    ax1.set_ylabel('价格(元)', fontsize=12)
    ax1.legend(loc='upper left')
    ax1.grid(True, alpha=0.3)

    # 子图2:均线群均值+分离度
    ax2.plot(df['date'], df['short_ma_mean'], label='短期均线均值', color='red', linewidth=1.5)
    ax2.plot(df['date'], df['long_ma_mean'], label='长期均线均值', color='green', linewidth=1.5)
    ax2_twin = ax2.twinx()
    ax2_twin.plot(df['date'], df['separation'], label='分离度(%)', color='blue', linewidth=1, linestyle='--')
    ax2.set_title('短期/长期均线均值与分离度', fontsize=14)
    ax2.set_ylabel('均线均值(元)', fontsize=12)
    ax2_twin.set_ylabel('分离度(%)', fontsize=12)
    ax2.legend(loc='upper left')
    ax2_twin.legend(loc='upper right')
    ax2.grid(True, alpha=0.3)

    # 子图3:持仓状态
    ax3.fill_between(df['date'], 0, df['position'], color='gray', alpha=0.5, label='持仓状态(1=持仓,0=空仓)')
    ax3.set_title('策略持仓状态', fontsize=14)
    ax3.set_ylabel('持仓状态', fontsize=12)
    ax3.legend(loc='upper left')
    ax3.grid(True, alpha=0.3)

    # 子图4:累计收益率对比
    ax4.plot(df['date'], df['cum_strategy_return'] * 100, label='策略累计收益', color='red', linewidth=1.5)
    ax4.plot(df['date'], df['cum_market_return'] * 100, label='市场累计收益', color='blue', linewidth=1.5)
    ax4.set_title('策略vs市场累计收益率', fontsize=14)
    ax4.set_xlabel('日期', fontsize=12)
    ax4.set_ylabel('累计收益率(%)', fontsize=12)
    ax4.legend(loc='upper left')
    ax4.grid(True, alpha=0.3)

    plt.xticks(rotation=45)
    plt.tight_layout()
    plt.show()

# ---------------------- 主函数调用 ----------------------
if __name__ == "__main__":
    # 步骤1:获取数据
    stock_df = get_stock_data(stock_code='300750.SZ', start_date='2022-01-01', end_date='2023-12-31')

    # 步骤2:计算顾比均线
    guppy_df = calculate_guppy_ma(stock_df)

    # 步骤3:生成交易信号
    signal_df = generate_trade_signals(guppy_df)

    # 步骤4:回测策略
    backtest_result = backtest_strategy(signal_df)
    print("顾比均线策略回测结果:")
    for key, value in backtest_result.items():
        print(f"{key}:{value}%")

    # 步骤5:可视化
    plot_guppy_ma(signal_df)

    # 输出关键数据
    print("\n核心数据(最后10行):")
    print(signal_df[['date', 'close', 'short_ma_mean', 'long_ma_mean', 'separation', 'signal', 'position']].tail(10))

代码关键说明

  1. 核心计算:使用Pandas的ewm(span=period, adjust=False)方法计算指数移动平均(EMA),严格遵循顾比均线的原始定义。
  2. 简化判断:通过计算短期组和长期组所有均线的平均值,简化了多线分析的复杂度,同时保留了整体趋势特征。
  3. 信号过滤:策略结合成交量特征(缩量回调、放量反弹)对买卖信号进行过滤,有助于提升策略的胜率,这是在量化交易实践中常用的技巧。
  4. 可视化呈现:通过4个子图分别展示股价与均线群、均线均值与分离度、策略持仓状态以及累计收益对比,能够直观、全面地评估策略效果。整个实现过程充分展示了如何利用Python进行金融数据分析与策略开发。

四、参数优化与风险控制

1. 周期参数优化(适配不同标的与市场周期)

顾比均线的经典周期参数通常无需大幅调整,但可根据交易标的的波动特性进行微调,以优化灵敏度与稳定性的平衡:

标的类型 短期周期调整建议 长期周期调整建议 核心逻辑
低波动标的(如银行股) 5, 8, 10, 12, 15, 20 40, 45, 50, 55, 60, 70 扩大周期,降低噪声干扰,提高信号稳定性
中波动标的(如消费股) 3, 5, 8, 10, 12, 15 30, 35, 40, 45, 50, 60 使用经典参数,在灵敏度与稳定性间取得平衡
高波动标的(如科技股) 2, 3, 5, 8, 10, 12 25, 30, 35, 40, 45, 50 适当缩小周期,以更快捕捉短期趋势变化
高频波动标的(如期货) 1, 2, 3, 5, 8, 10 15, 20, 25, 30, 35, 40 适配高波动性,要求指标能快速响应趋势

2. 核心风险点与应对方案

风险点 应对方案
震荡市中的假突破信号 增加“分离度过滤”:仅当分离度大于1%(多头)或小于-1%(空头)时才执行交易;分离度过小时保持空仓。
趋势反转时止损不及时 采用“分离度止损”法:在多头持仓中,一旦分离度由正转负,立即止损;空头持仓则反之。
极端行情下均线滞后 叠加其他趋势指标:例如结合唐奇安通道(Donchian Channel),仅当顾比均线信号与通道突破信号共振时才交易。
单一指标信号胜率有限 构建多指标共振系统:结合MACD的金叉/死叉、RSI的超买/超卖状态来共同确认趋势方向。

3. 进阶优化技巧

(1)分离度动态阈值

不要使用固定的1%作为阈值。可以根据标的历史数据中分离度的分布情况,设置动态阈值。例如,取历史分离度数据的90%分位数(如2%),那么仅当当前分离度大于2%时才执行加仓操作。

(2)基于分离度的仓位管理

将仓位大小与趋势强度(分离度)挂钩,实现动态仓位管理:

  • 分离度 < 1%(弱趋势):轻仓试探,仓位20%-30%。
  • 1% ≤ 分离度 ≤ 3%(中趋势):标准仓位,50%-60%。
  • 分离度 > 3%(强趋势):重仓参与,70%-80%。
(3)均线粘合度量化过滤

通过计算短期组或长期组内各条均线的标准差,来量化“粘合”程度。当该标准差小于近期股价波动范围的0.5%时,可判定市场处于高度粘合的震荡市,此时应空仓等待,避免无效交易。

五、总结:顾比均线的核心价值与适用边界

1. 核心价值

  • 解读资金行为:直观区分短期投机资金和长期机构资金的动向,有助于判断趋势的可持续性。
  • 刻画趋势特征:均线群的“分离”与“粘合”形态,比单根均线能更有效地反映趋势的强弱和转换。
  • 规则清晰可执行:基于均线群相对位置的买卖信号逻辑清晰,易于理解和程序化执行。

2. 适用边界

  • 适合场景:趋势性明确的标的(如行业龙头、大盘指数ETF)、日线或周线等中长期图表、侧重于趋势跟踪的交易者。
  • 不适合场景:长期处于震荡行情的标的(如部分小盘股)、分钟级别的超短线交易(均线滞后性会导致信号无效)。

3. 实战口诀

  • 短长分离看趋势,短上长多短下空。
  • 粘合震荡不交易,分离突破才入场。
  • 缩量回调可加仓,放量反弹要减仓。
  • 分离度定趋势强,风控永远放第一。

顾比均线的本质是 “通过多周期均线群来观测和解读市场资金的多空博弈” 。在实战中,不必过分关注单根均线的细微变化,而应将重点放在两组均线的整体形态关系上。结合成交量验证与分离度过滤,方能在趋势行情中最大化利润,在震荡行情中保存实力。

风险提示:本文内容仅作为技术分析方法分享与Python编程学习之用,所涉及的策略回测基于模拟数据,不构成任何实际的投资建议。金融市场有风险,投资需谨慎。




上一篇:入门到进阶:世界模型核心目标与关键技术解析
下一篇:CMake构建系统入门指南:跨平台编译C++项目的核心配置与实践
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-17 20:30 , Processed in 0.157886 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表