#!/usr/bin/env npx tsx /** * CLI: backtest GEX/VEX integrity by replaying chains as-of a timestamp. * * npx tsx scripts/dealer-map-replay.ts --symbol IREN --as-of 2026-08-07T13:14:00.000Z * npx tsx scripts/dealer-map-replay.ts --symbol IREN --from-snapshots --days 7 * * Exit 1 if integrity incomplete or snapshot drift too large. */ import { DatabaseSync } from 'node:sqlite'; import { resolve } from 'node:path'; import { replayDealerMapAt, replayFromSnapshots } from '../src/analysis/dealerMapReplay.ts'; function arg(name: string): string | undefined { const i = process.argv.indexOf(name); if (i < 0 || i + 1 >= process.argv.length) return undefined; return process.argv[i + 1]; } function has(name: string): boolean { return process.argv.includes(name); } const symbol = (arg('--symbol') ?? 'IREN').toUpperCase(); const asOf = arg('--as-of'); const days = Number(arg('--days') ?? '7'); const fromSnapshots = has('--from-snapshots'); const dbPath = arg('--db') ?? resolve(process.cwd(), 'data/investor-flow.db'); const db = new DatabaseSync(dbPath, { readOnly: true }); function printResult(r: ReturnType) { console.log('---'); console.log(r.symbol, r.asOf); console.log(' ok:', r.ok, '|', r.integrity.status); console.log(' ', r.summary); if (r.map?.levels.king) { console.log( ' king:', r.map.levels.king.strike, r.map.levels.king.expiry, `gex=${(r.map.levels.king.gex / 1000).toFixed(1)}K`, ); } console.log( ' metrics:', JSON.stringify(r.integrity.metrics), ); const fails = r.integrity.checks.filter((c) => !c.ok); if (fails.length) { console.log(' failed checks:'); for (const c of fails) { console.log(` [${c.level}] ${c.id}: ${c.detail}`); } } } let anyFail = false; if (fromSnapshots) { const results = replayFromSnapshots(db, symbol, days); if (results.length === 0) { console.error('No snapshots for', symbol); process.exit(2); } for (const r of results) { printResult(r); if (!r.ok) anyFail = true; } } else if (asOf) { const r = replayDealerMapAt(db, symbol, asOf); printResult(r); if (!r.ok) anyFail = true; } else { console.error('Usage: --symbol SYM --as-of ISO | --from-snapshots [--days N] [--db path]'); process.exit(2); } db.close(); process.exit(anyFail ? 1 : 0);