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.
103 lines (102 loc) • 6.15 kB
JavaScript
/**
* # grade/measurement — alpha measurements carry a KIND, and kinds never blend (kestrel-a57.6)
*
* A measurement of alpha is not one number; it is a number **plus the evidence semantics that produced it**.
* The three kinds carry DIFFERENT evidence, so silently blending or ranking one against another is a category
* error — the same class of error ADR-0006 forbids across measurement *versions* ("EVs across measurement
* versions refuse naive comparison"). This module is the KIND-axis sibling of that rule: **alphas across KINDS
* refuse naive comparison**, and the enforcement is the TypeScript compiler.
*
* 1. RULE ALPHA — a MECHANICAL TEMPLATE run over EVERY eligible opportunity on a tape (systematic, no
* discretion). Its evidence is the template's realized measure over the whole universe.
* 2. SELECTION ALPHA — POINT-IN-TIME CURATION (the author PICKED which opportunities to act on), measured
* VS A FROZEN COUNTERFACTUAL on the SAME FUTURE TAPE (what those same picks, frozen,
* would have realized). Its evidence is SELECTION skill: realized minus the frozen leg.
* 3. DIAGNOSTIC — exploratory / inspection only. Carries an explicit `non_promotable: true` marker and
* has NO ordering surface at all (no `compare`, no `rank`, no `promote`).
*
* ## The barrier (compile-time)
* Each kind is a distinctly **branded** record (a private `unique symbol` phantom brand ⇒ nominal, mutually
* non-assignable, even if fields ever coincided). `compare` / `rank` / `promote` are pinned with `NoInfer<M>`:
* the measurement type `M` is inferred ONLY from the first parameter, so a second argument of a different kind
* has nothing to unify with and fails to type-check. `PromotableAlpha` excludes diagnostics, so the diagnostic
* kind has no accepting overload anywhere — its only surface is construction and inspection.
*
* ## Diagnostics never promote (dual gate — fail-closed)
* (compile) `promote<M extends PromotableAlpha>` will not bind a `DiagnosticMeasurement`; (runtime) if a caller
* bypasses the types (an `any` / erased boundary), {@link promote} returns a typed refusal — `{ ok: false,
* reason, kind }` — never throws, never silently succeeds. This mirrors the module's fail-closed convention
* ({@link bankableEv} floors by RETURN; the receipt projector degrades with a logged reason) rather than
* inventing a new error style.
*
* Ranking is on ONE named scalar per kind — never a blended omnibus (honors the m9i no-omnibus rule). Pure and
* deterministic: no wall clock, no RNG; off the runtime/record path (no bus/Blotter/grammar/golden bytes move).
*/
/** Build a {@link RuleAlphaMeasurement}. Pure: stamps the discriminant kind; no clock, no RNG. */
export function ruleAlpha(input) {
return { ...input, kind: "rule_alpha" };
}
/** Build a {@link SelectionAlphaMeasurement}. Pure: stamps the discriminant kind; no clock, no RNG. */
export function selectionAlpha(input) {
return { ...input, kind: "selection_alpha" };
}
/** Build a {@link DiagnosticMeasurement}. Pure: stamps the kind + the explicit non-promotable marker. */
export function diagnostic(input) {
return { ...input, kind: "diagnostic", non_promotable: true };
}
/**
* The ONE named scalar a kind is ordered by:
* • rule alpha → `realized_r` (the mechanical rule's realized measure over its whole universe);
* • selection alpha → `selection_edge` = realized − frozen counterfactual (the marginal value of the curation).
* Never a composite — the honesty rule is that ranking is on a single, named measure.
*/
function scalarOf(m) {
if (m.kind === "rule_alpha") {
return { name: "realized_r", value: m.realized.realized_r };
}
return {
name: "selection_edge",
value: m.realized.realized_r - m.frozen_counterfactual.realized.realized_r,
};
}
/**
* Compare two measurements OF THE SAME KIND on that kind's one named scalar. `M` is inferred solely from `a`;
* `NoInfer<M>` pins `b` to the same kind, so a cross-kind second argument fails to compile. Diagnostics are not
* in {@link PromotableAlpha}, so they have no `compare` overload at all. Pure, total, deterministic.
*/
export function compare(a, b) {
const sa = scalarOf(a);
const sb = scalarOf(b);
const order = sa.value > sb.value ? 1 : sa.value < sb.value ? -1 : 0;
return { order, measure: sa.name };
}
/**
* Rank measurements OF THE SAME KIND, descending by that kind's one named scalar. `M` is inferred solely from
* the first element; every remaining element is pinned to the same kind via `NoInfer<M>`, so a mixed-kind list
* (or a list containing a diagnostic) fails to compile. Pure: returns a sorted COPY; the input is never mutated.
*/
export function rank(xs) {
return [...xs].sort((a, b) => scalarOf(b).value - scalarOf(a).value);
}
/**
* Promote a promotable alpha to a candidate. At compile time only {@link PromotableAlpha} binds `M`, so a
* diagnostic has no accepting path. At RUNTIME this is defense-in-depth for a caller that bypassed the types
* (an `any` / erased boundary): it inspects the actual object and FAILS CLOSED — a diagnostic, a non-promotable
* marker, or any unrecognized kind returns a typed refusal with a logged reason. It never throws, never silently
* succeeds. Pure and deterministic.
*/
export function promote(candidate) {
// Read the runtime shape through a widened view so the guard is NOT narrowed away by the compile-time type —
// a types-bypassed caller may hand us an object whose real kind is "diagnostic".
const probe = candidate;
const kind = typeof probe.kind === "string" ? probe.kind : "unknown";
const isPromotableKind = kind === "rule_alpha" || kind === "selection_alpha";
if (probe.non_promotable === true || !isPromotableKind) {
return {
ok: false,
reason: `diagnostic / non-promotable measurement can never promote (kind=${kind})`,
kind,
};
}
return { ok: true, candidate };
}