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.

78 lines (77 loc) 4.13 kB
/** * # blotter/protocol-view — the pure engine → PROTOCOL Blotter projection (kestrel-b0li). * * The ONE source of truth for turning a rich engine {@link EngineBlotter} into the generic public * PROTOCOL {@link Blotter} the {@link grade} Judge scores — un-dropping the risk-honest `totals` + * `fill_claim` (kestrel-h314 D2) so both metric families are outsider-recomputable from a published * Blotter. Extracted here from `sdk/local.ts` (which re-exports it) into a LIGHT module — it depends * only on the blotter types + the dependency-free protocol types, never on `lang`/`session`/`catalog` * — so the node-only `certify` verb can grade a re-projection (`published numbers == grade(reproject(tape))`, * OSS-ADR-0051) without dragging the engine drive into the npx-light import graph. * * Honest + deterministic: no wall clock (the settle instant is the settle-mark's `as_of_ts` or the * latest plan-lifecycle ts), no RNG, no invented arithmetic — only the accounting the engine record * already carries, reduced to its public verdict. */ /** The settle instant as an ISO-8601 string — from the settle-mark's `as_of_ts` when the graded bus * carries one, else the latest plan-lifecycle ts (deterministic; never a wall clock). */ function settledAtOf(b) { const asOf = b.totals.settle_mark?.as_of_ts; if (typeof asOf === "number") return new Date(asOf).toISOString(); let maxTs = 0; for (const p of b.plans) for (const s of p.lifecycle) if (s.ts > maxTs) maxTs = s.ts; return new Date(maxTs).toISOString(); } /** * Project the rich engine {@link EngineBlotter}'s totals into the verdict-only PROTOCOL {@link Totals} * (kestrel-h314 D2). UN-DROPS the risk-honest accounting the engine record already carries — byte-stable, * NOT invented arithmetic — so the risk-honest metrics are outsider-recomputable from the published Blotter. * The engine's licensed raw settle mark is REDUCED to its verdict here (D3): the raw vendor spot + * observation timestamps do NOT cross onto the public artifact. */ function toProtocolTotals(b) { const t = b.totals; const sm = t.settle_mark; const settle_mark = sm === undefined ? undefined : { stale: sm.stale, source: sm.source, mark_uncertain: sm.mark_uncertain, note: sm.note }; return { floor: t.floor, expected: t.expected, ...(t.sampled !== undefined ? { sampled: t.sampled } : {}), headline: { channel: t.headline.channel, usd: t.headline.usd, gate: { qualified: t.headline.gate.qualified, reasons: t.headline.gate.reasons }, tainted: t.headline.tainted, reasons: t.headline.reasons, }, ...(settle_mark !== undefined ? { settle_mark } : {}), }; } /** Project the engine `fill_claim` slices onto the wire {@link FillClaim} (kestrel-h314 D2): drops the * per-slice `orders` count (not needed to recompute bankable EV), keeps the SIGNED `expected`/`gain`/`loss`. * Deterministic, in the fixed `[calibrated, extrapolated]` order the engine already emits. */ function toProtocolFillClaim(b) { return b.fill_claim.map((c) => ({ support: c.support, expected: c.expected, gain: c.gain, loss: c.loss })); } /** * Project the rich engine {@link EngineBlotter} into the PROTOCOL {@link Blotter} (the generic public * view). Honest + deterministic. Carries the deterministic identity + the fully-determined settlement; * the generic order/fill/position arrays are empty (the engine record lacks the generic legs a faithful * public Instrument/Order needs; never fabricated). Additionally carries the un-dropped `totals` + * `fill_claim`, so the risk-honest metric family is outsider-recomputable by the {@link grade} Judge. */ export function toProtocolBlotter(sessionId, b) { return { sessionId, orders: [], fills: [], positions: [], settlement: { realized: b.totals.floor, asset: "usd", settledAt: settledAtOf(b) }, totals: toProtocolTotals(b), fill_claim: toProtocolFillClaim(b), }; }