feat(replay): R2 outcomes + calibration metrics #17

Merged
chemavx merged 1 commits from feat/replay-r2-outcomes into main 2026-07-02 20:12:22 +00:00
Owner

R2 — outcomes + métricas de calibración

Puntúa cada estimación archivada contra la realidad — el multiplicador de muestra del plan de fase: Brier/log-loss de estimated_prob benchmarkeado contra el precio de mercado (prior_prob) sobre las mismas filas, para TODAS las evaluaciones con outcome resuelto, no solo los trades ejecutados.

Cambios

  • schema.sql — tabla market_outcomes (1 fila por mercado resuelto; outcome = precio final YES 1.0/0.0, solo finalidad UMA). Idempotente; dry-run BEGIN/ROLLBACK limpio contra prod.
  • bot/outcomes.py — CLI python -m bot.outcomes en dos fases:
    1. Fetch: para cada mercado archivado sin outcome, consulta Gamma vía el get_market_resolution() existente (la misma puerta de finalidad UMA que usa el loop para liquidar posiciones). Abiertos/disputados/ambiguos se reintentan en la siguiente invocación — sin urgencia de pérdida de datos: Gamma reporta resoluciones pasadas en cualquier momento.
    2. Score: Brier micro (por evaluación) y macro (por mercado — el tamaño de muestra honesto dado ~1 eval/min autocorrelacionada), log-loss con clipping 1e-9, desglose por categoría. delta < 0 = el modelo aporta sobre el mercado.
    • --run-id puntúa las re-estimaciones de un replay run en vez del archivo → calibración contrafactual (¿la config X predice mejor que el mercado?).
    • Flags --fetch-only / --metrics-only.
  • db.py — 4 métodos (mercados pendientes, upsert de outcome, cobertura, filas de calibración para archivo o run).
  • tests — 12 nuevos (116/116 en verde); compute_calibration es función pura testeada con literales.

Sin cambio de comportamiento en prod

El bot nunca importa bot.outcomes; la única superficie compartida es la migración idempotente del schema. El freeze de estrategia queda intacto.

🤖 Generated with Claude Code

## R2 — outcomes + métricas de calibración Puntúa cada estimación archivada contra la realidad — el multiplicador de muestra del plan de fase: **Brier/log-loss de `estimated_prob` benchmarkeado contra el precio de mercado (`prior_prob`) sobre las mismas filas**, para TODAS las evaluaciones con outcome resuelto, no solo los trades ejecutados. ### Cambios - **`schema.sql`** — tabla `market_outcomes` (1 fila por mercado resuelto; `outcome` = precio final YES 1.0/0.0, solo finalidad UMA). Idempotente; dry-run BEGIN/ROLLBACK limpio contra prod. - **`bot/outcomes.py`** — CLI `python -m bot.outcomes` en dos fases: 1. *Fetch*: para cada mercado archivado sin outcome, consulta Gamma vía el `get_market_resolution()` existente (la misma puerta de finalidad UMA que usa el loop para liquidar posiciones). Abiertos/disputados/ambiguos se reintentan en la siguiente invocación — sin urgencia de pérdida de datos: Gamma reporta resoluciones pasadas en cualquier momento. 2. *Score*: Brier **micro** (por evaluación) y **macro** (por mercado — el tamaño de muestra honesto dado ~1 eval/min autocorrelacionada), log-loss con clipping 1e-9, desglose por categoría. `delta < 0` = el modelo aporta sobre el mercado. - `--run-id` puntúa las re-estimaciones de un replay run en vez del archivo → **calibración contrafactual** (¿la config X predice mejor que el mercado?). - Flags `--fetch-only` / `--metrics-only`. - **`db.py`** — 4 métodos (mercados pendientes, upsert de outcome, cobertura, filas de calibración para archivo o run). - **tests** — 12 nuevos (**116/116 en verde**); `compute_calibration` es función pura testeada con literales. ### Sin cambio de comportamiento en prod El bot nunca importa `bot.outcomes`; la única superficie compartida es la migración idempotente del schema. El freeze de estrategia queda intacto. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
chemavx added 1 commit 2026-07-02 20:10:13 +00:00
Scores every archived estimate against reality — the sample multiplier
the phase plan calls for: Brier/log-loss of estimated_prob benchmarked
against the market price (prior_prob) on the same rows, over ALL
evaluations with a resolved outcome, not just executed trades.

- schema.sql: market_outcomes (one row per resolved market; outcome =
  final YES price 1.0/0.0, UMA-final only)
- bot/outcomes.py: CLI (python -m bot.outcomes) with two phases —
  fetch resolutions for archived markets via the existing
  get_market_resolution() (open/disputed/ambiguous markets simply retry
  next invocation; no data-loss urgency, Gamma reports past resolutions
  at any time), then compute calibration: Brier micro (per evaluation) /
  macro (per market — the honest sample size given ~1 eval/min
  autocorrelation), log-loss with 1e-9 clipping, per-category breakdown.
  --run-id scores a replay run's re-estimates instead of the archive
  (counterfactual calibration).
- db.py: 4 accessors (pending markets, outcome upsert, coverage,
  calibration rows for archive or run)
- tests: 12 new (116 total green); compute_calibration is a pure
  function driven by literals

No prod behavior change: the bot never imports bot.outcomes; the only
shared surface is the idempotent schema migration (dry-run BEGIN/ROLLBACK
clean against prod).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
chemavx merged commit 2b326ad54f into main 2026-07-02 20:12:22 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chemavx/polymarket-bot#17