American Pricer (NN)
CRR binomial tree distilled — handles early-exercise premium.
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.
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.
trained vs 500-step Cox-Ross-Rubinstein
Real American Pricer (NN) bot, running on real Yahoo data when the symbol is available. Drag the params — the bot re-runs instantly.
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.
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 },
};
},
},
);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.
- Copy the whole block above.
- On /quant, click + Import your bot in the bot library.
- Paste, hit save. It hot-loads into your workspace.
- Edit any param defaults or logic to your taste — it's now yours.
- ·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.
- ·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.
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.
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.
cd "ai quants" && uvicorn serve:app --reload --port 8000When should I exercise American puts early?+
Why no early-exercise boundary in the output?+
Neural Black-Scholes — price + 5 Greeks in one shot.
GBM Monte Carlo distilled into a network — instant pricing.
Stochastic-vol pricer — vol of vol, mean reversion, leverage.
Pure math option pricer with all the Greeks.
All AI quants vote. Tier emerges from agreement, not opinion.
Will the stock be up or down 20 days from now? GBM ensemble vote.