LIVE·
fetching live quotes from Yahoo Finance…
--:--:--UTC
Learn/Bots/Monte Carlo VaR
Risk & Sizingid · mc-var
Σ

Monte Carlo VaR

Worst loss you'd expect 95% of the time.

In plain English

Run thousands of simulated 'next 10 days' for the stock. The 5th-worst outcome out of 100 is your Value-at-Risk — the bad day you should plan to survive. Helps you size positions so a normal bad day doesn't blow up your account.

No jargon. Just what this bot does.
The longer version

Run thousands of simulated 'next 10 days'. The 5th-worst outcome out of 100 is your Value-at-Risk — the bad day you should plan to survive. CVaR is the average of the days worse than that. The most rigorous way to translate 'how risky is this position' into a dollar number.

The math
formula
VaR = quantile of simulated horizon returns
parameters
simsSimulationsrange 1000 → 20000default · 4000
horizonHorizon (days)range 1 → 90default · 10
confidenceConfidence %range 90 → 99default · 95
notionalNotional $range 1000 → 10000000default · 100000
Live demo

Real Monte Carlo VaR bot, running on real Yahoo data when the symbol is available. Drag the params — the bot re-runs instantly.

symbolloading…
loading AMZN bars…
Source code · public

This is the actual code the bot runs — not a re-explanation, not a simplified version. Whatever ships here is what executes when you press Run All in the workbench. Read it, copy it, fork it, build a better one.

lib/quant/bots.ts·lines 640692
TypeScript · MIT-licensed
const varBot: BotDef = {
  id: "mc-var",
  name: "Monte Carlo VaR",
  category: "risk",
  glyph: "Σ",
  tagline: "Worst loss you'd expect 95% of the time.",
  formula: "VaR = quantile of simulated horizon returns",
  params: [
    { key: "sims", label: "Simulations", kind: "number", default: 4000, min: 1000, max: 20000, step: 500 },
    { key: "horizon", label: "Horizon (days)", kind: "number", default: 10, min: 1, max: 90, step: 1 },
    { key: "confidence", label: "Confidence %", kind: "number", default: 95, min: 90, max: 99, step: 0.5 },
    { key: "notional", label: "Notional $", kind: "number", default: 100000, min: 1000, max: 10000000, step: 1000 },
  ],
  run: (ctx, p): BotResult => {
    const sims = Math.round(num(p, "sims", 4000));
    const horizon = Math.round(num(p, "horizon", 10));
    const conf = num(p, "confidence", 95) / 100;
    const notional = num(p, "notional", 100000);
    const px = closes(ctx.candles);
    const rets = returns(px);
    const mean = rets.reduce((a, b) => a + b, 0) / Math.max(1, rets.length);
    const sd = Math.sqrt(rets.reduce((a, b) => a + (b - mean) ** 2, 0) / Math.max(1, rets.length - 1));
    const norm = makeNorm(31);
    const finals: number[] = [];
    for (let i = 0; i < sims; i++) {
      let r = 1;
      for (let d = 0; d < horizon; d++) r *= 1 + (mean + sd * norm());
      finals.push(r - 1);
    }
    finals.sort((a, b) => a - b);
    const idx = Math.floor((1 - conf) * sims);
    const varRet = finals[idx];
    const cvar = finals.slice(0, Math.max(1, idx)).reduce((a, b) => a + b, 0) / Math.max(1, idx);
    const expRet = finals.reduce((a, b) => a + b, 0) / sims;
    return {
      signals: [],
      metrics: [
        { key: "var", label: `VaR ${(conf * 100).toFixed(0)}%`, value: fmtMoney(varRet * notional), tone: "bear" },
        { key: "cvar", label: "CVaR (tail avg)", value: fmtMoney(cvar * notional), tone: "bear" },
        { key: "exp", label: `${horizon}d expected`, value: fmtMoney(expRet * notional), tone: expRet > 0 ? "bull" : "bear" },
        { key: "vol", label: "Daily vol", value: `${(sd * 100).toFixed(2)}%`, tone: "info" },
      ],
      summary: `${(conf * 100).toFixed(0)}% confident the ${horizon}-day loss won't exceed ${fmtMoney(varRet * notional)} on ${fmtMoney(notional)} notional.`,
      beginner:
        "Run thousands of simulated 'next 10 days'. The 5th-worst outcome out of 100 is your Value-at-Risk — the bad day you should plan to survive. CVaR is the average of the days worse than that.",
      verdict: {
        side: "warn",
        text: `Plan for losses up to ${fmtMoney(Math.abs(varRet * notional))} this ${horizon}-day window.`,
        confidence: 0.85,
      },
    };
  },
};
what each piece means
  • id — unique key the workbench uses to find the bot.
  • params — the sliders + inputs you see on the cell.
  • run(ctx, p) — the function that gets called with candles + your params and returns the verdict.
  • verdict — the BUY / SELL / HOLD pill at the top of the cell.
  • metrics — the small stat boxes shown in the cell body.
use this code yourself
  1. Copy the whole block above.
  2. On /quant, click + Import your bot in the bot library.
  3. Paste, hit save. It hot-loads into your workspace.
  4. Edit any param defaults or logic to your taste — it's now yours.
Specialty · when it shines, when it fails
✓ Shines when
  • ·Risk budgeting at the portfolio level. Aggregate VaR across positions for a single 95% number.
  • ·Margin sizing. Brokers margin you on rough VaR; computing your own gives you an early warning.
  • ·Sanity-check stop-losses. If your stop is tighter than 95% VaR, expect to be stopped out frequently by random drift.
✗ Fails when
  • ·Tail-risk underestimation. MC under GBM (which we use) misses fat-tails — real 99% VaR is worse than this simulation suggests.
  • ·Stationarity assumption. The bot uses recent realised vol; in regime shifts (2020 March), VaR was wrong by orders of magnitude before adapting.
  • ·Path-dependence. VaR ignores how the loss happened — slow drift to -10% vs gap to -10% have very different psychology.
How to read its verdict

Always WARN — VaR doesn't trade, it sizes risk. The headline number is 'plan for losses up to $X this 10-day window'. CVaR is shown alongside as the average of the bad-tail outcomes; that's what you actually lose when VaR breaches.

FAQ
What's the difference between VaR and CVaR?+
VaR(95%) = the 5th-percentile loss. So 'I will not lose more than this 95% of the time'. CVaR(95%) = the average loss across the worst 5% of cases. CVaR is always worse than VaR and is a better risk number for fat-tailed distributions.
Why GBM and not jumps?+
GBM is the textbook starting point and matches BS. Real markets have jumps; modelling them needs Merton jump-diffusion or similar. We could add it as a parameter — for now, treat the GBM VaR as a lower bound on actual risk.