
用蒙特卡洛模拟优化交易回测
用 Python 实现交易里的蒙特卡洛模拟,bootstrap 和参数化两条路怎么选,加上代码范式和那些会让结果直接作废的坑。
交互工具在翻译视图中可能无法使用。
用蒙特卡洛模拟优化交易回测
蒙特卡洛(Monte Carlo)干的事情,就是把一次回测变成一整套结果分布。两条路:bootstrap(自助法)和参数化,对应不同的问题;选错路,得到的只是看似自信的废话。
什么时候用哪个
- Bootstrap(重采样交易记录):手头有一份真实交易清单,想看这些单子能跑出多少条不同的资金曲线。不依赖分布假设。
- 参数化(按拟合分布抽样):想生成超出已观测样本的合成单子,比如千分之一概率的极端事件。需要先给收益率拟合一个分布。
默认走 bootstrap,只有当你愿意接受建模假设、又确实想看远端尾部时,才上参数化。
Bootstrap 实现范式
trades = array of R-multiples from backtest
n_sims = 10000
n_trades = len(trades)
terminal_equities = []
max_drawdowns = []
for i in range(n_sims):
sampled = random.choice(trades, size=n_trades, replace=True)
equity = cumsum(sampled)
terminal_equities.append(equity[-1])
max_drawdowns.append(max_drawdown(equity))
p5_terminal = percentile(terminal_equities, 5)
p95_drawdown = percentile(max_drawdowns, 95)
汇报的时候报第 5 百分位的期末资金和第 95 百分位的回撤。均值会骗人,尾部才是决策依据。
参数化实现
给日收益率拟合一个分布。厚尾市场用低自由度(3-5)的 Student's t 比正态分布靠谱得多。然后抽样:
df, loc, scale = t.fit(daily_returns)
simulated = t.rvs(df, loc, scale, size=(n_sims, n_days))
equity_curves = cumprod(1 + simulated, axis=1)
参数化的好处是能模拟出比观测样本更长的历史,估极端事件很有用,但结果好不好全看拟合质量。一定要把拟合的尾部和实际尾部对比一下;拟合低估了实际极值,参数化模拟就低估了风险。
让结果作废的几个坑
- 交易记录有自相关,却去重采样收益率。 趋势系统会出连击,按单笔重采样会把连击结构打散,回撤被低估。用块 bootstrap(block bootstrap),块长按自相关衰减程度取(5-20 笔)。
- 忽略成本。 重采样毛 R 倍数(R-multiple),滑点和手续费就漏了。要么重采样净 R 倍数,要么每笔扣成本。
- 只报均值。 均值期末 +30%、但第 5 百分位是 -50%,这是个爆仓风险,不是个赚钱系统。
- 模拟次数太少。 低于 1000 次,百分位估计抖得很厉害。尾部估计稳一点,用 10000 次。
怎么用输出
- 仓位管理:调每笔风险,让第 95 百分位回撤落在你能扛的回撤之内(比如权益的 20%)。
- 系统比较:比第 5 百分位期末资金,别比均值;更优的最坏情况才更稳健。
- 下线判据:第 95 百分位回撤超过你的生存阈值,这套系统在当前规模下不可交易。
验证
要拿现实校验:在交易清单的前半段跑 bootstrap,把预测的回撤分布和后半段的实际回撤对比。如果实际值落在模拟 90% 置信区间外,你的模型有问题,先修再信任何输出。
说白了,蒙特卡洛是个 sanity check(合理性检查),不是预言。它告诉你回测对成交顺序和采样有多脆弱——这个脆弱度,才是你最诚实的那一个风险数字。
实时行情
打开完整图表 →相关市场数据由 TradingView 提供。
我的笔记
登录后可在本文保存笔记并与社区分享。
下一篇推荐
Standard Deviation, Volatility, and Beta Calculations
Calculate standard deviation, annualized volatility, and Beta correctly for trading, with the common errors and the right windows for each measure.
阅读更多 →Smart Recommendations