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.

396 lines 26.9 kB
/** * # session/grid — the Simulate config-comparison harness: buildGrid + CellAggregate + leaderboard (kestrel-5zl.8) * * THE POINT of Simulate: the SAME recorded tape graded under N configs → a GRID of graded * {@link import("../blotter").Blotter}s → a pure comparison LEADERBOARD. This module is the two PURE * derivations that turn a set of FINALIZED Blotters into that grid + table — no wall clock, no RNG * (RUNTIME §0) — and it is a MEASUREMENT / reporting layer: it only READS the finalized record, and never * writes a byte back onto the graded bus or the Blotter (zero golden / e2e churn), and stamps NO new schema * field. It builds strictly on the run-identity layer (5zl.7 {@link cellOf}) + the config layer (5zl.6): * * 1. {@link buildGrid} — `(runs: readonly Blotter[]) → Grid`. Group the finalized Blotters by their 5zl.7 * {@link cellOf} CellKey (tape × fill_model × config-ConfigId). Runs sharing a CellKey are REPLICATES in * one comparison cell; each replicate keeps a DISTINCT SimRunId, read straight off the finalized record * as `blotter.session.bus.sha256` (which equals `SimRunId(gradedBus)` — the 5zl.7 pure-read * reconciliation, so no raw bus is needed). Each cell is a {@link CellAggregate} over its replicate runs. * * 2. {@link CellAggregate} — the honest measurements across a cell's replicate runs, using the Session/day * (one finalized Blotter = one run) as the INDEPENDENT EVIDENCE UNIT, and REPORTING UNCERTAINTY: every * numeric axis is a {@link Dist} — `{ n, mean, min, max, stdev }` — a distribution/spread over the * replicates, NEVER a single cherry-picked point (a single-run cell reports `n = 1`, spread `0` — still a * distribution, never a bare scalar). The axes come straight off the Blotter: financial (EV / P&L), risk, * process, fidelity, provider, cost — plus a {@link CertificationBreakdown}. * * 3. {@link leaderboard} — `(grid: Grid) → readonly LeaderboardRow[]`. A pure comparison table: ONE ROW PER * CELL, the honest multi-axis measurements reported SIDE BY SIDE with per-axis uncertainty, and NO opaque * omnibus score (the m9i principle: "report the financial, risk, process, attention, provider, and * interface measurements WITHOUT an opaque omnibus score"). The axes are laid out; they are never blended * into one number, and never sorted into a rank — the caller reads the axes it cares about. * * ## Determinism (RUNTIME §0 — a CI invariant) * Both derivations are PURE and INPUT-ORDER-INSENSITIVE: the same runs in ANY order ⇒ a byte-identical grid * and table. buildGrid sorts the cells by CellKey and each cell's replicates by SimRunId BEFORE any * aggregation, so every reduction (mean, stdev, …) folds over a FIXED order — no order-dependent float drift. * * ## Honesty (the 5zl.8 mandate) * The config axis of a cell is the FULL ConfigId (`session.config_id`, m9i.2 owner tweak) — a PROVISIONAL * run keys by its own stamped ConfigId (or, absent any config identity, the NO_ENVELOPE sentinel), so it * lands in its OWN cell, distinct from every differently-configured cell, and can NEVER be silently absorbed * into a certified cell's numbers (a provisional and a certified run can only share a cell by sharing the * ENTIRE config — and an identical config yields an identical completeness verdict). The cell's * {@link CertificationBreakdown} carries the certified/provisional COUNTS and a WORST-CASE verdict * (provisional if ANY replicate is provisional) — the projector's grade is surfaced, never laundered. * Provider / cost read the run's `session.envelope`, absent (`null`) for a no-envelope / provisional cell — * an honest gap, never a fabricated identity. */ import type { Blotter, ExperimentalEnvelope, FidelitySelfLimitation, Verdict } from "../blotter/index.ts"; /** * The distribution of one numeric measurement over a cell's replicate runs — the honest unit of the * leaderboard. `n` is the number of independent evidence units (Session/day runs) the measurement rests on; * `mean` is their arithmetic mean; `min`/`max`/`stdev` are the SPREAD — the uncertainty around the mean. * A single-run cell still reports a Dist (`n = 1`, `min = max = mean`, `stdev = 0`) — never a bare scalar, so * a consumer can never mistake one run for a converged estimate. `stdev` is the POPULATION standard deviation * (divide by `n`, not `n − 1`): a descriptive spread of the runs in hand, not an inferential estimator. */ export interface Dist { /** The number of replicate runs (Session/day evidence units) this distribution rests on. */ readonly n: number; /** The arithmetic mean of the per-run measurements. */ readonly mean: number; /** The smallest per-run measurement (the low end of the spread). */ readonly min: number; /** The largest per-run measurement (the high end of the spread). */ readonly max: number; /** The population standard deviation of the per-run measurements (0 for a single-run cell). */ readonly stdev: number; } /** Summarize a fixed-order list of per-run measurements as a {@link Dist}. PURE — folds in the caller's * (deterministic) order, so the same values always yield byte-identical floats. `values` is never empty (a * cell always holds ≥ 1 run). Exported so other measurement layers (e.g. the percept-lab score log, * kestrel-m9i.12) fold their replicate probes with the SAME semantics and their rows port into this grid. */ export declare function distOf(values: readonly number[]): Dist; /** * The cell underlier's price series over the horizon plus the units held — the source of the buy-and-hold * BASELINE (kestrel-m9i.19). The driver extracts the open → close SPOT series of the cell underlier from the * cell tape and hands it in (grid never reaches into the bus): `prices[0]` is the OPEN, `prices[last]` the * CLOSE, and `qty` the units held across the horizon. `symbol` is the underlier (SPY for an equity basket, BTC * for crypto — §4.1 public benchmark vocabulary), surfaced onto the {@link Benchmark} for provenance. */ export interface UnderlierHold { /** The underlier symbol held over the horizon (SPY for an equity basket, BTC for crypto — §4.1). */ readonly symbol: string; /** The underlier price series over the cell horizon: `[0]` = open, `[last]` = close (read off the cell tape). */ readonly prices: readonly number[]; /** The units of the underlier held across the horizon. */ readonly qty: number; } /** * The buy-and-hold P&L of an underlier over the horizon (kestrel-m9i.19): `qty × (close − open)`, where * `open = prices[0]` and `close = prices[last]`. PURE + byte-stable (no wall clock, no RNG — RUNTIME §0): the * interior prints don't matter, the hold is open → close and `qty` scales it linearly. FAIL-CLOSED — an * underlier price the baseline needs but cannot resolve (an empty series, or a non-finite open / close / qty) * is a typed refusal, NEVER a silent 0 (a silent 0-alpha would launder market direction as judgment). */ export declare function buyAndHoldBaseline(hold: UnderlierHold): number; /** The benchmark sub-axis of the financial axis (kestrel-m9i.19): the per-cell buy-and-hold BASELINE plus the * benchmark-relative ALPHA, reported ALONGSIDE the absolute `expected` EV (never replacing it). Position / * swing / crypto cells are BETA-dominated — absolute P&L there measures market DIRECTION, not judgment — so * this rides the cell EV against a buy-and-hold of the cell underlier (SPY for an equity basket, BTC for * crypto — §4.1) over the cell horizon. Present ONLY when a per-cell hold is supplied to {@link buildGrid}; * ABSENT (the field is not stamped) otherwise, so an un-baselined cell is byte-identical to today's grid. */ export interface Benchmark { /** The underlier held over the horizon for the baseline (SPY for equity, BTC for crypto — §4.1). */ readonly symbol: string; /** The buy-and-hold P&L of that underlier over the horizon ({@link buyAndHoldBaseline}) — a scalar $ amount, * the provenance `alpha` is measured against (mirrors 5zl.16.8 `InstanceFinancial.baseline`). */ readonly baseline: number; /** The benchmark-relative alpha as a {@link Dist} over the replicates: `alpha_i = expected_i − baseline`, so * `alpha.mean = cell EV − baseline` (the 5zl.16.8 identity), reported WITH grid-consistent uncertainty. */ readonly alpha: Dist; } /** The financial (EV / P&L) axis — the conservative definite-fill floor and the expected total, plus the * expected-$ partitioned by fill support (the `calibrated` slice a grader banks vs the `extrapolated` slice it * refuses to bank, 9gu.3). Each a distribution over the cell's replicate runs. */ export interface FinancialAxis { /** `totals.floor` — realized / definite-fill $ — across the replicates. */ readonly floor: Dist; /** `totals.expected` — E[$] — across the replicates. */ readonly expected: Dist; /** The `calibrated`-support slice of `totals.expected` (a grader banks this). */ readonly calibrated: Dist; /** The `extrapolated`-support slice of `totals.expected` (a grader refuses to bank this). */ readonly extrapolated: Dist; /** The per-cell benchmark baseline + benchmark-relative alpha (kestrel-m9i.19), reported ALONGSIDE the * absolute `expected` EV. Present ONLY when a per-cell hold is supplied to {@link buildGrid}; the field is * OMITTED otherwise (no grid churn — an un-baselined cell is byte-identical to today's). */ readonly benchmark?: Benchmark; } /** The risk axis — the headline taint and the far-OTM directional-cap disposition (9gu.6). Reported as honest * counts / a union of reasons across the cell's replicate runs (categorical, not a numeric distribution). */ export interface RiskAxis { /** How many replicate runs carried a TAINTED headline (`totals.headline.tainted`). */ readonly tainted_runs: number; /** The union of `totals.headline.reasons` across the replicates, de-duplicated and sorted (deterministic). */ readonly headline_reasons: readonly string[]; /** The far-OTM directional-cap disposition tallied over every order in every replicate run (9gu.6). */ readonly directional_cap: { readonly applied: number; readonly exempt: number; readonly na: number; }; } /** The process axis — the shape of the run's activity (orders, fills, reprices, plans), each a distribution * over the cell's replicate runs. */ export interface ProcessAxis { /** The placed-order count per run. */ readonly orders: Dist; /** The definite-fill count per run (`orders[].filled`). */ readonly fills: Dist; /** Σ `orders[].reprice_count` per run — the cancel/replace churn. */ readonly reprices: Dist; /** The plan-record count per run. */ readonly plans: Dist; } /** The fidelity axis — the realism `level` breakdown plus the judge's self-limitation (what the fill model * structurally could NOT observe). The self-limitation is invariant across a cell (the fill model is a CellKey * axis), so it is reported once. */ export interface FidelityAxis { /** The count of replicate runs at each fidelity level (e.g. `{ modeled: 3 }`) — the level breakdown. */ readonly levels: Readonly<Record<string, number>>; /** The judge's self-limitation (fill model + what it could not observe) — invariant across the cell. */ readonly self_limitation: FidelitySelfLimitation; } /** The cost axis — the INJECTED token accounting (`session.envelope.token_accounting`), each a distribution * over the cell's replicate runs. Config-level in the current schema (constant across a cell's replicates), so * the spread is `0` — reported honestly as a Dist all the same. */ export interface CostAxis { readonly input: Dist; readonly output: Dist; readonly thinking: Dist; } /** The certification breakdown of a cell — the projector's grade, surfaced, never laundered: the * certified/provisional replicate COUNTS plus a WORST-CASE verdict (provisional if ANY replicate is * provisional). A provisional run is thus never rendered as if certified. */ export interface CertificationBreakdown { /** How many replicate runs the projector graded `certified`. */ readonly certified: number; /** How many replicate runs the projector graded `provisional`. */ readonly provisional: number; /** The cell's worst-case verdict: `provisional` if any replicate is provisional, else `certified`. */ readonly verdict: Verdict; } /** The rankable breakdown of a cell (kestrel-m9i.25) — the DERIVED leaderboard-ELIGIBILITY axis, surfaced * DISTINCTLY from {@link CertificationBreakdown}. The two are ORTHOGONAL: a cell can be * `certification.verdict === "certified"` yet `rankable.verdict === false` (a certified PRE-cutoff cell). * The rankable/not-rankable replicate COUNTS plus a WORST-CASE verdict — the cell is rankable ONLY if EVERY * replicate is rankable (one not-rankable replicate makes the cell not rankable), mirroring the * worst-case discipline of the certification breakdown. */ export interface RankableBreakdown { /** How many replicate runs the projector derived `rankable`. */ readonly rankable: number; /** How many replicate runs the projector derived NOT rankable. */ readonly not_rankable: number; /** The cell's worst-case verdict: `true` only if every replicate is rankable, else `false`. */ readonly verdict: boolean; } /** * The aggregate of ONE comparison cell — the honest, multi-axis measurements over the cell's replicate runs, * each reported WITH uncertainty (a {@link Dist} for every numeric axis) and keyed to the cell's 5zl.7 * CellKey. Deliberately carries NO blended / omnibus score: the axes stand side by side (the m9i principle). */ export interface CellAggregate { /** The 5zl.7 CellKey (tape × fill_model × config-ConfigId) this cell aggregates — its stable identity. */ readonly cell: string; /** The number of replicate runs (Session/day evidence units) in this cell. */ readonly runs: number; /** The DISTINCT SimRunIds of the replicates (= `session.bus.sha256`), sorted for a byte-stable order. */ readonly runIds: readonly string[]; /** The financial (EV / P&L) axis. */ readonly financial: FinancialAxis; /** The risk axis (headline taint + directional-cap disposition). */ readonly risk: RiskAxis; /** The process axis (orders / fills / reprices / plans). */ readonly process: ProcessAxis; /** The fidelity axis (level breakdown + judge self-limitation). */ readonly fidelity: FidelityAxis; /** The provider axis — the a57.14 experimental envelope (the author's identity), invariant across the cell, * or `null` for a no-envelope cell (an honest gap, never a fabricated identity). */ readonly provider: ExperimentalEnvelope | null; /** The cost axis (injected token accounting), or `null` when the cell declares no envelope. */ readonly cost: CostAxis | null; /** The certification breakdown — the projector's grade, surfaced. */ readonly certification: CertificationBreakdown; /** The rankable breakdown (kestrel-m9i.25) — the DERIVED leaderboard-eligibility axis, surfaced DISTINCTLY * from {@link certification} (a certified cell can be not rankable). */ readonly rankable: RankableBreakdown; } /** The config-comparison GRID: the deterministically ordered set of {@link CellAggregate}s, one per distinct * CellKey. Cells are sorted by CellKey so the grid is byte-stable regardless of input order. */ export interface Grid { readonly cells: readonly CellAggregate[]; } /** * The ADDITIVE options of {@link buildGrid} (kestrel-m9i.19): a per-cell buy-and-hold BASELINE source, keyed by * the 5zl.7 {@link cellOf} CellKey (the tape axis already identifies the cell underlier). A cell WITH a supplied * hold gets a `financial.benchmark` (baseline + alpha); a cell WITHOUT one is byte-identical to today's grid. * The whole options object is OPTIONAL — `buildGrid(runs)` and `buildGrid(runs, {})` are byte-identical to each * other and to today's grid (no churn). */ export interface BuildGridOptions { /** Per-cell (CellKey → {@link UnderlierHold}) — the buy-and-hold source for that cell's benchmark baseline. */ readonly baselines?: ReadonlyMap<string, UnderlierHold>; } /** * Group a set of FINALIZED Blotters into the config-comparison {@link Grid} (kestrel-5zl.8). Each run is keyed * by its 5zl.7 {@link cellOf} CellKey (tape × fill_model × config-ConfigId); runs sharing a key are REPLICATES * aggregated into one {@link CellAggregate} (each keeping a distinct SimRunId). PURE and * INPUT-ORDER-INSENSITIVE: cells are sorted by CellKey and each cell's replicates by SimRunId before any * aggregation, so the same runs in ANY order yield a byte-identical grid (RUNTIME §0). Reads finalized * Blotters only — writes no bus/Blotter byte, stamps no schema field. * * ADDITIVE (kestrel-m9i.19): the optional 2nd arg supplies a per-cell buy-and-hold BASELINE. A cell whose * CellKey appears in `opts.baselines` gets a `financial.benchmark` (the baseline + benchmark-relative alpha, * ALONGSIDE absolute EV); every other cell — and the whole grid when no options are supplied — is BYTE-IDENTICAL * to today's. The baseline touches neither CellKey nor SimRunId nor the leaderboard row shape. FAIL-CLOSED: an * unresolvable supplied underlier price propagates {@link buyAndHoldBaseline}'s typed refusal (never a silent 0). */ export declare function buildGrid(runs: readonly Blotter[], opts?: BuildGridOptions): Grid; /** One row of the {@link leaderboard} — one comparison cell's honest measurements laid out SIDE BY SIDE with * per-axis uncertainty. Deliberately carries NO omnibus / composite / rank field (the m9i principle). */ export interface LeaderboardRow { /** The 5zl.7 CellKey this row reports on. */ readonly cell: string; /** The replicate (Session/day evidence-unit) count behind this row's measurements. */ readonly runs: number; /** The distinct SimRunIds of the replicates (provenance for the row's numbers). */ readonly runIds: readonly string[]; /** The financial axis, WITH uncertainty. */ readonly financial: FinancialAxis; /** The risk axis. */ readonly risk: RiskAxis; /** The process axis, WITH uncertainty. */ readonly process: ProcessAxis; /** The fidelity axis. */ readonly fidelity: FidelityAxis; /** The provider (envelope identity) axis, or `null`. */ readonly provider: ExperimentalEnvelope | null; /** The cost axis, WITH uncertainty, or `null`. */ readonly cost: CostAxis | null; /** The certification breakdown — a provisional cell is surfaced as provisional, never as certified. */ readonly certification: CertificationBreakdown; /** The rankable breakdown (kestrel-m9i.25) — leaderboard ELIGIBILITY, a DISTINCT axis from * {@link certification}: a row can be `certification.verdict === "certified"` yet `rankable.verdict === false`. */ readonly rankable: RankableBreakdown; } /** * Project a {@link Grid} into the comparison LEADERBOARD (kestrel-5zl.8): ONE ROW PER CELL, the honest * multi-axis measurements reported SIDE BY SIDE with per-axis uncertainty, and NO opaque omnibus score — the * axes are laid out, never blended into one number and never sorted into a rank (the m9i principle). PURE and * deterministic: the row order mirrors the grid's (CellKey-sorted), so the same grid always yields a * byte-identical table. */ export declare function leaderboard(grid: Grid): readonly LeaderboardRow[]; /** * One link of the Instance's chained-cash ledger — session `ordinal`'s place in the running P&L chain, a PURE * read of the finalized per-session Blotter. `openingCash` is the cash session N+1 OPENS from (= session N's * `closingCash`), `realized` is the session's definite-fill floor (`totals.floor`), and `closingCash = * openingCash + realized`. This re-derives, purely from the ordered Blotters, the exact chain `carry.ts` * threads (`carry.cash = prior.cash + settle.floorTotal`, and `settle.floorTotal === totals.floor`). */ export interface SessionLink { /** The session ordinal `k` (its position in the ordered sequence). */ readonly ordinal: number; /** The session's {@link SimRunId} (`session.bus.sha256`) — provenance for this link of the chain. */ readonly runId: string; /** The cash this session OPENS from — session `k-1`'s `closingCash` (`0` at the sequence origin). */ readonly openingCash: number; /** The session's realized / definite-fill P&L (`totals.floor`) — the chain increment. */ readonly realized: number; /** The cash this session CLOSES at — `openingCash + realized`, carried into session `k+1`'s open. */ readonly closingCash: number; } /** * The Instance's financial axis — the chained cash of the whole horizon plus the benchmark-relative ALPHA * hook. `cash` is the final running cash of the chain (`Σ per-session realized floor`); `instanceEV` is the * chained expected value (`Σ totals.expected`); `alpha = instanceEV − baseline` is the honest judgment axis * (ONE measure alongside `cash`/`instanceEV`, never a top-level collapse), and `baseline` is surfaced as the * provenance of that alpha. A missing / non-finite baseline is a typed refusal, never a silent 0-alpha default. */ export interface InstanceFinancial { /** The chained cash of the whole horizon (`Σ per-session realized floor` = the final `closingCash`). */ readonly cash: number; /** The chained expected value of the whole horizon (`Σ totals.expected`). */ readonly instanceEV: number; /** The benchmark-relative alpha: `instanceEV − baseline` (one honest axis, never raw EV, never raw beta). */ readonly alpha: number; /** The supplied benchmark expected value (in $) alpha is measured against — the provenance of `alpha`. */ readonly baseline: number; } /** * The sequence-level GRADE of an Instance — the honest multi-axis measurements over the ordered sequence, * each an axis reported SIDE BY SIDE, with NO opaque omnibus score (the m9i principle). The `financial` axis * is the CHAINED, benchmark-relative {@link InstanceFinancial}; the non-financial axes * (risk/process/fidelity/provider/cost/certification) reuse the EXISTING grid axes ({@link aggregateCell}) * over the sessions-as-replicate-runs, so a length-1 Instance's non-financial axes are BYTE-IDENTICAL to * today's single-Session grid cell. */ export interface InstanceGrade { /** The chained + benchmark-relative financial axis. */ readonly financial: InstanceFinancial; /** The risk axis (headline taint + directional-cap disposition) over the sessions. */ readonly risk: RiskAxis; /** The process axis (orders / fills / reprices / plans) over the sessions. */ readonly process: ProcessAxis; /** The fidelity axis (level breakdown + judge self-limitation) over the sessions. */ readonly fidelity: FidelityAxis; /** The provider axis — the a57.14 experimental envelope, or `null` for a no-envelope Instance. */ readonly provider: ExperimentalEnvelope | null; /** The cost axis (injected token accounting), or `null` when no envelope is declared. */ readonly cost: CostAxis | null; /** The certification breakdown — the projector's grade over the sessions, surfaced. */ readonly certification: CertificationBreakdown; } /** * The aggregate of ONE multi-session **Instance** (kestrel-5zl.16.8): the ORDERED sequence of per-session * {@link SessionLink}s (the chained-cash ledger) plus the sequence-level {@link InstanceGrade}, keyed by the * Instance's 5zl.16.5 identity. Deliberately carries NO blended / omnibus score — the axes stand side by side * (the m9i principle); alpha is ONE honest axis inside `financial`, never a collapse. */ export interface InstanceBlotter { /** The whole Instance's identity — `sha256` of the ORDERED per-session SimRunIds (kestrel-5zl.16.5). */ readonly instanceRunId: string; /** The Instance's sequence CELL key — the ordered per-session {@link cellOf} keys (length-1 unchanged). */ readonly sequenceCellKey: string; /** The ordered chained-cash ledger — one {@link SessionLink} per session, in SEQUENCE order. */ readonly sessions: readonly SessionLink[]; /** The sequence-level grade — honest multi-axis, chained financial + benchmark-relative alpha, NO omnibus. */ readonly grade: InstanceGrade; } /** Build options for {@link buildInstanceBlotter} — the supplied benchmark against which alpha is measured. */ export interface BuildInstanceBlotterOptions { /** The benchmark expected value (in $) alpha subtracts from `instanceEV`. Required + finite (fail-closed). */ readonly baseline: number; } /** * Fold the ORDERED per-session Blotters of a multi-session Instance into ONE {@link InstanceBlotter} * (kestrel-5zl.16.8) — a PURE read of the finalized sequence (no wall clock, no RNG — RUNTIME §0; no bus / * Blotter byte written, no schema field stamped). Where {@link buildGrid} folds order-INSENSITIVE REPLICATES * into a distribution, this folds an order-SENSITIVE SEQUENCE into one CHAINED record — the ordering IS the * semantics. Three things: * * 1. CHAINS per-session cash across the sequence: session N+1 OPENS from session N's carried cash * (`openingCash[k] = closingCash[k-1] = Σ_{j<k} realized_j`, `realized_k = totals.floor`), exactly * re-deriving the chain `carry.ts` threads (`carry.cash = prior.cash + settle.floorTotal`). Deterministic * + byte-stable: the ledger folds in SEQUENCE order (no clock, no RNG). `grade.financial.cash` is the * final running cash. * 2. a sequence-level GRADE — the financial axis chained; the non-financial axes reuse the EXISTING grid * axes ({@link aggregateCell}) over the sessions-as-replicate-runs, so a LENGTH-1 Instance's non-financial * axes are BYTE-IDENTICAL to `buildGrid([bl]).cells[0]` (NO existing-grid churn). NO opaque omnibus score. * 3. a benchmark-relative ALPHA hook — `alpha = instanceEV − baseline`, `instanceEV = Σ totals.expected`. * alpha lives INSIDE the financial axis, one honest measure — never a collapsed single score. * * FAIL-CLOSED: an empty (unstitchable) sequence, or a missing / non-finite baseline, is a typed refusal — * never a silent default (no silent 0-alpha). */ export declare function buildInstanceBlotter(orderedBlotters: readonly Blotter[], opts: BuildInstanceBlotterOptions): InstanceBlotter; //# sourceMappingURL=grid.d.ts.map