-
Notifications
You must be signed in to change notification settings - Fork 0
Data Model
Pantheon has two data contracts: the in-process typed contract (core/types.py — the only way agents talk) and the persistence schema (Supabase PostgreSQL + pgvector, plus a local SQLite fallback for dev).
The single source of truth for every inter-agent structure. Adding a field here is the only way to change the pipeline contract.
| Dataclass | Produced by | Carries |
|---|---|---|
RawSignal |
Icarus | signal_id, source_url, headline, summary, published_at, category, severity, affected_tickers, supplier |
FilteredSignal |
Hades | wraps RawSignal + compliance_score, esg_flag, ofac_flag, downgraded, notes |
MacroContext |
Artemis | regime, vix, sp500_1m_return, sector_momentum, suppress, suppress_reason |
SizedSignal |
Pythia | wraps FilteredSignal + macro, confidence, position_size_pct, skip, is_exploration |
TradeResult |
Ares | order_id, symbol, side, fill_price, qty, stop_loss_price, take_profit_price, pnl_pct, status |
DecisionTrace |
ZEUS | full per-signal audit: every stage outcome + LLM reasoning + kill stage/reason |
HealthReport |
Watchdog | agent_name, status, message, error_count, checked_at |
Enums: SignalCategory (supplier_disruption, positive_news, earnings_surprise, regulatory_action, macro_shift, neutral), Severity (LOW→CRITICAL), MarketRegime (bull/bear/sideways/unknown), PipelineStatus, AgentHealth (healthy/degraded/failed).
FilteredSignal / SizedSignal expose property pass-throughs (.category, .severity, .headline…) so downstream agents never reach into .original.
Initial schema is infra/supabase/001_schema.sql (11 tables); later migrations add seniority, EXP, LLM cost, and milestone state. Each pipeline stage maps to a table.
| # | Table | Owner | Purpose |
|---|---|---|---|
| 1 | signals |
Hermes Producer / Icarus | raw market signals; consumed_by_icarus flag drives polling |
| 2 | filtered_signals |
Hades | compliance results (compliance_score, ofac_flag, esg_flag, downgraded) |
| 3 | macro_context |
Artemis | regime snapshots (vix, sp500_1m_return, sector_momentum JSONB) |
| 4 | trades |
Pythia + Ares | every trade; context_key, confidence, position_pct, pnl_pct, hit (NULL=open) |
| 5 | decision_traces |
ZEUS | full pipeline audit per signal, incl. killed_at_stage / kill_reason
|
| 6 | portfolio_state |
Argus | equity / peak / drawdown (singleton row — fixed from per-tick bloat) |
| 7 | portfolio_positions |
Argus | open positions (qty, avg_cost, SL/TP, unrealized P&L) |
| 8 | agent_health |
Watchdog | health reports; agent_health_latest view = newest per agent |
| 9 | circuit_breakers |
CB | per-agent breaker state snapshots |
| 10 | knowledge_documents |
Apollo / KB | pgvector store; embedding vector(1536), HNSW index, collections: knowledge / decisions / literature |
| 11 | ticker_map |
Apollo | supplier → ticker + exchange (XETRA / NYSE / NASDAQ) |
| Migration | Adds |
|---|---|
004_seniority.sql |
agent_seniority, agent_seniority_history, system_seniority view, get_seniority_report() / get_promotion_history() RPCs |
005_llm_usage_*.sql |
llm_usage (model, symbol, input/output tokens, cost_usd) + portfolio_state singleton fix |
009_agent_exp.sql |
agent_exp_ledger, agent_exp (the cosmetic real-money XP bar — never affects sizing) |
011_seniority_tiers.sql |
tier model refresh (the inverted, earned-upward ladder) |
012_milestone_state.sql |
milestone_state singleton (vault_balance, total_vaulted, crossed_stages) |
(A parallel supabase/migrations/ tree holds the same schema in Supabase CLI timestamped format.)
The heart of position sizing. A materialized view aggregating trades by context key = {category}|{regime}|{vix_band}.
CREATE MATERIALIZED VIEW trade_hit_rates AS
SELECT context_key, category, regime, vix_band,
COUNT(*) AS total_trades,
COUNT(*) FILTER (WHERE hit IS NOT NULL) AS closed_trades,
AVG(CASE WHEN hit THEN 1.0 ELSE 0.0 END)
FILTER (WHERE hit IS NOT NULL) AS hit_rate,
AVG(pnl_pct) FILTER (WHERE pnl_pct IS NOT NULL) AS avg_pnl_pct
FROM trades GROUP BY context_key, category, regime, vix_band;Refreshed CONCURRENTLY by a trigger after any hit / pnl_pct update. Pythia looks up the row for the current context; the PromotionGate (core/shadow_learning.py) then Bayesian-shrinks the rate toward 0.50 until closed_trades ≥ 10 (see Design-Decisions).
VIX bands: low <15, medium <25, high <35, extreme ≥35.
Pythia/Ares INSERT → hit = NULL (open), pnl_pct = NULL
│
▼ position closes (IB bracket SL/TP fires)
Argus OutcomeResolver:
pnl_pct = (exit - fill)/fill (negated for shorts)
hit = pnl_pct > 0
UPDATE trades SET pnl_pct, hit, closed_at
→ trade_hit_rates refreshes → Pythia's next size uses it
→ ChromaDB decision trace updated with the real outcome
→ win count feeds the seniority ladder
The resolver is restart-safe: it can rebuild open state from the DB and only backfills a close when it has a trusted IB fill price (approximate fallbacks are off by default — protecting hit-rate integrity).
Every table has RLS enabled (001_schema.sql):
| Role | Access |
|---|---|
service_role (backend: ZEUS, Hermes, dashboard) |
full read/write on all tables |
anon (React dashboard, Grafana) |
read-only on trades, decision_traces, portfolio_state, portfolio_positions, agent_health, macro_context, signals, ticker_map
|
Supabase Realtime is enabled on trades, decision_traces, portfolio_state, agent_health so the dashboard updates live. New tables must add explicit GRANTs (template at infra/supabase/TEMPLATE_migration_NNN.sql) or PostgREST returns 403.
When SUPABASE_URL / SUPABASE_SERVICE_ROLE_KEY are unset, Pythia and the seniority evaluator fall back to a local SQLite data/trade_log.db (same trades schema), and the KB uses local persistent ChromaDB. This lets the system run end-to-end with no cloud account. The seniority evaluator reads whichever backend actually holds the trades (a past bug: reading SQLite while prod wrote Supabase left every agent stuck at 0 wins).
Pantheon OS — 8-agent autonomous trading system · Repository · Built by Eugen Müller
Overview
Deep dives