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.

247 lines (245 loc) 8.5 kB
import { neverFiredDigestLines, renderEpisodeReport } from "./bin-awvz75fn.js"; import { loadHeavy } from "./bin-6676fry4.js"; import { renderOffer } from "./bin-x2cbtyjz.js"; import { parseArgs, required } from "./bin-1gc4zavq.js"; import { CliError, EXIT } from "./bin-t9ggwnv5.js"; import"./bin-xx1qrxe3.js"; import"./bin-t58k60v9.js"; import"./bin-p5jfg5b0.js"; import { canonicalPlansText } from "./bin-29be75ss.js"; import { exports_fill } from "./bin-n77kea5n.js"; import"./bin-mn7wcxhv.js"; import"./bin-8pchjxn2.js"; import"./bin-am3351y2.js"; import"./bin-73jr945c.js"; import"./bin-df1tn094.js"; import"./bin-3ft0k1jq.js"; import { exports_lang } from "./bin-2ywrx58g.js"; import { __require } from "./bin-wckvcay0.js"; // src/cli/commands/grade.ts import { mkdirSync, readFileSync } from "node:fs"; import { dirname } from "node:path"; var FILL_MODELS = new Set(["strict-cross-v1", "maker-fair-v1"]); var DEFAULT_DB = "data/kestrel.db"; var HOURS_PER_YEAR = 365 * 24; function usageErr(message) { return new CliError({ code: "USAGE", exit: EXIT.USAGE, message }); } var DAY_HANDSHAKE_CODES = new Set(["NO_AUTHOR", "HANDSHAKE_ABANDONED"]); async function dayHandshakeTyped(run) { try { return await run(); } catch (err) { if (err instanceof Error && err.name === "DayHandshakeError") { const code = err.code; if (typeof code === "string" && DAY_HANDSHAKE_CODES.has(code)) { const hint = err.hint; throw new CliError({ code, exit: EXIT.HANDSHAKE, message: err.message, ...typeof hint === "string" ? { hint } : {} }); } } throw err; } } function loadDocuments(plansPath) { const text = readFileSync(plansPath, "utf8"); return plansPath.endsWith(".md") ? exports_lang.parseMarkdown(text) : [exports_lang.parse(text)]; } function parseGradeFlags(flags) { const fillModel = required(flags, "fill"); if (!FILL_MODELS.has(fillModel)) { throw usageErr(`unknown fill model ${JSON.stringify(fillModel)} — one of strict-cross-v1 | maker-fair-v1`); } const rUsdRaw = required(flags, "r-usd"); const rUsd = Number(rUsdRaw); if (!Number.isFinite(rUsd) || rUsd <= 0) { throw usageErr(`--r-usd must be a positive number, got ${JSON.stringify(rUsdRaw)}`); } let fairTauYears; const tauRaw = flags.get("tau-hours"); if (tauRaw !== undefined) { const tauHours = Number(tauRaw); if (!Number.isFinite(tauHours) || tauHours <= 0) { throw usageErr(`--tau-hours must be a positive number, got ${JSON.stringify(tauRaw)}`); } const tauYears = tauHours / HOURS_PER_YEAR; fairTauYears = () => tauYears; } let makerFairParams; const hazardPath = flags.get("hazard-params"); if (hazardPath !== undefined) { if (fillModel !== "maker-fair-v1") throw usageErr("--hazard-params applies only to --fill maker-fair-v1"); const raw = JSON.parse(readFileSync(hazardPath, "utf8")); makerFairParams = exports_fill.loadEpisodeSigmoidParams(raw); } return { fillModel, rUsd, ...fairTauYears !== undefined ? { fairTauYears } : {}, ...makerFairParams !== undefined ? { makerFairParams } : {}, ...flags.get("out") !== undefined ? { out: flags.get("out") } : {} }; } function settleDigest(report) { const traces = report.plans; const reached = (state) => traces.filter((p) => p.lifecycle.some((s) => s.state === state)).length; const armed = reached("armed"); const fired = reached("fired"); const expired = traces.filter((p) => p.final_state === "expired").length; const placed = report.orders.length; const filled = report.orders.filter((o) => o.filled).length; return `settle=${report.session.settle_ts}` + ` pnl=${report.totals.realized_floor_usd}` + ` expected=${report.totals.expected_usd}` + ` events=${report.session.bus_events}` + ` plans_armed=${armed} plans_fired=${fired} plans_expired=${expired}` + ` orders_placed=${placed} orders_filled=${filled}`; } function writeReport(report, ctx) { if (ctx.mode === "text") { const lines = [settleDigest(report), ...neverFiredDigestLines(report)]; process.stdout.write(lines.join(` `) + ` `); return; } if (ctx.mode === "human") { renderEpisodeReport(report, ctx); return; } process.stdout.write(JSON.stringify(report, null, 2) + ` `); } async function recordGraded(flags, report, opts) { const registry = await loadHeavy(() => import("./heavy-v95qw596.js")); const dbPath = flags.get("db") ?? DEFAULT_DB; mkdirSync(dirname(dbPath), { recursive: true }); const db = registry.openRegistry(dbPath); try { const { runId } = registry.record(db, report, { plansText: opts.plansText, now: report.session.settle_ts, rUsd: opts.rUsd, calibrated: opts.calibrated, ...opts.reportPath !== undefined ? { reportPath: opts.reportPath } : {} }); process.stderr.write(`session: recorded run ${runId.slice(0, 12)} into ${dbPath} `); } finally { db.close(); } } async function runCommand(argv, ctx, backend) { const { flags, bools } = parseArgs(argv, new Set(["no-record"]), new Set(["bus", "plans", "fill", "r-usd", "tau-hours", "hazard-params", "out", "db"])); const busPath = required(flags, "bus"); const plansPath = required(flags, "plans"); const { fillModel, rUsd, fairTauYears, makerFairParams, out } = parseGradeFlags(flags); const documents = loadDocuments(plansPath); const sessionArgs = { busPath, documents, fillModel, rUsd, ...fairTauYears !== undefined ? { fairTauYears } : {}, ...makerFairParams !== undefined ? { makerFairParams } : {}, ...out !== undefined ? { out } : {} }; const g = await backend.openSession("sim", sessionArgs); if (g.gated) { renderOffer(g.payment, ctx); return EXIT.PAYMENT_REQUIRED; } const { report } = g.value; writeReport(report, ctx); if (!bools.has("no-record")) { await recordGraded(flags, report, { plansText: canonicalPlansText(documents), rUsd, calibrated: makerFairParams !== undefined, ...out !== undefined ? { reportPath: out } : {} }); } return 0; } async function dayCommand(argv, ctx, backend) { const { flags, bools } = parseArgs(argv, new Set(["no-record", "structural", "no-author", "await-author"]), new Set(["bus", "dir", "fill", "r-usd", "tau-hours", "hazard-params", "wakes", "max-wait", "out", "db"])); const busPath = required(flags, "bus"); const dir = required(flags, "dir"); const { fillModel, rUsd, fairTauYears, makerFairParams, out } = parseGradeFlags(flags); let wakes = []; const wakesRaw = flags.get("wakes"); if (wakesRaw !== undefined) { const day = await loadHeavy(() => import("./heavy-v95qw596.js")); wakes = day.parseWakeTimes(wakesRaw); } let maxWaitSec; const maxWaitRaw = flags.get("max-wait"); if (maxWaitRaw !== undefined) { maxWaitSec = Number(maxWaitRaw); if (!Number.isFinite(maxWaitSec) || maxWaitSec <= 0) { throw usageErr(`--max-wait must be a positive number of seconds, got ${JSON.stringify(maxWaitRaw)}`); } } if (bools.has("await-author") && bools.has("no-author")) { throw usageErr("--await-author and --no-author are contradictory: declare at most one (default: refuse promptly on a missing document)."); } const dayArgs = { dir, documents: [], busPath, wakes, structural: bools.has("structural"), fillModel, rUsd, ...fairTauYears !== undefined ? { fairTauYears } : {}, ...makerFairParams !== undefined ? { makerFairParams } : {}, ...maxWaitSec !== undefined ? { maxWaitSec } : {}, ...bools.has("await-author") ? { awaitAuthor: true } : {}, ...bools.has("no-author") ? { noAuthor: true } : {}, ...out !== undefined ? { out } : {} }; const g = await dayHandshakeTyped(() => backend.openDaySession("sim", dayArgs)); if (g.gated) { renderOffer(g.payment, ctx); return EXIT.PAYMENT_REQUIRED; } const { report, plansText, wakes: delivered } = g.value; writeReport(report, ctx); const revised = delivered.filter((w) => w.revised).length; process.stderr.write(`day: ${delivered.length} wake(s), ${revised} revision(s) — settle ${report.session.settle_ts} `); if (!bools.has("no-record")) { await recordGraded(flags, report, { plansText, rUsd, calibrated: makerFairParams !== undefined, ...out !== undefined ? { reportPath: out } : {} }); } return 0; } export { runCommand, dayCommand };