欢迎加入专注于财经数据与量化投研的【数据科学实战】知识星球!在这里,您将获取持续更新的《财经数据宝典》和《量化投研宝典》,这两部宝典相辅相成,为您在量化投研道路上提供明确指引。 《量化投研宝典》精选了业内持续维护且实用性强的开源工具(Backtrader、Qlib、VeighNa等),配合详细教程与代码示例,帮助您快速构建量化策略;《财经数据宝典》则汇集了多年财经数据维护经验,全面介绍从 AKShare、Tushare 到 Wind、iFind 等国内外数据源,并附有丰富的使用技巧。 无论您是量化投资新手还是经验丰富的研究者,星球社区都能帮您少走弯路,事半功倍,共同探索数据驱动的投资世界!
引言
在量化交易领域,如何构建一个既稳定又能适应市场变化的交易系统一直是投资者关注的焦点。今天,我们将深入探讨一个基于 MACD、ADX 和 SMA 三个经典技术指标的自适应交易策略。这个策略不仅实现了 612% 的回报率,更重要的是将最大回撤从 88% 降低到了 32%,展现出了优秀的风险控制能力。
本文将通过 Python 代码实现,带你一步步构建这个交易系统,并通过前向优化(Walk-Forward Optimization)和蒙特卡洛模拟等方法验证其稳健性。
核心指标介绍
1. MACD(移动平均收敛发散指标)
MACD 是一个动量振荡器,通过计算两条指数移动平均线的差值来判断趋势方向和潜在的反转点。
2. ADX(平均趋向指标)
ADX 用于衡量趋势的强度。通常当 ADX 值大于 20 时,表示市场处于强趋势中,这有助于过滤掉噪音信号。
3. SMA(简单移动平均线)
SMA 作为动态支撑/阻力线使用。价格突破 SMA 确认上升趋势,作为入场的最终确认信号。
策略逻辑
入场信号
同时满足以下条件时产生买入信号:
出场信号
满足以下条件时平仓:
核心代码实现
指标计算函数
import numpy as np
import pandas as pd
import yfinance as yf
import vectorbt as vbt
import itertools
def calculate_indicators(df, macd_fast, macd_slow, macd_signal, adx_window, sma_window):
"""
计算 MACD、ADX 和 SMA 指标
参数:
df: 包含价格数据的 DataFrame
macd_fast: MACD 快线周期
macd_slow: MACD 慢线周期
macd_signal: MACD 信号线周期
adx_window: ADX 计算窗口
sma_window: SMA 计算窗口
"""
df = df.copy()
# 计算 MACD
ema_fast = df['Close'].ewm(span=macd_fast, adjust=False).mean()
ema_slow = df['Close'].ewm(span=macd_slow, adjust=False).mean()
df['MACD'] = ema_fast - ema_slow
df['MACD_Signal'] = df['MACD'].ewm(span=macd_signal, adjust=False).mean()
# 计算 ADX
high = df['High']
low = df['Low']
close = df['Close']
# 计算方向性移动
plus_dm = high.diff()
minus_dm = low.diff()
plus_dm[plus_dm 0] = 0
minus_dm[minus_dm > 0] = 0
# 计算真实波动范围
tr1 = high - low
tr2 = abs(high - close.shift())
tr3 = abs(low - close.shift())
tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
# 计算平均真实波动范围
atr = tr.rolling(window=adx_window).mean()
# 计算方向性指标
plus_di = 100 * (plus_dm.rolling(window=adx_window).mean() / atr)
minus_di = 100 * (minus_dm.rolling(window=adx_window).mean() / atr)
# 计算 ADX
dx = (abs(plus_di - minus_di) / (plus_di + minus_di)) * 100
df['ADX'] = dx.rolling(window=adx_window).mean()
# 计算 SMA
df['SMA'] = df['Close'].rolling(window=sma_window).mean()
return df
信号生成函数
def generate_signals(df):
"""
根据策略逻辑生成买卖信号
参数:
df: 包含指标的 DataFrame
返回:
entry_signal: 买入信号
exit_signal: 卖出信号
"""
# 买入信号:MACD 上穿信号线且大于零,ADX > 20,价格 > SMA
entry_signal = (
(df['MACD'] > df['MACD_Signal']) &
(df['MACD'].shift(1) <= df['MACD_Signal'].shift(1)) &
(df['MACD'] > 0) &
(df['ADX'] > 20) &
(df['Close'] > df['SMA'])
)
# 卖出信号:MACD 下穿信号线且小于零,价格 < SMA
exit_signal = (
(df['MACD'] < df['MACD_Signal']) &
(df['MACD'].shift(1) >= df['MACD_Signal'].shift(1)) &
(df['MACD'] 0) &
(df['Close'] < df['SMA'])
)
return entry_signal, exit_signal
前向优化(Walk-Forward Optimization)
前向优化是一种更接近实际交易的参数优化方法。它将数据分为训练集和测试集,每年使用前 4 年的数据找出最优参数,然后在下一年应用这些参数进行测试。
参数优化范围
前向优化实现
def walk_forward_optimization(df, start_year, end_year):
"""
执行前向优化
参数:
df: 价格数据
start_year: 开始年份
end_year: 结束年份
"""
results = []
param_combinations = generate_parameter_combinations()
# 对每一年进行优化
for test_year in range(start_year + 4, end_year + 1):
train_start = test_year - 4
train_end = test_year - 1
# 获取训练数据
train_data = df[(df.index.year >= train_start) &
(df.index.year <= train_end)]
best_params = None
best_performance = -np.inf
# 测试所有参数组合
for params in param_combinations:
macd_f, macd_s, macd_sig, adx_w, sma_w = params
# 计算指标和信号
data = calculate_indicators(train_data, macd_f, macd_s,
macd_sig, adx_w, sma_w)
entries, exits = generate_signals(data)
# 创建投资组合并计算收益
portfolio = vbt.Portfolio.from_signals(
close=data['Open'],
entries=entries.shift(1).fillna(False),
exits=exits.shift(1).fillna(False),
init_cash=100_000,
fees=0.001, # 0.1% 手续费
slippage=0.002, # 0.2% 滑点
freq='D'
)
performance = portfolio.total_return()
# 更新最佳参数
if performance > best_performance:
best_performance = performance
best_params = params
results.append({
'Year': test_year,
'Best_Params': best_params
})
return pd.DataFrame(results)
策略表现分析
优化结果
通过前向优化,我们得到了每年的最优参数组合:
- 2020 年:MACD(8,23,7),ADX(12),SMA(5)
- 2021 年:MACD(12,26,9),ADX(14),SMA(5)
- 2022 年:MACD(12,26,9),ADX(16),SMA(5)
- 2023 年:MACD(12,26,9),ADX(16),SMA(33)
- 2024 年:MACD(10,25,7),ADX(16),SMA(5)
- 2025 年:MACD(8,24,9),ADX(12),SMA(5)
关键绩效指标
策略在 2020-2025 年的表现:
Alpha 和 Beta 分析
# 计算策略相对于基准的 Alpha 和 Beta
from scipy.stats import linregress
def calculate_alpha_beta(portfolio_returns, benchmark_returns):
"""
计算策略的 Alpha 和 Beta
"""
# 使用线性回归计算
slope, intercept, r_value, _, _ = linregress(
benchmark_returns, portfolio_returns
)
beta = slope
alpha = intercept
correlation = portfolio_returns.corr(benchmark_returns)
return alpha, beta, correlation
计算结果:
- Alpha:0.0010(日度),约等于年化 25%
- Beta:0.4369(策略波动性约为市场的 44%)
蒙特卡洛模拟验证
为了验证策略的稳健性,我们使用区块自助法(Block Bootstrap)进行蒙特卡洛模拟:
def monte_carlo_simulation(returns, n_simulations=1000, block_size=5):
"""
使用区块自助法进行蒙特卡洛模拟
参数:
returns: 历史收益率
n_simulations: 模拟次数
block_size: 区块大小
"""
n_days = len(returns)
n_blocks = int(np.ceil(n_days / block_size))
results = {
'final_returns': [],
'max_drawdowns': [],
'sharpe_ratios': []
}
for _ in range(n_simulations):
# 随机抽取区块
block_indices = np.random.randint(
0, len(returns) - block_size + 1, size=n_blocks
)
# 构建模拟收益序列
sampled_returns = np.concatenate([
returns[i:i+block_size] for i in block_indices
])[:n_days]
# 计算累计收益
equity = 100 * np.cumprod(1 + sampled_returns)
# 计算绩效指标
total_return = (equity[-1] / 100) - 1
max_dd = np.max(1 - equity / np.maximum.accumulate(equity))
sharpe = np.mean(sampled_returns) / np.std(sampled_returns) * np.sqrt(252)
results['final_returns'].append(total_return)
results['max_drawdowns'].append(max_dd)
results['sharpe_ratios'].append(sharpe)
return results
模拟结果
1000 次模拟的统计结果:
重要发现:
实战应用建议
参数自适应:建议每季度或半年重新优化参数,保持策略的适应性。
风险管理:虽然策略的回撤控制较好,但仍建议设置止损点,如单笔交易最大损失不超过 2%。
分散投资:将该策略应用于多个相关性较低的标的,进一步降低风险。
交易成本:实盘交易时要充分考虑手续费和滑点的影响,本策略已经考虑了 0.1% 的手续费和 0.2% 的滑点。
总结
本文介绍的基于 MACD、ADX 和 SMA 的自适应交易策略展现出了优秀的风险调整后收益。通过前向优化和严格的多条件信号筛选,策略不仅实现了较高的收益率,更重要的是大幅降低了最大回撤,提供了更平滑的收益曲线。
蒙特卡洛模拟结果表明,该策略具有较好的稳健性,在各种市场情况下都能保持相对稳定的表现。对于 Python 量化交易学习者来说,这是一个很好的实战案例,展示了如何将经典技术指标组合成一个完整的交易系统。
需要提醒的是,历史回测结果不代表未来表现,实际交易前请务必进行充分的测试和风险评估。
参考文章
加入专注于财经数据与量化投研的知识星球【数据科学实战】,获取完整研究解析、详细回测框架代码实现和完整策略逻辑实操指南。财经数据与量化投研知识社区
核心权益如下:
- 赠送《财经数据宝典》完整文档,汇集多年财经数据维护经验
- 赠送《量化投研宝典》完整文档,汇集多年量化投研领域经验
- 赠送《PyBroker-入门及实战》视频课程,手把手学习量化策略开发
星球已有丰富内容积累,包括量化投研论文、财经高频数据、 PyBroker 视频教程、定期直播、数据分享和答疑解难。适合对量化投研和财经数据分析有兴趣的学习者及从业者。欢迎加入我们!