Development of Monte Carlo Simulation System for Trading Strategy Assessment
Monte Carlo simulation — method of evaluating stochastic systems through multiple random modeling. In trading it answers questions backtesting cannot solve: "Could the same loss happen in different order?", "What's probability of losing 20% in next 6 months?", "Can strategy survive 5-year drawdown?".
Why Monte Carlo for Trading
Single Backtest Curve is Random: Historical backtest — one realized path from infinite number of possible ones. Trades occurred in specific order, under specific market volatility. MC generates thousands of alternative paths from same trades.
Answers to Key Questions:
- Confidence interval for expected return
- Probability of specific drawdown level
- Required starting capital for 95% survival probability
- Expected time to recovery after drawdown
Monte Carlo Methods for Trading Systems
Randomization by Trades: Simplest approach — shuffle historical trades:
import numpy as np
import pandas as pd
def monte_carlo_randomize_trades(trade_returns, n_simulations=10000, n_periods=252):
"""
trade_returns: array of returns for each trade
Each simulation — random sampling with replacement
"""
results = np.zeros((n_simulations, n_periods))
for i in range(n_simulations):
sampled_trades = np.random.choice(trade_returns, size=n_periods, replace=True)
results[i] = np.cumprod(1 + sampled_trades) - 1
return results
equity_curves = monte_carlo_randomize_trades(historical_trades)
# Statistics
p5, p50, p95 = np.percentile(equity_curves[:, -1], [5, 50, 95])
print(f"5th percentile final equity: {p5:.1%}")
print(f"Median final equity: {p50:.1%}")
print(f"95th percentile final equity: {p95:.1%}")
Maximum Adverse Excursion (MAE) Simulation:
def max_drawdown_distribution(equity_curves):
max_dd = np.zeros(len(equity_curves))
for i, curve in enumerate(equity_curves):
running_max = np.maximum.accumulate(1 + curve)
drawdown = (1 + curve) / running_max - 1
max_dd[i] = drawdown.min()
return max_dd
dd_dist = max_drawdown_distribution(equity_curves)
prob_20pct_drawdown = np.mean(dd_dist < -0.20)
print(f"Probability of 20%+ drawdown: {prob_20pct_drawdown:.1%}")
Parametric Monte Carlo Simulation
Alternative approach: instead of shuffling trades, generate new ones from statistical model:
GBM (Geometric Brownian Motion):
def gbm_simulation(mu, sigma, S0, T, n_steps, n_sims):
dt = T / n_steps
returns = np.random.normal((mu - 0.5*sigma**2)*dt, sigma*np.sqrt(dt), (n_sims, n_steps))
price_paths = S0 * np.exp(np.cumsum(returns, axis=1))
return price_paths
Student-t Distribution (Better for Finance): Normal distribution underestimates fat tails. Student-t with 3-7 degrees of freedom better describes real return distributions:
from scipy import stats
def student_t_simulation(mu, sigma, df, n_steps, n_sims):
returns = stats.t.rvs(df=df, loc=mu, scale=sigma, size=(n_sims, n_steps))
return np.cumprod(1 + returns, axis=1)
Bootstrap Methods:
- Stationary Bootstrap: random blocks of variable length (preserves temporal dependencies)
- Block Bootstrap: fixed blocks of k periods
Risk of Ruin Assessment
def probability_of_ruin(equity_curves, ruin_threshold=0.5):
"""
Probability of losing >50% of capital at least once
"""
min_equity = equity_curves.min(axis=1)
return np.mean(min_equity < (1 - ruin_threshold))
prob_ruin = probability_of_ruin(equity_curves, ruin_threshold=0.5)
print(f"Probability of 50% drawdown (ruin): {prob_ruin:.1%}")
Optimization Through MC
Monte Carlo for Position Sizing: For different f (Kelly fraction) simulate 10,000 paths and choose f* maximizing final capital with max drawdown < X% constraint:
optimal_f = find_optimal_f(
trade_returns,
max_acceptable_drawdown=0.25,
n_simulations=10000
)
Stress Testing Scenarios:
- 2008 Crisis: increase negative skew and fat tails by 2σ
- COVID Crash: series of 10 losing trades in a row (real sequence)
- 2022 Bear Market: high correlation of losses (non-diversifiable risk)
Test strategy in these stress scenarios: will it survive with proper risk management?
Visualization and Reporting
Standard outputs for trader/investor:
- Probability cone (fan chart): p5/p25/p50/p75/p95 paths of capital
- Distribution of final returns
- Distribution of maximum drawdown
- Probability of various drawdown levels
- Expected time to new equity high
Automated Reporting: Every time new trades added — automatically recalculate MC and update report. If ruin probability rose from 3% to 8% — alert for manager.
Timeline: basic MC trade randomization + visualization — 1-2 weeks. Full system with parametric models, stress testing and automated reporting — 4-6 weeks.







