LIVE·
fetching live quotes from Yahoo Finance…
--:--:--UTC
Learn/Bots/Heston SV Pricer (NN)
AI QuantsAIid · ai-heston
Ψ

Heston SV Pricer (NN)

Stochastic-vol pricer — vol of vol, mean reversion, leverage.

▶ Try it now↗ Browse all 27srcai quants/models/heston/train.pyapi/api/heston
In plain English

Real markets don't have one fixed volatility — vol moves around too. Heston is the gold-standard model that simulates that, including the negative correlation that makes puts more expensive than calls. We trained an AI to price it instantly.

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

Real markets don't have a single fixed volatility — vol moves around too. Heston is the gold-standard model that simulates that, including the negative correlation that makes puts more expensive than calls (the famous skew). The bot trained on fypy library ground truth, neural-net distilled.

The math
formula
trained on fypy Heston ground truth
parameters
typeTypechoices: C, Pdefault · C
spotSpot $range — → —default · 100
strikeStrike $range — → —default · 100
daysDays to expiryrange — → —default · 60
rateRate %range — → —default · 4.5
v0v₀ (initial var)range 0.001 → 0.5default · 0.04
kappaκ (mean rev speed)range 0.1 → 10default · 2
thetaθ (long-run var)range 0.001 → 0.5default · 0.04
xiξ (vol of vol)range 0.05 → 2default · 0.5
rhoρ (S↔v corr)range -1 → 1default · -0.7
Live demo

Real Heston SV Pricer (NN) 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/ai-bots.ts·lines 466562
TypeScript · MIT-licensed
const hestonSurrogate: BotDef = aiBot<HestonReq, BSRes>(
  {
    id: "ai-heston",
    name: "Heston SV Pricer (NN)",
    category: "ai",
    glyph: "Ψ",
    tagline: "Stochastic-vol pricer — vol of vol, mean reversion, leverage.",
    formula: "trained on fypy Heston ground truth",
    endpoint: "/api/heston",
    module: "ai quants/models/heston/train.py",
    params: [
      { key: "type", label: "Type", kind: "select", default: "C", options: [{ value: "C", label: "Call" }, { value: "P", label: "Put" }] },
      { key: "spot", label: "Spot $", kind: "number", default: 100, step: 0.5 },
      { key: "strike", label: "Strike $", kind: "number", default: 100, step: 0.5 },
      { key: "days", label: "Days to expiry", kind: "number", default: 60, step: 1 },
      { key: "rate", label: "Rate %", kind: "number", default: 4.5, step: 0.1 },
      { key: "v0", label: "v₀ (initial var)", kind: "number", default: 0.04, min: 0.001, max: 0.5, step: 0.005 },
      { key: "kappa", label: "κ (mean rev speed)", kind: "number", default: 2.0, min: 0.1, max: 10, step: 0.1 },
      { key: "theta", label: "θ (long-run var)", kind: "number", default: 0.04, min: 0.001, max: 0.5, step: 0.005 },
      { key: "xi", label: "ξ (vol of vol)", kind: "number", default: 0.5, min: 0.05, max: 2, step: 0.05 },
      { key: "rho", label: "ρ (S↔v corr)", kind: "number", default: -0.7, min: -1, max: 1, step: 0.05 },
    ],
  },
  {
    request: (ctx, p) => {
      const lastPx = ctx.candles[ctx.candles.length - 1]?.c ?? 100;
      const type = (str(p, "type", "C") === "P" ? "p" : "c") as "c" | "p";
      return {
        S: num(p, "spot", lastPx),
        K: num(p, "strike", Math.round(lastPx)),
        T: Math.max(0.0005, num(p, "days", 60) / 365),
        r: num(p, "rate", 4.5) / 100,
        v0: num(p, "v0", 0.04),
        kappa: num(p, "kappa", 2.0),
        theta: num(p, "theta", 0.04),
        xi: num(p, "xi", 0.5),
        rho: num(p, "rho", -0.7),
        flag: type,
      };
    },
    build: (data, ctx, p) => {
      const lastPx = ctx.candles[ctx.candles.length - 1]?.c ?? 100;
      const type = (str(p, "type", "C") === "P" ? "P" : "C") as "C" | "P";
      const spot = num(p, "spot", lastPx);
      const strike = num(p, "strike", Math.round(lastPx));
      const days = num(p, "days", 60);
      const rate = num(p, "rate", 4.5) / 100;
      const rho = num(p, "rho", -0.7);
      const v0 = num(p, "v0", 0.04);
      const t = days / 365;
      const sigEff = Math.sqrt(v0);
      const bs = priceOption(spot, strike, t, rate, sigEff, type).price;
      const skew = data.price - bs;
      return {
        signals: [],
        metrics: [
          { key: "px", label: "Heston $", value: `$${data.price.toFixed(2)}`, tone: "info" },
          { key: "bs", label: "BS comparable", value: `$${bs.toFixed(2)}` },
          { key: "skew", label: "Skew premium", value: `${skew >= 0 ? "+" : ""}$${skew.toFixed(2)}`, tone: skew < 0 ? "bear" : "bull" },
          { key: "vol", label: "v₀ vol-equiv", value: `${(sigEff * 100).toFixed(1)}%` },
        ],
        summary: `Heston says $${data.price.toFixed(2)} — ${skew >= 0 ? "above" : "below"} BS because ρ = ${rho.toFixed(2)} pulls implied skew the way real markets price it.`,
        beginner:
          "Real markets don't have a single fixed volatility. Heston is the gold-standard model that simulates that, including the negative correlation that makes puts more expensive than calls.",
        verdict: { side: "hold", text: `Heston fair value $${data.price.toFixed(2)}.`, confidence: 1 },
      };
    },
    mock: (ctx, p) => {
      const lastPx = ctx.candles[ctx.candles.length - 1]?.c ?? 100;
      const type = (str(p, "type", "C") === "P" ? "P" : "C") as "C" | "P";
      const spot = num(p, "spot", lastPx);
      const strike = num(p, "strike", Math.round(lastPx));
      const days = num(p, "days", 60);
      const rate = num(p, "rate", 4.5) / 100;
      const v0 = num(p, "v0", 0.04);
      const xi = num(p, "xi", 0.5);
      const rho = num(p, "rho", -0.7);
      const t = days / 365;
      const sigEff = Math.sqrt(v0) * (1 + 0.3 * xi * t);
      const bs = priceOption(spot, strike, t, rate, sigEff, type).price;
      const skewBump = rho < 0 && type === "P" ? bs * 0.08 * Math.abs(rho) : rho > 0 && type === "C" ? bs * 0.05 * rho : 0;
      const heston = bs + skewBump;
      return {
        signals: [],
        metrics: [
          { key: "px", label: "Heston $", value: `$${heston.toFixed(2)}`, tone: "info" },
          { key: "bs", label: "BS comparable", value: `$${bs.toFixed(2)}` },
          { key: "skew", label: "Skew premium", value: `+$${skewBump.toFixed(2)}`, tone: rho < 0 ? "bear" : "bull" },
          { key: "vol", label: "Effective vol", value: `${(sigEff * 100).toFixed(1)}%` },
        ],
        summary: `Heston says $${heston.toFixed(2)} (TS approximation).`,
        beginner: "Real markets don't have a single fixed volatility — Heston simulates that.",
        verdict: { side: "hold", text: `Heston fair value $${heston.toFixed(2)}.`, confidence: 1 },
      };
    },
  },
);
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
  • ·Modelling skew. BS assumes flat IV across strikes; reality has a smile and a smirk. Heston captures it.
  • ·Long-dated options where stochastic vol matters most.
  • ·Calibrating to a vol surface. Run Heston across the chain, fit (κ, θ, ξ, ρ, v₀) to observed prices.
✗ Fails when
  • ·Inputs outside training distribution. Heston's parameter space is wide; the surrogate only saw a slice.
  • ·Short-dated, near-the-money options. BS is essentially correct there; Heston's edge is at the extremes.
  • ·Calibration is hard. The bot prices Heston given parameters — it doesn't fit parameters to a market chain. That's a separate optimisation.
How to read its verdict

HOLD always. The 'skew premium' (Heston − BS) is the interesting output. Negative ρ + put = bigger Heston premium = real market behaviour. Tells you how much skew is worth in dollar terms for these inputs.

Python service

This bot tries to call the FastAPI service first. When it's up, you get real model output. When it's down, the bot transparently falls back to a deterministic TS surrogate.

FastAPI·http://localhost:8000·/api/hestonCHECKING…
data flow
01
BotCell.run()
User clicks Run on this bot in /quant
02
callApi()
POST to localhost:8000/api/heston
03
load_surrogate()
ai quants/models/heston/train.py
04
predict()
Forward pass on the inputs you provided
05
BotResult
JSON returned, card flips green Source: Python NN
spin it upcd "ai quants" && uvicorn serve:app --reload --port 8000
FAQ
What do κ, θ, ξ, ρ, v₀ mean?+
v₀: current variance. θ: long-run variance the system reverts to. κ: speed of reversion. ξ: vol of vol (how jumpy the variance itself is). ρ: correlation between stock and variance — typically negative because stocks and vol move opposite.
How do I calibrate Heston for a specific stock?+
Outside the bot's scope. Standard practice: take observed option prices across strikes/expiries, run a least-squares fit on the 5 Heston parameters, plug calibrated params back into the bot for any new strike/expiry. We don't ship the calibration step yet.