feat(manifold): add persistent cooldowns to reduce redundant evaluations
CI/CD / build-and-push (push) Successful in 8s
CI/CD / build-and-push (push) Successful in 8s
The trading loop re-evaluated the same ~22 politics/tech markets every ~60s,
flooding manifold_match_audit with ~76k rows (~3,500 attempts/market) of which
none carried new information, making the metrics uninterpretable.
Add per-market persistent cooldowns:
- New table manifold_eval_cooldown (poly_market_id PK, last_evaluated_at,
last_status, retry_after, cooldown_reason) created via run_migrations.
- bayesian.evaluate() consults the cooldown BEFORE calling the matcher and skips
the call entirely while now() < retry_after — no matcher call, no audit row,
no signal (equivalent to no_results). After a real evaluation it upserts the
cooldown with a verdict-dependent backoff: no_results/low_score/outcome_mismatch/
ambiguous_inversion -> 24h, conditional_market -> 7d, accepted -> 1h.
- manifold.py stays a pure client/matcher with no DB access.
- New db methods get_manifold_cooldown / upsert_manifold_cooldown.
- /api/metrics/manifold-matches summary gains unique_markets
{evaluated, accepted, coverage_rate} for per-market (not per-attempt) coverage.
Matching logic, MANIFOLD_MATCHER_VERSION, MANIFOLD_LOGODDS_WEIGHT, edge/exposure
thresholds and existing audit rows are unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
df988a36b6
commit
98abd96fd2
@@ -291,3 +291,29 @@ CREATE TABLE IF NOT EXISTS checkpoint_alerts (
|
||||
fired_at TIMESTAMPTZ NOT NULL,
|
||||
last_fired_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────────────────────
|
||||
-- Manifold evaluation cooldown — per-market backoff for the Manifold matcher
|
||||
--
|
||||
-- The trading loop re-evaluates the same ~stable set of politics/tech markets
|
||||
-- every cycle (~60s). Most resolve to a stable terminal verdict (no Manifold
|
||||
-- coverage, low-score, outcome mismatch, conditional market) that will not change
|
||||
-- on the next cycle. Re-querying them every minute floods manifold_match_audit
|
||||
-- with redundant rows and makes the metrics uninterpretable.
|
||||
--
|
||||
-- This table records, per poly_market_id, when the market was last evaluated and
|
||||
-- the earliest time it should be evaluated again (retry_after). evaluate() in
|
||||
-- bot/strategy/bayesian.py consults it BEFORE calling the matcher and skips the
|
||||
-- call (and the audit write) entirely while now() < retry_after.
|
||||
--
|
||||
-- last_status / cooldown_reason are stored for observability only.
|
||||
-- ─────────────────────────────────────────────────────────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS manifold_eval_cooldown (
|
||||
poly_market_id TEXT PRIMARY KEY,
|
||||
last_evaluated_at TIMESTAMPTZ NOT NULL,
|
||||
last_status TEXT NOT NULL,
|
||||
retry_after TIMESTAMPTZ NOT NULL,
|
||||
cooldown_reason TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_mfld_cooldown_retry ON manifold_eval_cooldown(retry_after);
|
||||
|
||||
Reference in New Issue
Block a user