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.

47 lines (46 loc) 2.75 kB
/** * # fair/spot — `@fair` for a spot instrument (equity/crypto), ADR-0017 * * ExecutionFair-B76 (`./index.ts`) is underlying-anchored Black-76 backed out of an option * chain, floored at intrinsic — meaningless for a plain equity or coin: there is no chain to * read a vol out of and no strike to take an intrinsic of. For a **spot instrument** the honest * fill-reference is simply its own **two-sided quote mid**: `(bid + ask) / 2`, carrying a receipt * under the distinct model tag {@link EXEC_FAIR_QUOTE_MODEL} (EVs across tags do not compare). * * Note the deliberate contrast with the options doctrine, where *mid is never a fair-value source* * (ARCHITECTURE §4): there, the observed option mid is a health signal off a possibly-fictional * book. For a spot instrument there is no chain and no maker model between the quote and the fill — * the NBBO mid **is** the honest reference, and it is receipt-gated (the bid/ask it was built from * ride the receipt) exactly so a downstream consumer can see what it rested on. * * Fail-closed (RUNTIME §4/§8): a **one-sided or dark** quote (`bid`/`ask` `null`), a non-finite * side, or a crossed book (`ask < bid`) is **not** a fair — the function returns `null` and the * price resolver falls back to an explicit `@bid`/`@ask`/`@mid`/`@last` (a silent mid is * forbidden). This module is **pure** — no I/O, no clock, no RNG (RUNTIME §0); the caller injects * `asof` and any staleness gate is applied downstream (the receipt only makes `asof` observable). */ /** The versioned model tag stamped on every spot-fair receipt — distinct from the options * `exec-fair-b76-v1`, so a grade never compares a quote-mid fair against a Black-76 fair. */ export const EXEC_FAIR_QUOTE_MODEL = "exec-fair-quote-v1"; /** * Resolve `@fair` for one spot instrument. * * Returns `{ value, receipt }` with `value = (bid + ask) / 2` when the quote is genuinely * two-sided; returns **`null`** — the fail-closed "unbuildable fair" signal the caller handles * with an annotated `@bid`/`@ask`/`@mid` fallback — when either side is dark (`null`), a side is * non-finite, or the book is crossed (`ask < bid`). Never Black-76, never a silent mid. */ export function executionFairSpot(input) { const { bid, ask, asof } = input; if (bid === null || ask === null) return null; // one-sided / dark ⇒ no fair (fail-closed) if (!Number.isFinite(bid) || !Number.isFinite(ask)) return null; // degenerate side if (ask < bid) return null; // crossed book ⇒ not a valuation const value = (bid + ask) / 2; return { value, receipt: { model: EXEC_FAIR_QUOTE_MODEL, bid, ask, ...(asof !== undefined ? { asof } : {}) }, }; }