""" Monte Carlo Simulation — Stress testing the strategy by shuffling trade sequences. """ import numpy as np import pandas as pd from typing import List def run_monte_carlo(trades: List[dict], initial_capital: float, iterations: int = 1000): """ Run Monte Carlo simulation on a list of historical trades. Args: trades: List of trade dictionaries with 'pnl' and 'entry_price'. initial_capital: Starting capital. iterations: Number of simulations. """ if not trades: return {"error": "No trades to simulate"} pnls = [t["pnl"] for t in trades] results = [] for _ in range(iterations): # Shuffle the order of trades shuffled_pnls = np.random.choice(pnls, size=len(pnls), replace=True) equity = initial_capital equity_curve = [initial_capital] max_dd = 0 peak = initial_capital for pnl in shuffled_pnls: equity += pnl equity_curve.append(equity) if equity > peak: peak = equity dd = (peak - equity) / peak if dd > max_dd: max_dd = dd results.append({ "final_equity": equity, "max_drawdown": max_dd * 100, "return_pct": (equity / initial_capital - 1) * 100 }) df_results = pd.DataFrame(results) stats = { "avg_return": df_results["return_pct"].mean(), "median_return": df_results["return_pct"].median(), "worst_case_return": df_results["return_pct"].min(), "best_case_return": df_results["return_pct"].max(), "avg_drawdown": df_results["max_drawdown"].mean(), "max_drawdown_95th": df_results["max_drawdown"].quantile(0.95), # Risk at 95% confidence "ruin_probability": (df_results["final_equity"] < initial_capital * 0.5).mean() * 100 # Prob of losing 50% } return stats, df_results def print_mc_report(stats): print("\n" + "="*40) print(" MONTE CARLO STRESS TEST") print("="*40) print(f"Avg Return: {stats['avg_return']:.2f}%") print(f"Median Return: {stats['median_return']:.2f}%") print(f"Best Case: {stats['best_case_return']:.2f}%") print(f"Worst Case: {stats['worst_case_return']:.2f}%") print(f"Avg Drawdown: {stats['avg_drawdown']:.2f}%") print(f"Max DD (95% CI): {stats['max_drawdown_95th']:.2f}%") print(f"Prob. of Ruin: {stats['ruin_probability']:.1f}%") print("="*40)