Monte Carlo

Your track record is one sample of what could have happened. Monte Carlo resamples or models your daily returns to generate thousands of alternative paths, so you can see the range of outcomes instead of a single line — and estimate the odds of deep drawdowns or ruin.

You can run it on the whole portfolio or a single strategy. Active weekday filters are respected.

The series fed to the simulation is built from trading days only — the days you actually had a position. Idle calendar days (weekends, holidays, gaps between trades) are not part of the resampling pool, for the portfolio exactly as for a single strategy. This keeps both runs on the same footing: the horizon below is counted in trading days, and the portfolio simulation is directly comparable to the single-strategy one (no diluted volatility, no drift collapsing toward zero from padded idle days).

With dynamic sizing: the engine changes

When at least one strategy uses dynamic sizing (and the source is the portfolio, or that sized strategy), the simulator switches engine automatically: instead of resampling a produced P/L series, it resamples the raw trades in calendar blocks and re-runs the allocation inside every path — capital, compounding and the daily risk budget react to each simulated history, so the capital→size feedback loop is genuinely stressed. In a hybrid portfolio each block carries the sized trades and the fixed legs' daily P/L of the same period, preserving the correlation between legs; fixed-leg P/L enters the compounding capital from the next day and never consumes the daily budget.

What changes in the controls, and why:

  • Model becomes the trade block size (weekly ≈ 5, monthly ≈ 21, quarterly ≈ 63 trading days). Parametric models (Student-t, GARCH…) generate returns, not trades — they cannot feed a per-trade allocator, so they are unavailable; asking for one returns an explicit error.
  • Horizon disappears: every path replays as many blocks as the history contains, so simulated paths have the history's length.
  • Sizing (fixed vs compounding) is not asked: it is governed by the workspace's own Compounding switch and daily budget, echoed in the results header.
  • Winsorize here trims the premium/margin reference used for the fixed-sizing comparison — not the P/L tail.

The verdict compares the dynamic path (the real engine re-run per path) against a fixed sizing benchmark (contracts computed once on the initial capital), with ruin probability, final distribution and drawdown read off the dynamic paths. Selecting a single fixed strategy as the source keeps the classic series engine below, untouched.

Sizing: fixed contracts vs compounding

This is the single most important choice, because it decides how each resampled day changes the account — and it can change the median outcome by 2× or more.

SizingWhat it resamplesEquity recursionUse it when
Fixed contracts ($)defaultthe daily P/L in dollarsequity = capital + Σ P/L (additive)position size is fixed (e.g. always 1 contract): the dollar P/L does not grow with the account.
Compounding (%)the daily % returnsequity = capital × Π(1+r) (multiplicative)size scales with equity (fixed-fractional, reinvested profits, "N contracts per $X").

Why the default is fixed contracts

If your backtest trades a fixed number of contracts, its percentage returns are an artefact of the account size: a constant ±$400/day is a big % on a small early account and a tiny % on a large late one. Compounding those percentages re-applies the early small-account rates to an ever-growing balance, so it manufactures exponential growth the strategy can never realise — inflating the median, driving the probability of ruin to ~0, and making the max drawdown vanish. For a fixed-size book the honest model is additive in dollars: a +$400 day is +$400 wherever the path sits. Only switch to compounding if you genuinely scale contracts as the account grows.

In fixed-contract mode an absorbing ruin barrier is active: a path that touches the ruin level stops there (a real account that draws down that far can no longer post margin to keep trading), so the ruin probability is meaningful and responds to your starting capital. Compounding mode keeps the legacy non-absorbing behaviour.

Where to find it, and when to switch

The sizing control lives under Advanced and is off by default — every run is fixed-contract (additive) unless you deliberately enable compounding (and when it's on, the collapsed Advanced summary shows a · compounding marker so it's never silently active). Switch to compounding only when the series you uploaded is already equity-scaled — e.g. a fixed-fractional backtest where the broker export shows the contract count growing with the account. If instead you have a fixed 1-lot backtest and you want to study sizing up with capital, don't use this toggle: use the Risk Sizing module, which models dynamic position sizing properly (it recomputes contracts each day from your current capital and risk rules), rather than naively compounding percentage returns.

Choosing a model

VECTOR offers six models, from production-grade to didactic. Block bootstrap is the default and a safe general choice.

ModelWhat it doesUse it when
FHS + GARCH(1,1)Filtered Historical Simulation: fits a GARCH conditional-volatility model and bootstraps its standardised residuals. The market standard for VaR.Returns show volatility clustering (calm and stormy regimes).
Block bootstrapStationary bootstrap (Politis–Romano): resamples blocks of consecutive days, preserving autocorrelation and clustering.A robust default — structure without a parametric model.
Skewed Student-tFernández–Steel distribution: captures skew + fat tails, with degrees of freedom and skew fitted by MLE.Returns are asymmetric (e.g. short-vol, crash risk).
Student-tSymmetric fat-tailed distribution fitted by MLE.Symmetric returns with tail risk.
Bootstrap (IID)Resamples single days independently. Destroys serial dependence and underestimates drawdowns.Teaching / baseline only.
Gaussian GBMLog-normal random walk. Ignores fat tails.Teaching / baseline only.

IID and Gaussian are didactic

The last two models deliberately ignore real-world structure (clustering, fat tails). They're useful to show why the others matter — not to size real risk. Prefer Block bootstrap or FHS+GARCH for decisions.

Parameters

Sizing
Fixed contracts ($, additive) or Compounding (%, multiplicative). Default: fixed contracts. See above — this is the choice that most changes the result.
Model
One of the six above. Default: Block bootstrap.
Simulations
Number of paths, 100–1,000,000 (default 1,000). More paths = more precise risk numbers (VaR, CVaR, ruin, drawdown), at a slower run. The equity fan converges after a few thousand paths and won't visibly change beyond that — raise the count to sharpen the tail statistics, not the picture.
Horizon
Length of each path in trading days, 10–1,260 (default 252 ≈ one year). Going much beyond your historical sample length just resamples the same history repeatedly.
Ruin threshold
Equity level, as a % of starting capital, that counts as "ruin" if touched (0–100, default 50).
Block length
For bootstrap / FHS: days per block. Auto-estimated (Politis–White) or set manually. Presets: 5 (week), 21 (month), 63 (quarter).
Winsorize
Clips the sampled days to the chosen low/high percentiles before resampling, so a few extreme days don't dominate. Off by default (0–100). Caution: it also clips the loss tail, so drawdown, VaR and ruin probability come out more optimistic — use it to tame anomalous outliers, not to measure tail risk.
Starting capital
Defaults to the session's initial capital; you can override it for the run.

Reading the results

A run returns several views:

  • Percentile fan — the equity envelope over time at the 5th, 25th, 50th (median), 75th and 95th percentiles. The wider the fan, the more uncertain the outcome.
  • Sample paths — a handful of individual simulated curves, to feel the texture of the variation.
  • Final value distribution — a histogram of where equity ends up at the horizon (worst-case → typical → best-case).
  • Max drawdown distribution — a histogram of the deepest drawdown reached on each path. This is the one most traders underestimate.

Summary statistics

StatMeaning
Probability of ruinshare of paths that touch the ruin threshold at any point. In fixed-contract mode the barrier is absorbing, so this responds to your starting capital.
Prob. below capitalshare of scenarios that end below the starting capital — the plain "chance of losing money".
Median / P05 / P95 finaltypical and tail outcomes for final equity.
Max DD median / P95typical and bad-case worst drawdowns, shown in % of peak and in dollars.
Tail P/L 5% & 1% (VaR / CVaR)the final P/L in dollars at the 5th / 1st percentile (VaR) and the average P/L of that worst tail (CVaR). Negative = a loss; positive = even the tail is a gain (a profitable strategy at a long horizon). Computed on terminal dollars, so there is no "−1,129%" artefact from compounded returns.

Diagnostics

Each run also reports the fitted model internals — for FHS+GARCH that includes the persistence (α + β), the volatility half-life in days and the long-run volatility; for the t-models, the fitted degrees of freedom and skew; for bootstraps, the block length used. These let you sanity-check that the model captured your data.

It's still a model

Monte Carlo assumes the future resembles the resampled past. It widens your view of risk, but it cannot foresee regime changes the history never contained. Treat the ruin probability as a relative gauge across configurations, not a guarantee.

Performance

A million paths over a 1,260-day horizon is heavy but feasible; 1,000–10,000 simulations are plenty for interactive work, with 100,000+ reserved for final risk reports. Runs are offloaded to a worker thread so the UI stays responsive.

You can leave the tab while it runs

The simulation runs on the server as a background job: launching it returns immediately and the app polls for the result. You can switch tabs, open another app, or lock your phone — the run keeps going server-side and the result appears when you come back. The job is self-contained and saved, so it survives a page reload — and even a server restart: if the backend recycles mid-run, the next poll transparently re-runs it from the stored recipe.