🚀 AI 一键生成 ptrade 策略代码

如何导出 PTrade 交易数据,并使用蒙特卡洛模拟来评估策略的稳健性?

ptrade | 发布时间: 2025/12/19
以下内容由 EasyQuant 生成。

问题描述

如何对我的策略进行蒙特卡洛模拟,以检验其稳健性?

解决方案

在PTrade量化交易平台中,蒙特卡洛模拟(Monte Carlo Simulation)通常不直接用于策略的实时交易逻辑(handle_data)中,而是用于研究(Research)阶段回测后的分析

它的核心目的是通过**重抽样(Resampling)**历史收益数据,生成成千上万种可能的市场路径,从而评估策略在极端情况下的表现(如最大回撤、预期收益的分布),以检验策略是否仅仅是因为“运气好”才盈利。

以下是在PTrade研究环境(Notebook)中进行蒙特卡洛模拟的完整步骤和代码实现。

核心思路:Bootstrap重抽样法

  1. 获取数据:提取策略的历史日收益率单笔交易盈亏比
  2. 随机重组:打乱这些收益率的顺序(有放回或无放回抽样),生成新的资金曲线。
  3. 重复模拟:重复上述步骤N次(例如1000次)。
  4. 统计分析:观察模拟出的最大回撤分布、年化收益分布,确定策略的置信区间。

PTrade 研究环境实现代码

你可以将以下代码复制到 PTrade 的 研究(Notebook) 中运行。为了演示,代码中包含了一段生成模拟收益数据的逻辑,实际使用时请替换为你策略的真实收益率数据。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# ==========================================
# 1. 数据准备 (实际使用时请替换为你的策略数据)
# ==========================================
def get_strategy_returns():
    """
    模拟获取策略的日收益率序列。
    在实际场景中,你可以读取回测保存的csv文件,
    或者使用 get_price 计算基准收益来模拟。
    """
    np.random.seed(42)
    # 模拟250个交易日,均值0.05%,波动率2%
    returns = np.random.normal(0.0005, 0.02, 250) 
    return pd.Series(returns)

# ==========================================
# 2. 蒙特卡洛模拟核心函数
# ==========================================
def run_monte_carlo(returns, simulations=1000, confidence_level=0.95):
    """
    执行蒙特卡洛模拟
    :param returns: pandas.Series, 策略的日收益率序列
    :param simulations: int, 模拟次数
    :param confidence_level: float, 置信度
    """
    print("开始执行蒙特卡洛模拟,模拟次数: %d..." % simulations)
    
    # 存储每次模拟的最终累计收益和最大回撤
    sim_final_returns = []
    sim_max_drawdowns = []
    
    # 绘图初始化
    plt.figure(figsize=(12, 6))
    
    # 原始数据的累积收益曲线(作为对比)
    original_cum_ret = (1 + returns).cumprod()
    plt.plot(original_cum_ret.values, color='black', linewidth=2, label='Original Strategy')
    
    for i in range(simulations):
        # 核心逻辑:Bootstrap重抽样 (有放回抽样)
        # 随机打乱收益率的顺序,模拟不同的市场路径
        random_returns = np.random.choice(returns, size=len(returns), replace=True)
        
        # 计算资金曲线
        cum_returns = (1 + random_returns).cumprod()
        
        # 记录最终收益
        sim_final_returns.append(cum_returns[-1])
        
        # 计算最大回撤
        # 1. 计算累计最大值
        roll_max = np.maximum.accumulate(cum_returns)
        # 2. 计算回撤
        drawdown = (cum_returns - roll_max) / roll_max
        # 3. 记录最大回撤 (取最小值,因为回撤是负数)
        sim_max_drawdowns.append(drawdown.min())
        
        # 绘制前50条模拟路径,避免图表过于杂乱
        if i < 50:
            plt.plot(cum_returns, color='grey', alpha=0.1)

    plt.title('Monte Carlo Simulation of Equity Curves (Bootstrap)')
    plt.xlabel('Trading Days')
    plt.ylabel('Cumulative Returns')
    plt.legend()
    plt.grid(True)
    plt.show()
    
    # ==========================================
    # 3. 统计分析与稳健性评估
    # ==========================================
    sim_final_returns = np.array(sim_final_returns)
    sim_max_drawdowns = np.array(sim_max_drawdowns)
    
    # 计算分位数 (VaR - Value at Risk)
    # 比如 95% 的置信度下,最坏的情况是多少
    worst_return_percentile = np.percentile(sim_final_returns, (1 - confidence_level) * 100)
    worst_drawdown_percentile = np.percentile(sim_max_drawdowns, (1 - confidence_level) * 100)
    
    print("-" * 30)
    print("蒙特卡洛模拟结果分析 (置信度 %.0f%%):" % (confidence_level * 100))
    print("-" * 30)
    print("原始策略最终净值: %.4f" % original_cum_ret.iloc[-1])
    print("模拟平均最终净值: %.4f" % np.mean(sim_final_returns))
    print("模拟最差最终净值 (VaR): %.4f" % worst_return_percentile)
    print("-" * 30)
    print("模拟平均最大回撤: %.2f%%" % (np.mean(sim_max_drawdowns) * 100))
    print("模拟最差最大回撤 (VaR): %.2f%%" % (worst_drawdown_percentile * 100))
    print("-" * 30)
    
    # 绘制最大回撤分布图
    plt.figure(figsize=(10, 4))
    plt.hist(sim_max_drawdowns * 100, bins=50, color='red', alpha=0.7)
    plt.title('Distribution of Max Drawdowns')
    plt.xlabel('Max Drawdown (%)')
    plt.ylabel('Frequency')
    plt.grid(True)
    plt.show()

# ==========================================
# 执行主程序
# ==========================================
# 1. 获取收益率数据
strategy_daily_returns = get_strategy_returns()

# 2. 运行模拟
run_monte_carlo(strategy_daily_returns, simulations=1000)

结果解读指南

运行上述代码后,你需要关注以下几个关键指标来评估稳健性:

  1. 模拟路径图(Equity Curves)

    • 如果灰色的模拟线条非常发散(有的上天,有的入地),说明策略对交易顺序非常敏感,稳健性较差。
    • 如果大部分线条都呈现向上的趋势,说明策略具有正期望值,不仅仅是运气。
  2. 最差最大回撤(VaR Drawdown)

    • 代码中计算了95%置信度下的最差回撤。例如,如果你的原始回撤是 -10%,但模拟显示有5%的概率回撤会达到 -30%,那么你在实盘中就要做好承受 -30% 回撤的心理准备和资金管理。
  3. 平均最终净值 vs 原始净值

    • 如果模拟平均最终净值远低于原始策略最终净值,说明原始策略的表现可能包含了很多“运气成分”(即特定的行情顺序有利于策略)。

如何在PTrade中获取真实的策略收益率?

在PTrade中,你无法直接在Notebook里调用回测引擎的内部数据。通常有以下两种方法获取真实数据:

方法一:回测后导出(推荐)

  1. 运行你的策略回测。
  2. 在回测结果页面,找到“收益概览”或“交易明细”。
  3. 导出为 Excel/CSV 文件。
  4. 将文件上传到 PTrade 研究环境,使用 pd.read_csv 读取并计算 pct_change() 得到日收益率序列,然后传入上面的 run_monte_carlo 函数。

方法二:在策略中保存数据
在策略代码的 after_trading_endhandle_data 中,将每日权益记录到全局变量或文件中(注意:PTrade实盘/回测对文件写入有路径限制,通常用 logget_trades_file)。

总结

蒙特卡洛模拟通过打乱市场节奏,剥离了“时间运气”因素。如果一个策略在打乱顺序后,依然大概率能赚钱,且最大回撤在可接受范围内,那么该策略的**鲁棒性(Robustness)**就较强。


Q&A

Q: 为什么使用重抽样(Resampling)而不是生成随机价格路径(Random Walk)?
A: 重抽样保留了策略在特定市场环境下的单次博弈特征(即保留了收益率的统计分布特性,如肥尾效应),只是改变了发生的顺序。生成完全随机的价格路径(如几何布朗运动)可能会破坏市场本身的波动率聚集等特征,对于依赖特定K线形态的策略来说,重抽样更具参考价值。

Q: 模拟次数设置多少合适?
A: 通常建议至少 1000次,以便得到相对平滑的分布曲线和准确的分位数统计。

Q: 如果模拟结果显示回撤巨大,我该怎么办?
A: 这意味着策略存在潜在的破产风险。建议:1. 降低仓位(去杠杆);2. 优化止损逻辑;3. 增加过滤条件,避免在特定高波动的市场环境下开仓。