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.

52 lines (51 loc) 3.1 kB
/** * # series/types — the value model of the series layer (RUNTIME §2–§3) * * Two small, load-bearing types and the units bridge shared by every file in this module. * * - {@link UNKNOWN} — the single sentinel for "insufficient data / unresolvable". It is a * value, distinct from `false`: a series with too little history reads UNKNOWN, never a * guess (RUNTIME §2), and a trigger over an UNKNOWN operand evaluates UNKNOWN, never * silently false (RUNTIME §3). Only a definite `true` fires. * - {@link Resolved} — what a series resolves to: a `number` (a market/org scalar), a * `string` (a symbolic state value like a plan-state or regime tag), or {@link UNKNOWN}. * - {@link TriState} — the result of evaluating a trigger: `true | false | UNKNOWN`. * * All time is injected (RUNTIME §0): {@link durationMs} is the one place a `Window` or * `Duration` value+unit is turned into milliseconds, so every window/held/within/esc span * measures identically. */ // ───────────────────────────────────────────────────────────────────────────── // UNKNOWN — the third truth value / the missing scalar // ───────────────────────────────────────────────────────────────────────────── /** The sole "insufficient data / unresolvable" sentinel. A unique symbol so it can never * be confused with a real string value, a `0`, or a `false`. */ export const UNKNOWN = Symbol("kestrel.UNKNOWN"); /** Is `x` the UNKNOWN sentinel? */ export function isUnknown(x) { return x === UNKNOWN; } /** Is `x` a resolved *number* (not a string, not UNKNOWN)? */ export function isNumber(x) { return typeof x === "number"; } // ───────────────────────────────────────────────────────────────────────────── // Units bridge — the one time→ms conversion (RUNTIME §0: all time injected) // ───────────────────────────────────────────────────────────────────────────── /** Milliseconds per {@link TimeUnit}. Calendar units use fixed nominal spans (a month is * 30d, a quarter 90d, a year 365d) — windows are trailing measurement horizons, not * calendar arithmetic, so a fixed nominal span is the honest, deterministic choice. */ const MS = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000, w: 604_800_000, mo: 2_592_000_000, // 30d q: 7_776_000_000, // 90d y: 31_536_000_000, // 365d }; /** Convert a `{ value, unit }` window/duration to milliseconds. */ export function durationMs(value, unit) { return value * MS[unit]; }