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
JavaScript
/**
* # 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 },
};
}