This document describes the equity-path Monte Carlo in @kiploks/engine-core: buildPathMonteCarloSimulation. It is not the same as wfaProfessional.monteCarloValidation (bootstrap over window-level OOS returns; see WFA_PROFESSIONAL.md §5).
Index: MONTE_CARLO_SIMULATION_IMPLEMENTATION.md.
Given a sequence of equity values (and optional timestamps), the engine:
- Builds period returns from consecutive points.
- Runs an i.i.d. bootstrap (resampling with replacement) of those returns to synthesize many synthetic paths.
- Compounds each path, then computes CAGR (
calculateCagrFromYears) and max drawdown per path (peak-to-trough on the compounded series; reported as negative decimals, e.g.-0.15for 15% drawdown). - Summarizes percentile bands, probability of positive CAGR, path stability and tail risk labels, plus interpretation bullets (including limits of i.i.d. bootstrap).
Use this block when you want a path-level view of uncertainty from a single realized equity curve, not a WFA window permutation test.
- Normalization: Equity points are sorted by
timestampwhen present; values must be strictly positive. Flat series (zero variance of returns) yieldsnull. - Horizon for CAGR: If all points have
timestamp, horizon in years follows first-to-last span. OtherwisehorizonYearsfrom options, orreturns.length / 252withmeta.approximationsUsednoting the trading-day convention. - PRNG: Always Mulberry32 via
createMulberry32inpackages/core/src/prng.ts. Ifoptions.seedis omitted,PATH_MONTE_CARLO_DEFAULT_SEEDis used and recorded inmeta.seedUsed. - CAGR horizon: Per-path CAGR uses
calculateCagrFromYears(start, end, horizonYears)so the horizon is explicit in years (not a fragile pair of synthetic Unix ms). - Ruined paths: Non-positive compounded equity records CAGR and MDD sample value
-1as sentinels (counted inruinousPathCount); they remain in percentile arrays when finite and lower tail metrics accordingly. - Period returns: When |lag-1 autocorrelation| > 0.15, a warning is appended to
meta.approximationsUsed.meta.periodReturnsAutocorrelationLag1andmeta.periodReturnsNeweyWestTStat(HAC t-stat for the mean return) are populated when finite. - Ruinous paths: Paths that hit non-positive balance are counted in
meta.ruinousPathCount; CAGR/MDD for those samples use sentinel values consistent withfinancialMath(see implementation). - Max drawdown in output: Stored as negative decimals (e.g.
-0.23for -23% peak-to-trough on each simulated path).
Contracts live in @kiploks/engine-contracts (pathMonteCarlo.ts). The equity input type is PathMonteCarloEquityPoint (value, optional timestamp). Options: PathMonteCarloOptions (simulations, seed, minPeriods, horizonYears, initialBalance, budget).
Return type: PathMonteCarloResult or null if the block is unavailable (too few periods, flat returns, etc.).
Constants are in packages/core/src/pathMonteCarloConstants.ts, including:
PATH_MONTE_CARLO_METHOD_VERSION(bump independently ofFORMULA_VERSIONper plan §7; 1.1.0 = audit alignment: CAGR years helper, inline MDD, Type-7-consistent CVaR, CF VaR optional, autocorrelation / Newey–West meta).- Simulation bounds, default
minPeriods,budget→ simulation count mapping. - Labels for
pathStability,tailRisk, and viable path definition (VIABLE_MDD_THRESHOLD_DECIMAL).
Percentiles use Hyndman–Fan type 7 (percentileType7 in percentile.ts), recorded as meta.percentileMethod: "type7".
| Limitation | Note |
|---|---|
| i.i.d. bootstrap | Ignores serial correlation; block bootstrap is future work. |
| No regime model | Complement with WFA OOS and professional diagnostics where relevant. |
| 252-day horizon when timestamps missing | See meta.approximationsUsed. |
null for short/flat curves |
Valid "unavailable" outcome; do not treat as engine error. |
| No benchmark / alpha | Out of scope for v1. |
- Pass an explicit
seedfor deterministic multi-run output in tests and audits. - Golden fixture:
examples/monte-carlo-seed42.json. Regenerate withnpm run engine:examples:generate-monte-carlo-fixture(afternpm run build). Any intentional output change should bumpPATH_MONTE_CARLO_METHOD_VERSIONand CHANGELOG.
Use budget: 'fast' | 'standard' | 'thorough' when you do not set simulations explicitly (maps to 1k / 10k / 50k paths, capped by pathMonteCarloConstants.ts). Browser embedders should prefer 'fast' if latency matters.
- Efron, B. (1979). Bootstrap Methods: Another Look at the Jackknife. Annals of Statistics.
- Basel framework: expected shortfall (CVaR) motivation aligns with tail summaries in
DistributionStats(engine uses sample CVaR at 95% in stats objects; primary user-facing tail framing is still percentile bands and labels).