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 • 4.61 kB
TypeScript
/**
* # session/clock — the session calendar (ET wall-clock ⇆ epoch-ms, dynamic tau)
*
* Pure calendar arithmetic over the IANA `America/New_York` zone (the US options session's
* clock). **No wall clock is read** — every function is a deterministic function of an injected
* epoch-ms instant and/or the session date, so replay is byte-stable (RUNTIME §0). The tz
* database (EST/EDT transitions) is supplied by the runtime's ICU; a given (date, instant) maps
* to the same wall time on every machine.
*
* Three jobs:
* - {@link etMinuteOfDay} — minutes-since-ET-midnight for an instant (0..1439). Drives the
* `time HH:MM` trigger window and the absolute `ttl 16:00` deadline (RUNTIME §5, provider
* hook `timeOfDayMinutes`).
* - {@link etWallClockMs} — the epoch-ms that reads as a given ET wall time on a session date
* (e.g. 16:00 ET on `2026-07-10` = the settle instant).
* - {@link expiryTauYears} — the per-event time-to-expiry in YEARS, `max(0, (16:00 ET on the
* CONTRACT's expiry date − now)) / year` — the injection `@fair` (and the maker-fair hazard)
* decays from, instead of a static `--tau-hours` constant (RUNTIME §4).
*
* ## τ is EXPIRY-driven, never session-driven (kestrel-wcnd)
* The predecessor (`dynamicTauYears(sessionDate)`) pinned the expiry instant to 16:00 ET **on the
* session date** and never received the contract's expiry at all — a baked-in 0DTE identity
* (`session_date == expiry`). On a multi-day (swing) tape that computes time-to-CLOSE, not
* time-to-EXPIRY: on the 4-calendar-day SPY tape it returns ≈6.5h/8760h ≈ 0.00074 yr where the
* truth is ≈4.27/365 ≈ 0.0117 yr — **~16× too small**, collapsing every OTM `@fair` toward zero.
* {@link expiryTauYears} therefore takes the per-book `expiry` and derives the settle instant from
* IT. The session date survives for exactly ONE job: resolving the relative `0dte` tag (the only
* tag resolvable without a trading calendar).
*
* **Fail closed** (RUNTIME §8): an absent, unparseable, or unresolvable-tag expiry returns `null`
* — `@fair` is then unbuildable ⇒ UNKNOWN ⇒ the caller de-arms with a logged reason. It NEVER
* silently assumes same-day expiry; that unchecked assumption is the bug this replaced.
*/
declare const MS_PER_MINUTE = 60000;
/** Hours in a (365-day) year — matches `src/fair`'s `MS_PER_YEAR` convention exactly. */
declare const MS_PER_YEAR: number;
/** Minutes since ET midnight for `nowMs` (0..1439) — the `timeOfDayMinutes` provider hook. */
export declare function etMinuteOfDay(nowMs: number): number;
/**
* The epoch-ms that reads as `hour:minute` ET on `sessionDate` (`YYYY-MM-DD`). One offset
* correction suffices for session-hour times — the EST/EDT transition is at 02:00 local, far
* from any trading-session wall time, so the offset at the naïve guess equals the true offset.
*/
export declare function etWallClockMs(sessionDate: string, hour: number, minute: number): number;
/**
* The per-event time-to-expiry provider (τ, in YEARS): `(now, expiry) => max(0, (16:00 ET on the
* CONTRACT expiry − now)) / year`, or **`null`** when `expiry` names no resolvable date.
*
* `expiry` is the per-book token (`BookEvent`/`BookState` `expiry` — an ISO date or the `0dte`
* tag), threaded from the SAME book the surface is built from, so a multi-day contract prices on
* its own tenor. Pure in `(now, expiry)` (RUNTIME §0): the only clock read is the injected `now`
* (the tape's), and `etWallClockMs` is pure calendar arithmetic — replay stays byte-stable.
*
* `sessionDate` is bound ONCE and used for exactly one thing: resolving the `0dte` tag. On a 0DTE
* tape this returns `max(0, (16:00 ET on session_date − now))/year` — bit-for-bit what the
* predecessor `dynamicTauYears(sessionDate)` returned, so 0DTE goldens do not move.
*/
export declare function expiryTauYears(sessionDate: string): FairTauProvider;
/**
* The τ-provider seam every `@fair` caller injects (RUNTIME §4). `now` is the tape instant being
* priced; `expiry` is the valued contract's own expiry token. Returns `null` when τ is unknowable
* — the caller MUST then treat `@fair` as unbuildable and fail closed, never substitute a default.
*
* The CLI's `--tau-hours` override is simply a provider that ignores both arguments and returns
* its constant — an explicit operator assertion of the tenor, which is why it is allowed to.
*/
export type FairTauProvider = (now: number, expiry?: string) => number | null;
export { MS_PER_MINUTE, MS_PER_YEAR };
//# sourceMappingURL=clock.d.ts.map