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.

69 lines (68 loc) 4.2 kB
/** * # session/vehicle-health — the cockpit routing gate's per-vehicle liquidity read * * A vehicle's book at a wake vantage → its {@link VehicleHealth} fingerprint (the MM-pull signal the * acting agent routes on). Extracted from the Simulate driver ({@link import("./simulate.ts")}) so the * projection lives beside its own small, testable interface: the driver freezes market time, hands each * exec vehicle's book in ({@link VehicleBook}), and reads back the date-blind health line the enriched * cockpit kernel renders. * * PURE + injected-time: no wall clock, no RNG. `staleS` is a RELATIVE seconds count (`nowTs − asof_ts`), * never an absolute time, so the same book + same vantage projects a byte-identical health line — the * determinism the tracer's replay rides on. FAIL-CLOSED: a dark / one-sided / crossed book projects no * liquidity (never fabricated), and an equity instrument with no chain book sources its NBBO from the * SAME spot quote the fill floor executes against ({@link vehicleBookFromSpot}), so HEALTH and PRICING * can never disagree. */ /** Project one vehicle's book into its cockpit {@link VehicleHealth} (the routing gate). A vehicle * with no observed book is DARK-and-named (never blank); otherwise the MM-pull fingerprint is the * bid-present rate + two-sidedness, and `staleS` is a RELATIVE duration (a date-blind seconds count, * `nowTs − asof_ts`), never an absolute time. Pure. */ export function vehicleHealthOf(v, nowTs) { const book = v.book; if (book === undefined || book.legs.length === 0) { return { instrument: v.instrument, bidPresentRate: 0, twoSided: false, staleS: 0, dark: true }; } const legs = book.legs; const bidCount = legs.reduce((n, l) => n + (l.bid !== null ? 1 : 0), 0); return { instrument: v.instrument, bidPresentRate: bidCount / legs.length, twoSided: legs.every((l) => l.bid !== null && l.ask !== null), staleS: Math.max(0, (nowTs - book.asof_ts) / 1000), dark: bidCount === 0, }; } /** Source an exec vehicle's health book, closing the equity false-dark gap (kestrel-710). `core.books` * only ever holds the OPTION-CHAIN book; a plain EQUITY instrument has no chain book, so its * {@link VehicleBook} would be `book:undefined` ⇒ {@link vehicleHealthOf} hard-returns DARK even while * the SPOT NBBO the fill floor + `exec-fair-quote-v1` execute against is genuinely two-sided. * * When a real option book exists it is passed through untouched (the options path is byte-identical). * Otherwise, when `core.spotFill.currentQuote(instrument)` reports a live NBBO, project a synthetic * ONE-LEG book from it so HEALTH and PRICING read the SAME source. **Fail-closed**, using the exact * predicate of {@link import("../fair/index.ts").executionFairSpot}: an absent, one-sided (a `null` * side), non-finite, or crossed (`ask < bid`) quote projects NO book ⇒ the vehicle stays DARK — never * fabricate liquidity. Only a genuine two-sided uncrossed quote reports live. Pure + injected-time: * `asof_ts` is the quote's own event ts (so `staleS = nowTs − asof_ts`), never a wall clock. */ export function vehicleBookFromSpot(instrument, optionBook, spot) { if (optionBook !== undefined) return { instrument, book: optionBook }; if (spot === undefined) return { instrument, book: undefined }; const { bid, ask } = spot.quote; // Parity with executionFairSpot (ADR-0017): one-sided / non-finite / crossed ⇒ no live leg (dark). if (bid === null || ask === null) return { instrument, book: undefined }; if (!Number.isFinite(bid) || !Number.isFinite(ask)) return { instrument, book: undefined }; if (ask < bid) return { instrument, book: undefined }; const leg = { strike: 0, right: "C", bid, ask, bsz: null, asz: null }; return { instrument, // asof_seq is unused by vehicleHealthOf and this synthetic book never enters the real book map; // -1 marks it as SPOT-sourced, not folded from a BOOK event. book: { instrument, underlier_px: (bid + ask) / 2, legs: [leg], asof_seq: -1, asof_ts: spot.ts }, }; }