feat(bot): 5-phase strategy upgrade — edge neto, families, GNews priority, regimes
CI/CD / build-and-push (push) Successful in 2m30s
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:
+36
-3
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user