LIVE·
fetching live quotes from Yahoo Finance…
--:--:--UTC
Learn/Bots/American Pricer (NN)
AI QuantsAIid · ai-american
🇺🇸

American Pricer (NN)

CRR binomial tree distilled — handles early-exercise premium.

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

American options can be cashed in any time before expiry. That extra freedom is worth a tiny bit more than European-style options (cashed only at expiry). The AI learned exactly how much.

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

American options can be exercised any time before expiry. That extra freedom is worth a tiny bit more than a European-style option (which can only be cashed at expiry). The bot priced a 500-step Cox-Ross-Rubinstein binomial tree as ground truth, then distilled the answer into a neural network. ~0.5% relative error.

The math
formula
trained vs 500-step Cox-Ross-Rubinstein
parameters
typeTypechoices: C, Pdefault · P
spotSpot $range — → —default · 100
strikeStrike $range — → —default · 100
daysDays to expiryrange — → —default · 60
ivIV %range — → —default · 32
rateRate %range — → —default · 4.5
Live demo

Real American 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 393458
TypeScript · MIT-licensed
const americanSurrogate: BotDef = aiBot<BSReq, BSRes>(
  {
    id: "ai-american",
    name: "American Pricer (NN)",
    category: "ai",
    glyph: "🇺🇸",
    tagline: "CRR binomial tree distilled — handles early-exercise premium.",
    formula: "trained vs 500-step Cox-Ross-Rubinstein",
    endpoint: "/api/american",
    module: "ai quants/models/american/train.py",
    params: [
      { key: "type", label: "Type", kind: "select", default: "P", 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: "iv", label: "IV %", kind: "number", default: 32, step: 0.5 },
      { key: "rate", label: "Rate %", kind: "number", default: 4.5, step: 0.1 },
    ],
  },
  {
    request: (ctx, p) => bsRequest(ctx, p, 60),
    build: (data, ctx, p) => {
      const req = bsRequest(ctx, p, 60);
      const euro = priceOption(req.S, req.K, req.T, req.r, req.sigma, req.flag === "p" ? "P" : "C").price;
      const premium = Math.max(0, data.price - euro);
      return {
        signals: [],
        metrics: [
          { key: "amer", label: "American", value: `$${data.price.toFixed(2)}`, tone: "info" },
          { key: "euro", label: "European", value: `$${euro.toFixed(2)}` },
          { key: "exer", label: "Early-exercise $", value: `+$${premium.toFixed(2)}`, tone: "bull" },
          { key: "err", label: "Surrogate err", value: "≈0.5%", tone: "info" },
        ],
        summary: `American premium = European $${euro.toFixed(2)} + $${premium.toFixed(2)} early-exercise value.`,
        beginner:
          "American options can be cashed in any time before expiry. That extra freedom is worth a tiny bit more than a European-style option.",
        verdict: { side: "hold", text: `Fair American premium $${data.price.toFixed(2)}.`, confidence: 1 },
      };
    },
    mock: (ctx, p) => {
      const lastPx = ctx.candles[ctx.candles.length - 1]?.c ?? 100;
      const type = (str(p, "type", "P") === "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 iv = num(p, "iv", 32) / 100;
      const rate = num(p, "rate", 4.5) / 100;
      const t = Math.max(0.0005, days / 365);
      const euro = priceOption(spot, strike, t, rate, iv, type).price;
      const premium = type === "P" ? Math.max(0, rate * t * strike * 0.45 + iv * 0.05) : Math.max(0, rate * t * 0.04);
      const american = euro + premium;
      return {
        signals: [],
        metrics: [
          { key: "amer", label: "American", value: `$${american.toFixed(2)}`, tone: "info" },
          { key: "euro", label: "European", value: `$${euro.toFixed(2)}` },
          { key: "exer", label: "Early-exercise $", value: `+$${premium.toFixed(2)}`, tone: "bull" },
          { key: "err", label: "Surrogate err", value: "≈0.5%", tone: "info" },
        ],
        summary: `American premium = European $${euro.toFixed(2)} + $${premium.toFixed(2)} early-exercise value.`,
        beginner: "American options can be cashed in any time before expiry.",
        verdict: { side: "hold", text: `Fair American premium $${american.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
  • ·Single-name US equity options. Most of the listed market is American-style; this is the right pricer.
  • ·Dividend-paying stocks. Early-exercise premium grows with dividends; the model learns that relationship.
  • ·Comparing chain quotes against fair value. Like the BS surrogate, but accurate for American-style.
✗ Fails when
  • ·Index options (SPX, NDX). Those are European-style; use BS Surrogate instead.
  • ·Bermudan and other exotic exercise schedules. The model learned American-style only.
  • ·Extreme rates or dividends outside training distribution.
How to read its verdict

HOLD always. The published premium (American − European) tells you whether early exercise is worth anything for these specific inputs. If premium > 5% of European price, the early-exercise feature is materially valuable.

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/americanCHECKING…
data flow
01
BotCell.run()
User clicks Run on this bot in /quant
02
callApi()
POST to localhost:8000/api/american
03
load_surrogate()
ai quants/models/american/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
When should I exercise American puts early?+
Roughly: when the option is deep ITM and the interest you'd earn on the strike (if exercised and parked in cash) exceeds the time value remaining. The bot doesn't tell you when to exercise — just what the option is worth to someone who has the right.
Why no early-exercise boundary in the output?+
Because we distilled the price, not the policy. The CRR tree implicitly contains the optimal exercise boundary; we trained the NN to mimic the resulting price. If you need the boundary itself, you'd train a separate model on it.