feat(bot): 5-phase strategy upgrade — edge neto, families, GNews priority, regimes
CI/CD / build-and-push (push) Successful in 2m30s

Phase 1 — Edge neto real (paper.py, bayesian.py, risk/manager.py, db.py):
- Trade records now store edge_gross, edge_net, prior_prob, final_prob,
  mid_price, spread_estimate, commission, family_key
- edge_net = edge_gross - SPREAD_ESTIMATE(0.02) - COMMISSION_RATE(0.02)
  NOTE: both constants are heuristics, not exact Polymarket exchange costs
- Execution gate changed from edge_gross > MIN_EDGE to edge_net > regime_min_edge

Phase 2 — Market families (polymarket.py):
- market_family_key(market) groups related markets:
    texas-republican-2026, fed-april-2026, openai-2026, etc.
- At most 1 trade per family per cycle; occupied_families propagated via main.py
- Family key logged on every TRADE and SKIP line

Phase 3 — GNews priority (news.py, bayesian.py, main.py):
- NewsClient.get_freshness() returns 1.0/0.75/0.40/0.10 by cache age
- gnews_priority(market, news) = uncertainty × volume_score × freshness
- Politics markets sorted by priority DESC before eval so best markets get
  the 5-query/cycle GNews budget first

Phase 4 — Regime min-edge by category/horizon (bayesian.py):
- politics >60d → 0.12, 30-60d → 0.10, <30d → 0.08
- tech / crypto/finance → 0.10
- All thresholds applied to edge_net (not edge_gross)

Phase 5 — Observability (bayesian.py, main.py):
- Structured skip labels: SKIP_UNSUPPORTED, SKIP_NO_SIGNALS,
  SKIP_PRIOR_EXTREME, SKIP_FAMILY, SKIP_GNEWS_PRIORITY, SKIP_EDGE_NET
- TRADE lines now include family_key, edge_gross, edge_net, regime_min, days
- schema.sql: 8 new cols on trades, 7 new cols on signals (via ALTER TABLE IF NOT EXISTS)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
chemavx
2026-04-16 15:34:46 +00:00
parent a0cbdc0256
commit 63d9f637ff
8 changed files with 620 additions and 141 deletions
+36 -3
View File
@@ -6,7 +6,7 @@ All trades are logged to PostgreSQL for metrics analysis.
"""
import logging
import uuid
from dataclasses import dataclass
from dataclasses import dataclass, field
from datetime import datetime, UTC
from typing import Optional
@@ -15,7 +15,10 @@ from bot.data.db import Database
log = logging.getLogger(__name__)
POLYMARKET_FEE = 0.02 # 2% fee on each trade
# Polymarket taker fee used for paper simulation.
# Also stored as commission in each Trade for audit purposes.
# NOTE: this is a heuristic — see COMMISSION_RATE in bayesian.py for context.
POLYMARKET_FEE = 0.02 # 2%
@dataclass
@@ -32,11 +35,27 @@ class Trade:
timestamp: datetime
reasoning: str
paper: bool = True
# ── Phase 1: edge neto audit fields ──────────────────────────────────────
# edge_gross: raw model edge before any cost deductions
# edge_net: edge_gross - spread_estimate - commission/size_usdc
# Both are heuristic estimates — see schema.sql comment for details.
edge_gross: float = 0.0
edge_net: float = 0.0
prior_prob: float = 0.0 # market.yes_price clamped, before Bayesian update
final_prob: float = 0.0 # estimated probability after all signals
# mid_price: order-book midpoint when available; falls back to market.yes_price
mid_price: float = 0.0
spread_estimate: float = 0.02
commission: float = 0.0 # = POLYMARKET_FEE * size_usdc
# ── Phase 2: market family ────────────────────────────────────────────────
family_key: str = ""
def __str__(self) -> str:
return (
f"[PAPER] {self.direction} {self.shares:.1f} shares @ {self.entry_price:.3f} "
f"= ${self.net_cost:.2f} (fee ${self.fee_usdc:.2f}) | {self.question[:40]}"
f"= ${self.net_cost:.2f} (fee ${self.fee_usdc:.2f}) "
f"edge_net={self.edge_net:+.3f} family={self.family_key} "
f"| {self.question[:40]}"
)
@@ -102,6 +121,10 @@ class PaperExecutor:
net_cost = order.size_usdc + fee
shares = order.size_usdc / entry_price
# commission mirrors the heuristic COMMISSION_RATE applied in bayesian.py
# when computing edge_net. Stored for audit: confirms cost assumption held.
commission = order.size_usdc * POLYMARKET_FEE # = fee_usdc at current rate
trade = Trade(
id=str(uuid.uuid4()),
market_id=order.market_id,
@@ -115,6 +138,16 @@ class PaperExecutor:
timestamp=datetime.now(UTC),
reasoning=order.reasoning,
paper=True,
# Phase 1 audit fields
edge_gross=order.edge_gross,
edge_net=order.edge_net,
prior_prob=order.prior_prob,
final_prob=order.final_prob,
mid_price=order.mid_price,
spread_estimate=order.spread_estimate,
commission=commission,
# Phase 2 family
family_key=order.family_key,
)
# Update paper portfolio