UNPKG

kestrel.markets

Version:

A typed, token-efficient language + runtime for agentic trading: agents author bounded plans, the runtime fires them at the tick. CLI + typed library + MCP server.

110 lines 6.13 kB
/** * # fair/black76 — the option-pricing math core (r = 0) * * ExecutionFair is built on Black-76: options priced off the **forward**, discounted at the * risk-free rate. Kestrel runs the whole surface at **r = 0** — short-dated index and * equity options carry no meaningful carry over the horizons that matter, and a zero rate * makes the forward equal spot, keeps put-call parity exactly `C - P = F - K`, and removes a * calibration knob nobody would trust anyway. (ARCHITECTURE §4: "underlying-anchored * intrinsic + a vol read backed out of the *liquid* quotes, floored at intrinsic.") * * Everything here is a **pure function** — no I/O, no clock, no RNG (RUNTIME §0). Time is a * parameter (`tauYears`), never read from a wall clock. * * ## Contract * - `black76` prices a call/put; `tauYears <= 0` **or** `sigma <= 0` collapse to the forward * intrinsic (no time value to add). The price is always `>= intrinsic`. * - `impliedVol` back-outs the volatility that reprices a given premium by bisection, and * returns `null` when there is **no positive-vol solution** (premium at/below intrinsic) or * the premium is **unreachably rich** (>= the asymptote: `forward` for a call, `strike` for * a put — the sigma→∞ limits at r = 0). * - `intrinsic` and `tauYearsToClose` are the small shared helpers callers reuse. */ import type { Right } from "../bus/types.ts"; /** Calendar-year basis for `tauYearsToClose` (365d × 24h × 60m × 60s × 1000ms). */ export declare const MS_PER_YEAR: number; /** * Error function, implemented **odd by construction** (`erf(-x) = -erf(x)`) so that * `normCdf(x) + normCdf(-x) === 1` exactly — which is what makes put-call parity hold to * floating-point rounding. Abramowitz & Stegun 7.1.26 on the magnitude (|error| ≲ 1.5e-7), * mirrored through the sign. The exponential is the vendored {@link dexp}, not `Math.exp`, so * this stays bit-identical across V8/JSC on the certified-grade path (see {@link ./detmath.ts}). */ export declare function erf(x: number): number; /** Standard-normal CDF. `normCdf(x) + normCdf(-x) === 1` exactly (see {@link erf}). */ export declare function normCdf(x: number): number; /** Standard-normal PDF `φ(x) = e^(−x²/2) / √(2π)`. Uses the vendored {@link dexp} so gamma/vega * stay bit-identical across V8/JSC on the certified-grade path (see {@link ./detmath.ts}). */ export declare function normPdf(x: number): number; /** * The two spot-greeks the options-analytics MODEL panes need (delta + gamma), plus vega, at r = 0 * (forward = spot). All are **model outputs** — computed, never observed — so every consumer that * renders one must carry the Black-Scholes receipt (see {@link ../frame/options-analytics.ts}). * - `delta` — call `N(d1)`, put `N(d1) − 1` (∈ [−1, 1]). * - `gamma` — `φ(d1) / (F σ √τ)` (per $1 of underlier; ≥ 0, peaks at-the-money, blows up as τ→0). * - `vega` — `F φ(d1) √τ` (per 1.00 = 100 vol-points; ≥ 0). * - `theta` — `−F φ(d1) σ / (2√τ)` (per YEAR of calendar time; the time-decay bleed). At r = 0 the * rate/carry terms vanish, so theta is IDENTICAL for a call and a put and is `≤ 0` for a long * option (holding it loses value as τ shrinks) — the θ the theta-bleed percept pane renders. */ export interface Greeks { readonly delta: number; readonly gamma: number; readonly vega: number; readonly theta: number; } /** * The Black-76 greeks at r = 0. A degenerate leg (`τ ≤ 0`, `σ ≤ 0`, or a non-positive forward/ * strike) has NO time value: gamma/vega/theta collapse to 0 and delta is the moneyness step (a call * is 0/1, a put 0/−1 across the strike). Pure — a total function of its parameters. */ export declare function greeks(p: Black76Params): Greeks; /** * Intrinsic value of an option at `spot` — the payoff if it settled now. Call = `max(spot - * strike, 0)`, put = `max(strike - spot, 0)`. At r = 0 the forward equals spot, so this is * also the forward intrinsic that {@link black76} floors at. Never negative. */ export declare function intrinsic(spot: number, strike: number, right: Right): number; /** Parameters for a single Black-76 valuation (r = 0, so `forward` is the spot/forward). */ export interface Black76Params { readonly forward: number; readonly strike: number; readonly tauYears: number; readonly sigma: number; readonly right: Right; } /** * Black-76 price at r = 0. `tauYears <= 0` or `sigma <= 0` ⇒ intrinsic exactly (no time value * to add). Strictly increasing in `sigma` (positive vega), so it is invertible by bisection. * The result is always `>= intrinsic(forward, strike, right)`. */ export declare function black76(p: Black76Params): number; /** Parameters for an implied-vol back-out. `price` is the premium to invert (typically a * two-sided mid). */ export interface ImpliedVolParams { readonly forward: number; readonly strike: number; readonly tauYears: number; readonly price: number; readonly right: Right; } /** * Back out the Black-76 volatility that reprices `price`, by bisection. * * Returns `null` when there is no positive-vol solution: * - `price` is not a finite positive number, or `tauYears <= 0` (no time value to carry vol); * - `price <= intrinsic` (the sigma→0 limit — nothing to back out); * - `price >= asymptote` (`forward` for a call, `strike` for a put — the sigma→∞ limit at * r = 0): an **unreachably-rich** mid. * * Otherwise a unique sigma exists in the open interval and bisection converges to it (the * inverse is exact against {@link black76}, so a round-trip recovers the input sigma). */ export declare function impliedVol(p: ImpliedVolParams): number | null; /** * Year-fraction from `nowTs` to the session `closeTs`, both epoch-ms (injected — never a wall * clock, RUNTIME §0), on a 365-day calendar basis. Past the close the value is `<= 0`, which * {@link black76} treats as intrinsic. */ export declare function tauYearsToClose(nowTs: number, closeTs: number): number; //# sourceMappingURL=black76.d.ts.map