问题描述
解决方案
在PTrade量化交易平台中,蒙特卡洛模拟(Monte Carlo Simulation)通常不直接用于策略的实时交易逻辑(handle_data)中,而是用于研究(Research)阶段或回测后的分析。
它的核心目的是通过**重抽样(Resampling)**历史收益数据,生成成千上万种可能的市场路径,从而评估策略在极端情况下的表现(如最大回撤、预期收益的分布),以检验策略是否仅仅是因为“运气好”才盈利。
以下是在PTrade研究环境(Notebook)中进行蒙特卡洛模拟的完整步骤和代码实现。
核心思路:Bootstrap重抽样法
- 获取数据:提取策略的历史日收益率或单笔交易盈亏比。
- 随机重组:打乱这些收益率的顺序(有放回或无放回抽样),生成新的资金曲线。
- 重复模拟:重复上述步骤N次(例如1000次)。
- 统计分析:观察模拟出的最大回撤分布、年化收益分布,确定策略的置信区间。
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)
结果解读指南
运行上述代码后,你需要关注以下几个关键指标来评估稳健性:
-
模拟路径图(Equity Curves):
- 如果灰色的模拟线条非常发散(有的上天,有的入地),说明策略对交易顺序非常敏感,稳健性较差。
- 如果大部分线条都呈现向上的趋势,说明策略具有正期望值,不仅仅是运气。
-
最差最大回撤(VaR Drawdown):
- 代码中计算了95%置信度下的最差回撤。例如,如果你的原始回撤是 -10%,但模拟显示有5%的概率回撤会达到 -30%,那么你在实盘中就要做好承受 -30% 回撤的心理准备和资金管理。
-
平均最终净值 vs 原始净值:
- 如果
模拟平均最终净值远低于原始策略最终净值,说明原始策略的表现可能包含了很多“运气成分”(即特定的行情顺序有利于策略)。
- 如果
如何在PTrade中获取真实的策略收益率?
在PTrade中,你无法直接在Notebook里调用回测引擎的内部数据。通常有以下两种方法获取真实数据:
方法一:回测后导出(推荐)
- 运行你的策略回测。
- 在回测结果页面,找到“收益概览”或“交易明细”。
- 导出为 Excel/CSV 文件。
- 将文件上传到 PTrade 研究环境,使用
pd.read_csv读取并计算pct_change()得到日收益率序列,然后传入上面的run_monte_carlo函数。
方法二:在策略中保存数据
在策略代码的 after_trading_end 或 handle_data 中,将每日权益记录到全局变量或文件中(注意:PTrade实盘/回测对文件写入有路径限制,通常用 log 或 get_trades_file)。
总结
蒙特卡洛模拟通过打乱市场节奏,剥离了“时间运气”因素。如果一个策略在打乱顺序后,依然大概率能赚钱,且最大回撤在可接受范围内,那么该策略的**鲁棒性(Robustness)**就较强。
Q&A
Q: 为什么使用重抽样(Resampling)而不是生成随机价格路径(Random Walk)?
A: 重抽样保留了策略在特定市场环境下的单次博弈特征(即保留了收益率的统计分布特性,如肥尾效应),只是改变了发生的顺序。生成完全随机的价格路径(如几何布朗运动)可能会破坏市场本身的波动率聚集等特征,对于依赖特定K线形态的策略来说,重抽样更具参考价值。
Q: 模拟次数设置多少合适?
A: 通常建议至少 1000次,以便得到相对平滑的分布曲线和准确的分位数统计。
Q: 如果模拟结果显示回撤巨大,我该怎么办?
A: 这意味着策略存在潜在的破产风险。建议:1. 降低仓位(去杠杆);2. 优化止损逻辑;3. 增加过滤条件,避免在特定高波动的市场环境下开仓。