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 4.61 kB
/** * # 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