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.
1,040 lines (1,025 loc) • 31.9 kB
JavaScript
import {
black76,
impliedVol,
intrinsic
} from "./bin-df1tn094.js";
import {
assertNever
} from "./bin-2ywrx58g.js";
// src/series/types.ts
var UNKNOWN = Symbol("kestrel.UNKNOWN");
function isUnknown(x) {
return x === UNKNOWN;
}
var MS = {
s: 1000,
m: 60000,
h: 3600000,
d: 86400000,
w: 604800000,
mo: 2592000000,
q: 7776000000,
y: 31536000000
};
function durationMs(value, unit) {
return value * MS[unit];
}
// src/series/windows.ts
var DEFAULTS = { baselineCapacity: 512, minBaselineSamples: 30, maxSamples: 200000 };
class BaselineRing {
cap;
buf = [];
head = 0;
constructor(cap) {
this.cap = cap;
}
push(v) {
if (this.buf.length < this.cap) {
this.buf.push(v);
} else {
this.buf[this.head] = v;
this.head = (this.head + 1) % this.cap;
}
}
get count() {
return this.buf.length;
}
percentile(n) {
const sorted = [...this.buf].sort((a, b) => a - b);
const N = sorted.length;
const rank = Math.min(N, Math.max(1, Math.ceil(n / 100 * N)));
return sorted[rank - 1];
}
sigmaBand(k) {
const N = this.buf.length;
let sum = 0;
for (const v of this.buf)
sum += v;
const mean = sum / N;
let ss = 0;
for (const v of this.buf)
ss += (v - mean) * (v - mean);
const sd = Math.sqrt(ss / N);
return mean + k * sd;
}
}
function comboKey(metric, windowMs) {
return `${metric}|${windowMs}`;
}
class WindowEngine {
samples = [];
baselines = new Map;
cfg;
constructor(cfg = {}) {
this.cfg = {
baselineCapacity: cfg.baselineCapacity ?? DEFAULTS.baselineCapacity,
minBaselineSamples: cfg.minBaselineSamples ?? DEFAULTS.minBaselineSamples,
maxSamples: cfg.maxSamples ?? DEFAULTS.maxSamples
};
}
track(metric, value, unit) {
const key = comboKey(metric, durationMs(value, unit));
if (!this.baselines.has(key))
this.baselines.set(key, new BaselineRing(this.cfg.baselineCapacity));
}
pushSpot(ts, px) {
this.samples.push({ ts, px });
if (this.samples.length > this.cfg.maxSamples)
this.samples.shift();
for (const [key, ring] of this.baselines) {
const [metric, windowMsStr] = key.split("|");
const wv = this.compute(metric, Number(windowMsStr), ts);
if (wv !== UNKNOWN)
ring.push(wv.dollars);
}
}
value(metric, value, unit, now) {
return this.compute(metric, durationMs(value, unit), now);
}
baseline(metric, value, unit, stat) {
const ring = this.baselines.get(comboKey(metric, durationMs(value, unit)));
if (ring === undefined || ring.count < this.cfg.minBaselineSamples)
return UNKNOWN;
return stat.kind === "p" ? ring.percentile(stat.n) : ring.sigmaBand(stat.n);
}
get sampleCount() {
return this.samples.length;
}
reset() {
this.samples.length = 0;
this.baselines.clear();
}
compute(metric, windowMs, now) {
const cutoff = now - windowMs;
const startPx = this.priceAtOrBefore(cutoff);
if (startPx === undefined)
return UNKNOWN;
const nowPx = this.latestPx();
if (nowPx === undefined)
return UNKNOWN;
if (metric === "range") {
let hi = -Infinity;
let lo = Infinity;
for (let i = this.samples.length - 1;i >= 0; i--) {
const s = this.samples[i];
if (s.ts < cutoff)
break;
if (s.px > hi)
hi = s.px;
if (s.px < lo)
lo = s.px;
}
const dollars = hi - lo;
return { dollars, pct: startPx !== 0 ? dollars / Math.abs(startPx) : 0 };
}
const delta = nowPx - startPx;
const signed = metric === "velocity" ? delta : Math.abs(delta);
return { dollars: signed, pct: startPx !== 0 ? signed / Math.abs(startPx) : 0 };
}
priceAtOrBefore(cutoff) {
for (let i = this.samples.length - 1;i >= 0; i--) {
const s = this.samples[i];
if (s.ts <= cutoff)
return s.px;
}
return;
}
latestPx() {
const last = this.samples[this.samples.length - 1];
return last?.px;
}
}
// src/series/state.ts
class CanonicalState {
instrument;
windows;
orMs;
priorCloseVal;
spotVal;
spotTs;
hodVal;
lodVal;
hodExclVal;
lodExclVal;
orHiExclVal;
orLoExclVal;
orAnchorTs;
orHi;
orLo;
vwapNum = 0;
vwapDen = 0;
lastPx;
lastPxTs;
phaseVal;
constructor(cfg) {
this.instrument = cfg.instrument;
this.priorCloseVal = cfg.priorClose;
this.orMs = durationMs(cfg.openingRangeMinutes ?? 5, "m");
this.windows = new WindowEngine(cfg.windows ?? {});
}
applyEvent(ev) {
if (ev.stream === "TICK") {
if (ev.type === "SPOT") {
if (ev.instrument === this.instrument)
this.onSpot(ev.ts, ev.px);
} else if (ev.type === "HEARTBEAT") {
if (ev.phase !== undefined)
this.phaseVal = ev.phase;
}
}
}
onSpot(ts, px) {
this.hodExclVal = this.hodVal?.value;
this.lodExclVal = this.lodVal?.value;
this.orHiExclVal = this.orHi;
this.orLoExclVal = this.orLo;
if (this.lastPx !== undefined && this.lastPxTs !== undefined) {
const dt = ts - this.lastPxTs;
if (dt > 0) {
this.vwapNum += this.lastPx * dt;
this.vwapDen += dt;
}
}
this.lastPx = px;
this.lastPxTs = ts;
this.spotVal = px;
this.spotTs = ts;
if (this.hodVal === undefined || px > this.hodVal.value)
this.hodVal = { value: px, ts };
if (this.lodVal === undefined || px < this.lodVal.value)
this.lodVal = { value: px, ts };
if (this.orAnchorTs === undefined)
this.orAnchorTs = ts;
if (ts <= this.orAnchorTs + this.orMs) {
this.orHi = this.orHi === undefined ? px : Math.max(this.orHi, px);
this.orLo = this.orLo === undefined ? px : Math.min(this.orLo, px);
}
this.windows.pushSpot(ts, px);
}
get spot() {
return this.spotVal ?? UNKNOWN;
}
get spotStamp() {
return this.spotVal !== undefined && this.spotTs !== undefined ? { value: this.spotVal, ts: this.spotTs } : UNKNOWN;
}
get hod() {
return this.hodVal?.value ?? UNKNOWN;
}
get hodStamp() {
return this.hodVal ?? UNKNOWN;
}
get lod() {
return this.lodVal?.value ?? UNKNOWN;
}
get lodStamp() {
return this.lodVal ?? UNKNOWN;
}
get hodTrigger() {
return this.hodExclVal ?? UNKNOWN;
}
get lodTrigger() {
return this.lodExclVal ?? UNKNOWN;
}
get orHighTrigger() {
return this.orHiExclVal ?? UNKNOWN;
}
get orLowTrigger() {
return this.orLoExclVal ?? UNKNOWN;
}
get priorClose() {
return this.priorCloseVal ?? UNKNOWN;
}
get orHigh() {
return this.orHi ?? UNKNOWN;
}
get orLow() {
return this.orLo ?? UNKNOWN;
}
get phase() {
return this.phaseVal ?? UNKNOWN;
}
get vwap() {
if (this.spotVal === undefined)
return UNKNOWN;
if (this.vwapDen === 0)
return this.spotVal;
return this.vwapNum / this.vwapDen;
}
reset() {
this.spotVal = undefined;
this.spotTs = undefined;
this.hodVal = undefined;
this.lodVal = undefined;
this.hodExclVal = undefined;
this.lodExclVal = undefined;
this.orHiExclVal = undefined;
this.orLoExclVal = undefined;
this.orAnchorTs = undefined;
this.orHi = undefined;
this.orLo = undefined;
this.vwapNum = 0;
this.vwapDen = 0;
this.lastPx = undefined;
this.lastPxTs = undefined;
this.phaseVal = undefined;
this.windows.reset();
}
}
// src/series/registry.ts
var OBSERVABILITY_ORDER = ["tick", "second", "minute", "session"];
function observabilityRank(c) {
return OBSERVABILITY_ORDER.indexOf(c);
}
function isRung(v) {
return OBSERVABILITY_ORDER.includes(v);
}
function isFinerThanFidelity(cls, fidelity) {
if (!isRung(cls) || !isRung(fidelity))
return true;
return observabilityRank(cls) < observabilityRank(fidelity);
}
function marketScalarReg(name, observabilityClass) {
return {
name,
kind: "market",
scope: { space: "signal" },
windowing: "scalar",
source: { kind: "platform" },
unit: "price",
market: { via: "scalar", scalar: name },
observabilityClass
};
}
function marketWindowReg(name, metric, pct) {
return {
name,
kind: "market",
scope: { space: "signal" },
windowing: "windowed",
source: { kind: "platform" },
unit: pct ? "fraction" : "price_delta",
market: { via: "window", metric, pct },
observabilityClass: "tick"
};
}
var PLATFORM_SERIES = [
marketScalarReg("spot", "tick"),
marketScalarReg("vwap", "tick"),
marketScalarReg("hod", "minute"),
marketScalarReg("lod", "minute"),
marketScalarReg("prior_close", "session"),
marketScalarReg("or_high", "minute"),
marketScalarReg("or_low", "minute"),
marketWindowReg("velocity", "velocity", false),
marketWindowReg("velocity_pct", "velocity", true),
marketWindowReg("move", "move", false),
marketWindowReg("move_pct", "move", true),
marketWindowReg("range", "range", false),
marketWindowReg("range_pct", "range", true)
];
function headName(ref) {
return ref.segments[0]?.name;
}
function orgScopePath(segments) {
return segments.map((s) => s.name);
}
class SeriesRegistry {
records = new Map;
constructor(platform = PLATFORM_SERIES) {
for (const r of platform)
this.records.set(r.name, r);
}
lookup(name) {
return this.records.get(name);
}
classify(ref) {
const name = headName(ref);
if (name === undefined)
return UNKNOWN;
return this.records.get(name) ?? UNKNOWN;
}
admitAtFidelity(ref, fidelity) {
const rec = this.classify(ref);
const label = headName(ref) ?? "(empty path)";
if (!isRung(fidelity)) {
return {
admit: false,
reason: `unknown grading fidelity "${fidelity}" — not a recognized observability rung (${OBSERVABILITY_ORDER.join(", ")}); series "${label}" cannot be graded on an untrusted fidelity (fail-closed, RUNTIME §2/§8)`
};
}
if (isUnknown(rec)) {
return {
admit: false,
reason: `series "${label}" has no phonebook record — an unknown series cannot be graded at ${fidelity} fidelity (fail-closed, RUNTIME §2/§8)`
};
}
if (rec.kind === "org")
return { admit: true };
const cls = rec.observabilityClass;
if (cls === undefined) {
return {
admit: false,
reason: `market series "${rec.name}" carries no observability class — cannot confirm it is observable at ${fidelity} fidelity (fail-closed)`
};
}
if (isFinerThanFidelity(cls, fidelity)) {
return {
admit: false,
reason: `series "${rec.name}" is ${cls}-observable but the session grades at ${fidelity} fidelity — a finer-than-fidelity series cannot be graded honestly; de-arm (fidelity-1, RUNTIME §2/§8)`
};
}
return { admit: true };
}
noteOrgWrite(segments, by) {
const head = segments[0];
if (head === undefined)
return UNKNOWN;
const existing = this.records.get(head.name);
if (existing !== undefined)
return existing;
const reg = {
name: head.name,
kind: "org",
scope: { space: "org", path: orgScopePath(segments) },
windowing: "scalar",
source: { kind: "authored", by }
};
this.records.set(head.name, reg);
return reg;
}
dump() {
return [...this.records.values()].map((r) => ({ ...r })).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
}
}
var defaultSeriesRegistry = new SeriesRegistry;
// src/series/provider.ts
function marketBinding(registry, name) {
const reg = registry.lookup(name);
return reg?.kind === "market" ? reg.market : undefined;
}
function isBareSegment(ref) {
return ref.segments.length === 1 && ref.segments[0]?.selector === undefined;
}
class CanonicalSeriesProvider {
state;
org;
hooks;
registry;
constructor(state, org, hooks = {}, registry = defaultSeriesRegistry) {
this.state = state;
this.org = org;
this.hooks = hooks;
this.registry = registry;
}
timeOfDayMinutes(now) {
return this.hooks.timeOfDayMinutes ? this.hooks.timeOfDayMinutes(now) : UNKNOWN;
}
fillEvent(ev) {
return this.hooks.fillEvent ? this.hooks.fillEvent(ev) : UNKNOWN;
}
temporalEnvelope(env, inner, now) {
return this.hooks.temporalEnvelope ? this.hooks.temporalEnvelope(env, inner, now) : UNKNOWN;
}
resolve(ref, now) {
if (ref.segments.length === 0)
return UNKNOWN;
const head = ref.segments[0];
if (head === undefined)
return UNKNOWN;
if (ref.window !== undefined) {
if (!isBareSegment(ref))
return UNKNOWN;
const binding = marketBinding(this.registry, head.name);
if (binding?.via !== "window")
return UNKNOWN;
const wv = this.state.windows.value(binding.metric, ref.window.value, ref.window.unit, now);
if (wv === UNKNOWN)
return UNKNOWN;
return binding.pct ? wv.pct : wv.dollars;
}
if (isBareSegment(ref)) {
const binding = marketBinding(this.registry, head.name);
if (binding?.via === "scalar")
return this.marketScalar(binding.scalar);
}
return this.org.resolve(ref.segments);
}
quantify(ref, _now) {
return this.org.quantify?.(ref.segments) ?? UNKNOWN;
}
baseline(ref, stat) {
if (ref.window === undefined || !isBareSegment(ref))
return UNKNOWN;
const head = ref.segments[0];
if (head === undefined)
return UNKNOWN;
const binding = marketBinding(this.registry, head.name);
if (binding?.via !== "window")
return UNKNOWN;
const bstat = stat.stat === "p" ? { kind: "p", n: stat.n } : { kind: "sigma", n: stat.n };
return this.state.windows.baseline(binding.metric, ref.window.value, ref.window.unit, bstat);
}
phase() {
return this.state.phase;
}
marketScalar(name) {
switch (name) {
case "spot":
return this.state.spot;
case "vwap":
return this.state.vwap;
case "hod":
return this.state.hodTrigger;
case "lod":
return this.state.lodTrigger;
case "prior_close":
return this.state.priorClose;
case "or_high":
return this.state.orHighTrigger;
case "or_low":
return this.state.orLowTrigger;
default:
return UNKNOWN;
}
}
}
function pathKey(segments) {
return segments.map((s) => {
if (s.selector === undefined)
return s.name;
const inner = s.selector.kind === "sel-quant" ? s.selector.q : s.selector.name;
return `${s.name}(${inner})`;
}).join(".");
}
class FakeOrgFacts {
facts;
constructor(facts = new Map) {
this.facts = facts;
}
static of(entries) {
return new FakeOrgFacts(new Map(Object.entries(entries)));
}
resolve(segments) {
return this.facts.get(pathKey(segments)) ?? UNKNOWN;
}
}
// src/series/trigger.ts
var ROOT = "$";
function quantOf(op) {
if (op.kind !== "series" || op.window !== undefined)
return null;
const head = op.segments[0];
return head?.selector?.kind === "sel-quant" ? head.selector.q : null;
}
class TriggerEvaluator {
mem = new Map;
evaluate(trigger, provider, now) {
return this.evalNode(trigger, ROOT, provider, now);
}
reset() {
this.mem.clear();
}
dumpState() {
return [...this.mem.entries()].map(([path, m]) => [path, { ...m }]).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
}
evalNode(node, path, provider, now) {
switch (node.kind) {
case "cmp": {
if (quantOf(node.left) !== null || quantOf(node.right) !== null) {
return this.evalQuantifiedCompare(node.op, node.left, node.right, provider, now);
}
const { lv, rv } = this.resolvePair(node.left, node.right, provider, now);
const lU = isUnknown(lv);
const rU = isUnknown(rv);
if (lU && rU)
return UNKNOWN;
if (lU || rU) {
if (node.op === "eq" || node.op === "ne") {
const lFinal = lU ? this.literalOf(node.left) : lv;
const rFinal = rU ? this.literalOf(node.right) : rv;
if (!isUnknown(lFinal) && !isUnknown(rFinal)) {
return node.op === "eq" ? lFinal === rFinal : lFinal !== rFinal;
}
}
return UNKNOWN;
}
return this.compareResolved(node.op, lv, rv);
}
case "cross": {
if (quantOf(node.left) !== null || quantOf(node.right) !== null)
return UNKNOWN;
const { lv, rv } = this.resolvePair(node.left, node.right, provider, now);
if (isUnknown(lv) || isUnknown(rv))
return UNKNOWN;
if (typeof lv !== "number" || typeof rv !== "number")
return UNKNOWN;
const mem = this.crossMem(path);
const cur = lv > rv ? "above" : lv < rv ? "below" : "equal";
if (node.band !== undefined && !mem.armed) {
const width = node.band.value;
const cleared = node.dir === "above" ? lv <= rv - width : lv >= rv + width;
if (cleared)
mem.armed = true;
}
const side = cur === "equal" ? node.touch === true ? node.dir : null : cur;
if (side === null)
return false;
const prev = mem.prevSide;
mem.prevSide = side;
if (prev === null)
return false;
if (!(prev !== side && side === node.dir))
return false;
if (node.band !== undefined) {
if (!mem.armed)
return false;
mem.armed = false;
}
return true;
}
case "break-hold": {
const inner = this.evalNode(node.inner, `${path}.0`, provider, now);
const mem = this.heldMem(path);
const dur = durationMs(node.dur.value, node.dur.unit);
if (inner === true) {
if (mem.since === null)
mem.since = now;
return now - mem.since >= dur;
}
mem.since = null;
return inner === UNKNOWN ? UNKNOWN : false;
}
case "within": {
const inner = this.evalNode(node.inner, `${path}.0`, provider, now);
const mem = this.withinMem(path);
const dur = durationMs(node.dur.value, node.dur.unit);
if (inner === true)
mem.lastTrue = now;
if (mem.lastTrue !== null)
return now - mem.lastTrue <= dur;
return inner === UNKNOWN ? UNKNOWN : false;
}
case "until":
case "at": {
const inner = this.evalNode(node.inner, `${path}.0`, provider, now);
return provider.temporalEnvelope ? provider.temporalEnvelope(node, inner, now) : UNKNOWN;
}
case "held-stop": {
return UNKNOWN;
}
case "clock-stop": {
return UNKNOWN;
}
case "nth": {
const inner = this.evalNode(node.event, `${path}.0`, provider, now);
const mem = this.nthMem(path);
if (inner === true && !mem.prevInner)
mem.count += 1;
mem.prevInner = inner === true;
if (mem.count >= node.ordinal)
return true;
return inner === UNKNOWN ? UNKNOWN : false;
}
case "phase": {
const p = provider.phase();
if (isUnknown(p))
return UNKNOWN;
return p === node.phase;
}
case "time-window": {
if (provider.timeOfDayMinutes === undefined)
return UNKNOWN;
const m = provider.timeOfDayMinutes(now);
if (isUnknown(m))
return UNKNOWN;
const from = node.from ? node.from.hour * 60 + node.from.minute : null;
const to = node.to ? node.to.hour * 60 + node.to.minute : null;
const afterFrom = from === null || m >= from;
const beforeTo = to === null || m < to;
return afterFrom && beforeTo;
}
case "event": {
return provider.structural ? provider.structural(node, now) : UNKNOWN;
}
case "fill": {
return provider.fillEvent ? provider.fillEvent(node) : UNKNOWN;
}
case "and": {
const vals = node.terms.map((t, i) => this.evalNode(t, `${path}.${i}`, provider, now));
let anyUnknown = false;
for (const v of vals) {
if (v === false)
return false;
if (isUnknown(v))
anyUnknown = true;
}
return anyUnknown ? UNKNOWN : true;
}
case "or": {
const vals = node.terms.map((t, i) => this.evalNode(t, `${path}.${i}`, provider, now));
let anyUnknown = false;
for (const v of vals) {
if (v === true)
return true;
if (isUnknown(v))
anyUnknown = true;
}
return anyUnknown ? UNKNOWN : false;
}
case "not": {
const v = this.evalNode(node.term, `${path}.0`, provider, now);
if (isUnknown(v))
return UNKNOWN;
return !v;
}
default:
return assertNever(node, "series/trigger evalNode");
}
}
resolvePair(left, right, provider, now) {
if (right.kind === "baseline") {
if (left.kind !== "series")
return { lv: UNKNOWN, rv: UNKNOWN };
return { lv: provider.resolve(left, now), rv: provider.baseline(left, right) };
}
if (left.kind === "baseline") {
if (right.kind !== "series")
return { lv: UNKNOWN, rv: UNKNOWN };
return { lv: provider.baseline(right, left), rv: provider.resolve(right, now) };
}
return {
lv: this.operandValue(left, provider, now),
rv: this.operandValue(right, provider, now)
};
}
operandValue(op, provider, now) {
switch (op.kind) {
case "series":
return provider.resolve(op, now);
case "quantity":
return op.value;
case "baseline":
return UNKNOWN;
default:
return assertNever(op, "series/trigger operandValue");
}
}
literalOf(op) {
if (op.kind !== "series" || op.window !== undefined || op.segments.length !== 1)
return UNKNOWN;
const seg0 = op.segments[0];
if (seg0 === undefined || seg0.selector !== undefined)
return UNKNOWN;
return seg0.name;
}
evalQuantifiedCompare(op, left, right, provider, now) {
const lq = quantOf(left);
const rq = quantOf(right);
if (lq !== null && rq !== null)
return UNKNOWN;
const quant = lq ?? rq;
const qRef = lq !== null ? left : right;
const other = lq !== null ? right : left;
const values = provider.quantify?.(qRef, now) ?? UNKNOWN;
if (isUnknown(values))
return UNKNOWN;
const threshold = this.operandValue(other, provider, now);
if (isUnknown(threshold))
return UNKNOWN;
let anyTrue = false;
let anyFalse = false;
let anyUnknown = false;
for (const v of values) {
const r = lq !== null ? this.compareResolved(op, v, threshold) : this.compareResolved(op, threshold, v);
if (r === true)
anyTrue = true;
else if (isUnknown(r))
anyUnknown = true;
else
anyFalse = true;
}
if (quant === "any")
return anyTrue ? true : anyUnknown ? UNKNOWN : false;
return anyFalse ? false : anyUnknown ? UNKNOWN : true;
}
compareResolved(op, lv, rv) {
switch (op) {
case "eq":
return lv === rv;
case "ne":
return lv !== rv;
case "gt":
case "ge":
case "lt":
case "le": {
if (typeof lv !== "number" || typeof rv !== "number")
return UNKNOWN;
return op === "gt" ? lv > rv : op === "ge" ? lv >= rv : op === "lt" ? lv < rv : lv <= rv;
}
default:
return assertNever(op, "series/trigger compareResolved");
}
}
crossMem(path) {
const m = this.mem.get(path);
if (m !== undefined) {
if (m.kind !== "cross")
throw new Error(`series/trigger: memory kind clash at ${path}`);
return m;
}
const fresh = { kind: "cross", prevSide: null, armed: true };
this.mem.set(path, fresh);
return fresh;
}
heldMem(path) {
const m = this.mem.get(path);
if (m !== undefined) {
if (m.kind !== "held")
throw new Error(`series/trigger: memory kind clash at ${path}`);
return m;
}
const fresh = { kind: "held", since: null };
this.mem.set(path, fresh);
return fresh;
}
withinMem(path) {
const m = this.mem.get(path);
if (m !== undefined) {
if (m.kind !== "within")
throw new Error(`series/trigger: memory kind clash at ${path}`);
return m;
}
const fresh = { kind: "within", lastTrue: null };
this.mem.set(path, fresh);
return fresh;
}
nthMem(path) {
const m = this.mem.get(path);
if (m !== undefined) {
if (m.kind !== "nth")
throw new Error(`series/trigger: memory kind clash at ${path}`);
return m;
}
const fresh = { kind: "nth", count: 0, prevInner: false };
this.mem.set(path, fresh);
return fresh;
}
}
// src/fair/spot.ts
var EXEC_FAIR_QUOTE_MODEL = "exec-fair-quote-v1";
function executionFairSpot(input) {
const { bid, ask, asof } = input;
if (bid === null || ask === null)
return null;
if (!Number.isFinite(bid) || !Number.isFinite(ask))
return null;
if (ask < bid)
return null;
const value = (bid + ask) / 2;
return {
value,
receipt: { model: EXEC_FAIR_QUOTE_MODEL, bid, ask, ...asof !== undefined ? { asof } : {} }
};
}
// src/fair/surface.ts
var PARITY_TOTAL_VOL_TOLERANCE = 0.001;
function realSides(q, forward) {
let bid = q.bid;
let ask = q.ask;
if (bid !== null && bid < intrinsic(forward, q.strike, q.right))
bid = null;
const ceiling = q.right === "C" ? forward : q.strike;
if (ask !== null && ask >= ceiling)
ask = null;
if (bid !== null && ask !== null && bid >= ask) {
bid = null;
ask = null;
}
return { bid, ask };
}
function liquidMid(q, forward) {
const { bid, ask } = realSides(q, forward);
if (bid === null || ask === null)
return null;
const mid = 0.5 * (bid + ask);
return mid > 0 ? mid : null;
}
var FORWARD_NO_ARB_BAND = 0.1;
function impliedForward(quotes, spot) {
const degraded = (reason) => ({ forward: spot, source: "spot", degraded: reason });
if (!Number.isFinite(spot) || spot <= 0)
return degraded("underlying spot unusable — no ATM anchor to read parity at");
const calls = new Map;
const puts = new Map;
for (const q of quotes) {
const mid = liquidMid(q, spot);
if (mid === null)
continue;
(q.right === "C" ? calls : puts).set(q.strike, mid);
}
let bestStrike = null;
let bestDist = Infinity;
for (const [strike, _cmid] of calls) {
if (!puts.has(strike))
continue;
const dist = Math.abs(strike - spot);
if (dist < bestDist || dist === bestDist && bestStrike !== null && strike < bestStrike) {
bestDist = dist;
bestStrike = strike;
}
}
if (bestStrike === null) {
return degraded("no strike carries a liquid two-sided CALL and PUT — put-call parity underivable");
}
const cmid = calls.get(bestStrike);
const pmid = puts.get(bestStrike);
if (cmid === undefined || pmid === undefined)
return degraded("parity pair vanished — refusing to guess");
const forward = bestStrike + (cmid - pmid);
if (!Number.isFinite(forward) || forward <= 0) {
return degraded(`parity-implied forward is not a price (${forward}) — refusing to price on it`);
}
if (Math.abs(forward / spot - 1) > FORWARD_NO_ARB_BAND) {
return degraded(`parity-implied forward ${forward} is >${FORWARD_NO_ARB_BAND * 100}% from spot ${spot} — a broken quote, not a forward`);
}
return { forward, source: "parity", strike: bestStrike, residual: forward - spot };
}
function buildSurface(quotes, forward, tauYears) {
const acc = new Map;
for (const q of quotes) {
const mid = liquidMid(q, forward);
if (mid === null)
continue;
const iv = impliedVol({ forward, strike: q.strike, tauYears, price: mid, right: q.right });
if (iv === null)
continue;
const cur = acc.get(q.strike) ?? {};
if (q.right === "C") {
if (cur.call === undefined)
cur.call = iv;
} else if (cur.put === undefined) {
cur.put = iv;
}
acc.set(q.strike, cur);
}
const points = [];
const sqrtTau = Math.sqrt(tauYears);
for (const [strike, { call, put }] of acc) {
if (call !== undefined && put !== undefined) {
const dispersion = Math.abs(call - put);
if (dispersion * sqrtTau > PARITY_TOTAL_VOL_TOLERANCE)
continue;
points.push({ strike, iv: 0.5 * (call + put), dispersion });
continue;
}
const only = call ?? put;
if (only !== undefined)
points.push({ strike, iv: only });
}
points.sort((a, b) => a.strike - b.strike);
return points;
}
function interpIv(points, strike) {
const n = points.length;
const first = points[0];
const last = points[n - 1];
if (first === undefined || last === undefined)
return null;
if (n === 1 || strike <= first.strike)
return first.iv;
if (strike >= last.strike)
return last.iv;
for (let i = 0;i < n - 1; i++) {
const a = points[i];
const b = points[i + 1];
if (a === undefined || b === undefined)
break;
if (strike >= a.strike && strike <= b.strike) {
const span = b.strike - a.strike;
if (span <= 0)
return a.iv;
const w = (strike - a.strike) / span;
return a.iv + w * (b.iv - a.iv);
}
}
return last.iv;
}
// src/fair/index.ts
var EXEC_FAIR_MODEL = "exec-fair-b76-v1";
function isFairRefusal(o) {
return "refused" in o;
}
var BOOK_BOUND_EPS = 0.000000001;
function executionFairOutcome(input) {
const { underlyingSpot, strike, right, tauYears, liquidQuotes, asof } = input;
if (!Number.isFinite(underlyingSpot) || underlyingSpot <= 0) {
return { refused: "unbuildable", reason: "no-underlying" };
}
const fwd = impliedForward(liquidQuotes, underlyingSpot);
const surface = buildSurface(liquidQuotes, fwd.forward, tauYears);
const nLiquid = surface.length;
if (nLiquid === 0)
return { refused: "unbuildable", reason: "no-liquid-strikes" };
const ivAtStrike = interpIv(surface, strike);
if (ivAtStrike === null)
return { refused: "unbuildable", reason: "no-surface-at-strike" };
let parityResidual;
for (const p of surface) {
if (p.dispersion === undefined)
continue;
if (parityResidual === undefined || p.dispersion > parityResidual)
parityResidual = p.dispersion;
}
const modeled = black76({ forward: fwd.forward, strike, tauYears, sigma: ivAtStrike, right });
const value = Math.max(modeled, intrinsic(underlyingSpot, strike, right));
if (input.bookFresh === true) {
const bid = input.legBid ?? null;
const ask = input.legAsk ?? null;
if (bid !== null && ask !== null && bid < ask) {
if (value > ask + BOOK_BOUND_EPS)
return { refused: "tainted", reason: "fair-above-fresh-ask" };
if (value < bid - BOOK_BOUND_EPS)
return { refused: "tainted", reason: "fair-below-fresh-bid" };
}
}
return {
value,
receipt: {
model: EXEC_FAIR_MODEL,
nLiquid,
ivAtStrike,
forward: fwd.forward,
forwardSource: fwd.source,
...fwd.strike !== undefined ? { forwardStrike: fwd.strike } : {},
...fwd.residual !== undefined ? { forwardResidual: fwd.residual } : {},
...fwd.degraded !== undefined ? { forwardDegraded: fwd.degraded } : {},
...parityResidual !== undefined ? { parityResidual } : {},
...asof !== undefined ? { asof } : {}
}
};
}
function executionFair(input) {
const outcome = executionFairOutcome(input);
return isFairRefusal(outcome) ? null : outcome;
}
export { UNKNOWN, isUnknown, durationMs, CanonicalState, defaultSeriesRegistry, CanonicalSeriesProvider, pathKey, FakeOrgFacts, TriggerEvaluator, impliedForward, buildSurface, interpIv, EXEC_FAIR_QUOTE_MODEL, executionFairSpot, EXEC_FAIR_MODEL, isFairRefusal, executionFairOutcome, executionFair };