社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

用 Python 打造稳健的量化交易策略:从回测到蒙特卡洛验证(第二部分)

数据科学实战 • 昨天 • 17 次点击  

欢迎加入专注于财经数据与量化投研的【数据科学实战】知识星球!在这里,您将获取持续更新的《财经数据宝典》和《量化投研宝典》,这两部宝典相辅相成,为您在量化投研道路上提供明确指引。 《量化投研宝典》精选了业内持续维护且实用性强的开源工具(Backtrader、Qlib、VeighNa等),配合详细教程与代码示例,帮助您快速构建量化策略;《财经数据宝典》则汇集了多年财经数据维护经验,全面介绍从 AKShare、Tushare 到 Wind、iFind 等国内外数据源,并附有丰富的使用技巧。 无论您是量化投资新手还是经验丰富的研究者,星球社区都能帮您少走弯路,事半功倍,共同探索数据驱动的投资世界!

引言

在量化交易的世界里,一个看似优秀的策略在实盘中却可能表现平平。如何验证策略的稳健性?如何避免过度拟合?今天我们将通过一个完整的案例,展示如何使用 Python 构建一个基于 EMA 和 Stochastic 指标的动量策略,并通过前向验证(Walk-Forward Optimization)和蒙特卡洛模拟等方法,全面评估策略的真实表现。

策略核心思想

本文介绍的交易策略结合了两个经典的技术指标:

  1. EMA(指数移动平均线):用于判断趋势方向
  2. Stochastic(随机指标):用于识别超买超卖区域

入场信号

  • Stochastic K 线上穿 D 线
  • Stochastic K 值低于 30(超卖区)
  • 收盘价高于 EMA(上升趋势)

出场信号

  • Stochastic K 线下穿 D 线
  • Stochastic K 值高于 70(超买区)
  • 收盘价低于 EMA(下降趋势)

完整代码实现

让我们看看完整的策略实现代码:

import numpy as np
import pandas as pd
import yfinance as yf
import vectorbt as vbt
import itertools

# --- Stochastic 和 EMA 计算 ---
def calculate_ema_sto(df, ema_period=20, k_period=14, d_period=3, k_smooth=3):
    """
    计算 EMA 和 Stochastic 指标
    
    参数:
    - df: 包含 OHLC 数据的 DataFrame
    - ema_period: EMA 周期
    - k_period: Stochastic K 线周期
    - d_period: Stochastic D 线周期
    - k_smooth: K 线平滑周期
    """

    df = df.copy()
    
    # 计算 EMA
    df['EMA'] = df['Close'].ewm(span=ema_period, adjust=False).mean()
    
    # 计算 Stochastic
    low_k = df['Low'].rolling(window=k_period).min()
    high_k = df['High'].rolling(window=k_period).max()
    df['%K_raw'] = 100 * (df['Close'] - low_k) / (high_k - low_k)
    df['%K_smooth'] = df['%K_raw'].rolling(window=k_smooth).mean()
    df['%D'] = df['%K_smooth'].rolling(window=d_period).mean()
    
    return df

# --- 信号生成器 ---
def generate_signals_ema_sto(df):
    """
    根据 EMA 和 Stochastic 生成交易信号
    """

    # 入场信号
    entry_signal = (
        ((df['%K_smooth'] > df['%D'])) &  # K 线上穿 D 线
        (df['%K_smooth'] 30) &          # 超卖区
        (df['Close'] > df['EMA'])         # 价格在 EMA 上方
    )
    
    # 出场信号
    exit_signal = (
        ((df[ '%K_smooth'] < df['%D'])) &  # K 线下穿 D 线
        (df['%K_smooth'] > 70) &          # 超买区
        (df['Close'] < df['EMA'])         # 价格在 EMA 下方
    )
    
    return entry_signal, exit_signal

前向验证(Walk-Forward Optimization)

前向验证是避免过度拟合的关键技术。它通过滚动的训练窗口来优化参数,确保策略在未来数据上的表现。

def walk_forward_optimization(df, start_year, end_year):
    """
    执行前向验证优化
    
    使用 4 年训练窗口,1 年测试窗口的滚动方式
    """

    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:
            ema_p, k_p, d_p, ks_p = params
            
            # 计算指标并生成信号
            data = calculate_ema_sto(train_data, ema_p, k_p, d_p, ks_p)
            entries, exits = generate_signals_ema_sto(data)
            
            # 回测
            pf = vbt.Portfolio.from_signals(
                close=data['Open'],
                entries=entries.shift(1),  # 延迟一根 K 线执行
                exits=exits.shift(1),
                init_cash=100_000,
                fees=0.001,      # 0.1% 手续费
                slippage=0.002,  # 0.2% 滑点
                freq='D'
            )
            
            performance = pf.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)

策略评估指标

除了基本的收益率,我们还需要更全面的评估指标:

# === 计算风险调整后的收益指标 ===
risk_free_rate = 0.02# 2% 无风险利率

# 获取核心指标
car = portfolio.annualized_return()          # 年化收益率
vol = portfolio.annualized_volatility()      # 年化波动率
max_dd = abs(portfolio.max_drawdown())       # 最大回撤

# Sharpe 风格的调整收益率(基于波动率)
adj_car_sharpe = (car - risk_free_rate) / vol if vol != 0else np.nan

# Calmar 风格的调整收益率(基于回撤)
adj_car_calmar = car / max_dd if max_dd != 0else np.nan

# 计算市场暴露时间
exposure_percentage = calculate_exposure(df, combined_entries, combined_exits)

蒙特卡洛模拟验证

为了更全面地评估策略的稳健性,我们使用区块自助法(Block Bootstrap)进行蒙特卡洛模拟:

# === 区块自助法蒙特卡洛模拟 ===
n_simulations = 1000
block_size = 5# 每个区块包含 5 天

# 存储模拟结果
equity_paths = []
drawdowns = []
final_returns = []

# 基准收益和回撤
benchmark_return = -0.0919   # 买入持有策略收益
benchmark_drawdown = 0.4545# 买入持有策略最大回撤

# 模拟完整路径
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 = init_value * np.cumprod(1 + sampled_returns)
    equity_paths.append(equity)
    
    # 计算性能指标
    max_dd = np.max(1 - equity / np.maximum.accumulate(equity))
    total_return = (equity[-1] / init_value) - 1
    
    drawdowns.append(max_dd)
    final_returns.append(total_return)

# 统计超越基准的概率
prob_beat_return = sum(r > benchmark_return for r in final_returns) / n_simulations
prob_beat_dd = sum(d < benchmark_drawdown for d in drawdowns) / n_simulations

print(f"超越基准收益的概率:{prob_beat_return:.1%}")
print(f"超越基准回撤的概率:{prob_beat_dd:.1%}")

实战案例:AMT 股票交易

让我们以美国电塔公司(AMT)为例,展示策略的实际表现:

前向验证结果

年份
最优参数 (EMA, K, D, K_smooth)
2020
(20, 13, 2, 4)
2021
(13, 10, 4, 4)
2022
(19, 12, 5, 4)
2023
(5, 11, 5, 2)
2024
(5, 11, 5, 2)
2025
(9, 20, 4, 3)

策略表现对比

交易策略

  • 总收益率:19%
  • 最大回撤:41%
  • 夏普比率:0.30
  • 市场暴露时间:36.45%

买入持有策略

  • 总收益率:-9%
  • 最大回撤:45%
  • 夏普比率:0.09

策略相对基准的表现

  • Alpha: 0.0002(日均超额收益 0.02%)
  • Beta: 0.3449(策略波动率约为基准的 34%)
  • 相关性: 0.5849(与基准中度相关)

蒙特卡洛模拟结果

经过 1000 次模拟:

  • 平均收益率:31.77%
  • 5% 分位数收益:-40.45%
  • 95% 分位数收益:135.47%
  • 超越基准收益的概率:76.3%
  • 超越基准回撤的概率:86.5%

关键启示

  1. 参数自适应:不同市场阶段需要不同的参数设置,前向验证帮助我们动态调整
  2. 风险控制:虽然策略收益提升,但最大回撤改善有限,需要额外的风险管理措施
  3. 稳健性验证:蒙特卡洛模拟显示策略有较高概率超越基准,证明策略具有统计优势

总结

本文展示了如何构建一个完整的量化交易系统,从策略设计到稳健性验证。通过前向验证避免过度拟合,通过蒙特卡洛模拟评估策略的统计特性。虽然策略在 AMT 股票上取得了正收益,但投资者仍需注意:

  1. 历史表现不代表未来收益
  2. 实盘交易还需考虑更多因素(如资金管理、执行延迟等)
  3. 建议在多个品种上测试策略的普适性

记住,量化交易的核心不是找到"圣杯",而是通过科学的方法管理风险、获取稳定的超额收益。

参考文章

加入专注于财经数据与量化投研的知识星球【数据科学实战】,获取完整研究解析、详细回测框架代码实现和完整策略逻辑实操指南。

财经数据与量化投研知识社区

核心权益如下:

  1. 赠送《财经数据宝典》完整文档,汇集多年财经数据维护经验
  2. 赠送《量化投研宝典》完整文档,汇集多年量化投研领域经验
  3. 赠送《PyBroker-入门及实战》视频课程,手把手学习量化策略开发
  4. 每日分享高质量量化投研文章、代码和相关资料
  5. 定期更新高频财经数据
  6. 参与年度不少于 10 次专属直播与录播课程
  7. 与核心开发者直接交流,解决实际问题
  8. 获取专业微信群交流机会和课程折扣

星球已有丰富内容积累,包括量化投研论文、财经高频数据、 PyBroker 视频教程、定期直播、数据分享和答疑解难。适合对量化投研和财经数据分析有兴趣的学习者及从业者。欢迎加入我们!

好文推荐

1. 用 Python 打造股票预测系统:Transformer 模型教程(一)

2. 用 Python 打造股票预测系统:Transformer 模型教程(二)

3. 用 Python 打造股票预测系统:Transformer 模型教程(三)

4. 用 Python 打造股票预测系统:Transformer 模型教程(完结)

5. 揭秘隐马尔可夫模型:因子投资的制胜武器

6. YOLO 也能预测股市涨跌?计算机视觉在股票市场预测中的应用

7. 金融 AI 助手:FinGPT 让你轻松掌握市场分析

8. 量化交易秘籍:为什么专业交易员都在用对数收益率?

9. Python 量化投资利器:Ridge、Lasso 和 Elastic Net 回归详解

10. 掌握金融波动率模型:完整 Python 实现指南

好书推荐

《Python编程:从入门到实践(第3版)》是一本广受欢迎的 Python 入门经典教材,由经验丰富的程序员 Eric Matthes 编写。该书采用循序渐进的教学方式,从基础语法讲解到实战项目开发,内容编排合理,实例丰富,语言通俗易懂。全书配有大量练习题和完整项目实战,包括数据可视化、网络爬虫、Web 应用开发等,让读者在实践中掌握编程技巧。第3版还增加了 f-string、海龟绘图等最新的 Python 特性内容。这本书不仅适合零基础读者入门学习,也非常适合想系统掌握 Python 的编程爱好者以及数据分析、人工智能等领域的学习者。它不仅教授编程知识,更注重培养读者的编程思维,是一本非常值得投资的 Python 学习指南。


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/183233
 
17 次点击