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

3683

积分

0

好友

506

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

希尔伯特变换是信号处理中的经典工具,近年来被一些量化研究者尝试用于金融市场分析,特别是判断市场处于“趋势”还是“震荡”状态。然而,金融时间序列数据具有其独特的复杂性,直接套用传统方法往往会得到失真的结果。本文将探讨其基本思路、传统方法在A股应用中的问题,并重点介绍一种更有效的改进方案——Hilbert-Huang Transform (HHT)。

一、希尔伯特变换基本概念

希尔伯特变换是一种数学变换,它将一个实值信号 x(t) 转换为一个复解析信号 z(t) = x(t) + i * H[x(t)],其中 H[x(t)]x(t) 的希尔伯特变换。从这个解析信号中,我们可以提取出信号的瞬时幅度瞬时相位瞬时频率

  • 瞬时相位 φ(t) = arctan(H[x(t)] / x(t)),反映了信号在时刻 t 的相位角。
  • 瞬时频率 f(t) = (1/(2π)) * dφ(t)/dt,表示信号在局部时刻的振荡频率。

在理想情况下,如果一个信号是窄带(频率成分集中在单一频率附近)且稳态(统计特性不随时间变化)的,那么它的瞬时频率具有明确的物理意义,能够准确反映信号的局部振荡特性。这一特性使得希尔伯特变换被广泛应用于机械振动、生物医学信号处理等领域。

二、在A股使用希尔伯特变换进行市场状态分析的思路

将希尔伯特变换应用于A股市场,核心思路是通过价格序列的瞬时频率来判断市场状态,进而指导交易策略的选择。具体逻辑如下:

  1. 计算瞬时频率:对价格序列(或经过预处理的价格序列)进行希尔伯特变换,得到每个时刻的瞬时频率。
  2. 市场状态分类
    • 当瞬时频率较低且变化缓慢时,表明价格呈现单向运动(趋势行情)。
    • 当瞬时频率较高且稳定波动时,表明价格呈现周期性来回摆动(震荡行情)。
  3. 策略切换
    • 在趋势行情中,采用突破策略(如通道突破、均线跟随)。
    • 在震荡行情中,采用均值回归策略(如布林带反转、RSI高抛低吸)。

一些金融技术指标如TA-Lib中的 HT_TRENDMODE 正是基于这一思想:它通过希尔伯特变换计算瞬时周期,比较当前价格与一个周期前的价格,若价格变化显著则判定为趋势,否则为震荡。

三、使用传统希尔伯特变换在A股市场中的问题

尽管上述思路直观,但直接对A股价格序列应用传统希尔伯特变换会面临严重的数学和实际障碍,导致结果失去意义:

  1. 非窄带信号:股票价格通常包含多种频率成分——长期趋势、中期波动、短期噪音等,频谱较宽,不满足窄带条件。直接进行希尔伯特变换得到的瞬时频率会混杂不同频率的贡献,无法区分市场的主导周期。
  2. 非稳态特性:价格序列具有趋势、异方差性(波动率聚集)等非稳态特征。例如,牛市中价格持续上升,均值随时间变化,这会导致希尔伯特变换的解析信号无法准确提取局部振荡信息。
  3. 瞬时频率无物理意义:在上述条件下,计算出的瞬时相位会发生不规则跳跃,瞬时频率可能出现负值或剧烈振荡,无法反映市场的真实周期状态。实践中常表现为相位轨迹杂乱无章,而不是围绕原点规则旋转。
  4. 结果噪声大:为了强行使用,一些研究者会对数据进行多次平滑滤波,但这会引入滞后并损失关键信息,且无法从根本上解决多频率叠加的问题。

四、改进方法:Hilbert-Huang Transform (HHT)

针对传统方法的局限性,学术界提出了Hilbert-Huang Transform (HHT)。它由经验模态分解(EMD)希尔伯特变换两部分组成,能够自适应地处理非稳态、多频率信号,在A股市场分析中更具实用价值。

1. 经验模态分解(EMD)

EMD是一种数据驱动的分解方法,它不需要预设基函数,而是通过“筛分”过程将原始信号 X(t) 分解为若干个本征模态函数(IMF) 和一个残余项:X(t) = Σ IMF_i(t) + r_n(t)。每个IMF分量必须满足两个条件:

  • 在整个数据段内,极值点个数与过零点个数相等或最多相差一个。
  • 在任意点,由局部极大值和极小值定义的包络均值为零。

这些IMF分量代表信号中不同时间尺度的振荡模式,且每个IMF都是窄带近似稳态的。对于A股价格序列,分解结果通常包括:

  • 高频IMF:市场噪音或日内波动(可忽略)。
  • 中频IMF:短期市场波动(如周度周期),这正是短线择时所关心的。
  • 低频IMF:长期趋势(如月度以上方向)。

2. 对目标IMF进行希尔伯特变换

选取代表短期市场波动的IMF(例如IMF2或IMF3),对该分量进行希尔伯特变换,就可以得到有意义的瞬时频率和相位。因为该IMF已满足窄带稳态条件,其瞬时频率能够准确反映当前市场的主要振荡节奏,相位轨迹也会围绕原点规则旋转。

3. 改进后的优势

  • 自适应性:EMD完全根据数据自身的时间尺度分解,无需人工设定滤波器参数,更贴合A股市场的非线性、时变特性。
  • 物理意义明确:每个IMF对应一种市场周期成分,便于针对性地构建交易策略。
  • 瞬时参数可靠:基于IMF得到的瞬时频率可用于定量划分趋势/震荡状态,例如设置阈值,当瞬时频率低于某值时为趋势,反之为震荡。
  • 避免未来数据:尽管经典EMD需要整段数据,但在实际应用中可采用滑动窗口或实时分解算法,满足在线交易需求。

4. 在A股中的应用示例与Python实现

下面通过一个完整的Python示例,演示如何利用HHT(EMD+希尔伯特变换)构建一个简单的市场状态识别与策略切换系统。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import yfinance as yf
from PyEMD import EMD
from scipy.signal import hilbert
import warnings
warnings.filterwarnings('ignore')

# ==================== 1. 数据获取 ====================
# 使用沪深300 ETF (510300.SS) 作为沪深300指数替代,获取最近3年日线数据
ticker = '510300.SS'
data = yf.download(ticker, period='3y', interval='1d', progress=False)
price = data['Close'].dropna()
if len(price) < 200:
    raise ValueError("数据量不足,请检查网络或更换数据源")

# ==================== 2. EMD分解 ====================
# 对整个序列进行EMD分解(注意:实际回测需滚动处理,此处仅为演示)
emd = EMD()
IMFs = emd(price.values)  # shape: (n_imfs, n_points)
# 选择短期IMF(通常第一个或第二个IMF代表短期波动)
short_term_imf = IMFs[0, :]  # 可根据需要改为 IMFs[1, :]

# ==================== 3. 计算瞬时频率 ====================
analytic_signal = hilbert(short_term_imf)
instantaneous_phase = np.unwrap(np.angle(analytic_signal))
# 瞬时频率 = 相位差分 / (2π * Δt),Δt=1天
instantaneous_frequency = np.diff(instantaneous_phase) / (2.0 * np.pi)
freq = pd.Series(instantaneous_frequency, index=price.index[1:])
# 平滑频率(5日移动平均)
freq_smooth = freq.rolling(window=5, min_periods=1).mean()

# ==================== 4. 设定阈值 ====================
# 使用平滑频率的中位数作为阈值(可调)
threshold = freq_smooth.median()
print(f"瞬时频率阈值: {threshold:.4f}")

# ==================== 5. 构建交易信号 ====================
signal = pd.Series(0, index=price.index)   # 1:做多, -1:做空, 0:空仓
lookback = 20      # 突破策略的回顾窗口
bb_period = 20     # 布林带周期
bb_std = 2         # 标准差倍数

# 逐日判断(从足够长的起始点开始,避免指标计算缺失)
start_idx = max(lookback, bb_period) + 1
for i in range(start_idx, len(price)):
    # 使用前一天的平滑频率判断市场状态(避免未来数据)
    current_freq = freq_smooth.iloc[i-1] if i-1 < len(freq_smooth) else threshold
    is_trend = current_freq < threshold       # 趋势行情
    is_range = not is_trend                    # 震荡行情

    # 获取历史数据(截至前一日)
    hist_price = price.iloc[:i]   # 包括当天之前的所有数据
    hist_close = hist_price
    hist_high = hist_price
    hist_low = hist_price

    if is_trend:
        # 突破策略:价格突破前N日高点/低点时开仓
        recent_high = hist_high.iloc[-lookback-1:-1].max()  # 前一天的过去N日高点
        recent_low = hist_low.iloc[-lookback-1:-1].min()
        if price.iloc[i] > recent_high:
            signal.iloc[i] = 1
        elif price.iloc[i] < recent_low:
            signal.iloc[i] = -1
        else:
            signal.iloc[i] = 0   # 无信号则空仓
    else:
        # 均值回归策略:布林带上下轨
        sma = hist_close.iloc[-bb_period:].mean()
        std = hist_close.iloc[-bb_period:].std()
        upper = sma + bb_std * std
        lower = sma - bb_std * std
        if price.iloc[i] < lower:
            signal.iloc[i] = 1
        elif price.iloc[i] > upper:
            signal.iloc[i] = -1
        else:
            signal.iloc[i] = 0

# ==================== 6. 回测 ====================
tcost = 0.001   # 单边交易成本0.1%
returns = price.pct_change().fillna(0)
position = signal.shift(1).fillna(0)   # 次日开盘以收盘价成交(简化)
strat_returns = position * returns
# 交易成本:每次持仓变动时扣除
trade = position.diff().abs().fillna(0)
strat_returns_net = strat_returns - trade * tcost
cumulative = (1 + strat_returns_net).cumprod()
benchmark = (1 + returns).cumprod()

# 绩效指标
total_ret = cumulative.iloc[-1] - 1
bench_ret = benchmark.iloc[-1] - 1
sharpe = np.sqrt(252) * strat_returns_net.mean() / strat_returns_net.std()
print(f"策略总收益: {total_ret:.2%}")
print(f"基准总收益: {bench_ret:.2%}")
print(f"策略夏普比率: {sharpe:.2f}")

# ==================== 7. 可视化 ====================
fig, axes = plt.subplots(3, 1, figsize=(12, 10))
# 价格与信号
axes[0].plot(price.index, price, label='Price', linewidth=1)
axes[0].plot(price.index[signal==1], price[signal==1], '^', markersize=4, color='g', label='Long')
axes[0].plot(price.index[signal==-1], price[signal==-1], 'v', markersize=4, color='r', label='Short')
axes[0].set_title('Price and Trading Signals')
axes[0].legend()
# 瞬时频率与阈值
axes[1].plot(freq_smooth.index, freq_smooth, label='Smoothed Instantaneous Frequency', linewidth=1)
axes[1].axhline(y=threshold, color='r', linestyle='--', label='Threshold')
axes[1].set_title('Instantaneous Frequency (5-day MA)')
axes[1].legend()
# 净值曲线
axes[2].plot(cumulative.index, cumulative, label='Strategy', linewidth=1)
axes[2].plot(benchmark.index, benchmark, label='Buy & Hold', linewidth=1)
axes[2].set_title('Cumulative Returns')
axes[2].legend()
plt.tight_layout()
plt.show()

流程解析

  1. 数据获取与EMD分解:获取沪深300ETF价格数据,并使用EMD分解出本征模态函数。
  2. 计算瞬时频率:选取代表短期波动的IMF分量,对其进行希尔伯特变换并计算瞬时频率,再进行平滑处理。
  3. 状态判断与策略生成:基于平滑后的瞬时频率与预设阈值判断市场状态(趋势/震荡),并相应地触发突破策略或均值回归策略,生成交易信号。
  4. 回测与评估:对生成的信号进行简单的回测,计算策略收益、夏普比率等关键指标,并可视化价格、频率信号及净值曲线。

总结

希尔伯特变换为识别市场状态提供了理论可能,但在A股这样复杂的金融市场中,传统方法因信号非稳态、多频率而失效。通过引入 Hilbert-Huang Transform (HHT),利用经验模态分解先行提取窄带稳态分量,再应用希尔伯特变换,能够有效克服原有限制,为量化交易提供更可靠的市场状态识别工具。这一改进不仅保留了希尔伯特变换的瞬时分析能力,还增强了其对金融时间序列的适应性。当然,实际应用中还需考虑过拟合、参数优化、实时计算效率等问题。希望本文的探讨和代码示例能为你的量化策略研究带来新的启发。欢迎在云栈社区交流更多关于信号处理与量化交易的实战心得。




上一篇:LCSB方法解析:选择性反向传播如何实现大模型移动端训练提速与稳定
下一篇:C++ std::map operator[]的陷阱:详解查找与插入的误用与性能对比
您需要登录后才可以回帖 登录 | 立即注册

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

GMT+8, 2026-2-23 12:59 , Processed in 0.728580 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

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