Master Playbook
Stand: 31. Mai 2026 Für: Sebastian Friedrich / plan.ai (Wien) Methode: Jede Rolle wurde via hart nachdenkendes 3-Perspektiven-LLM-Council (Opus + GPT-5.5 + Gemini 3.1 Pro) durchdacht — drei gegensätzliche Blickwinkel (P1 Quant/Stratege · P2 Engineer/Pragmatiker · P3 Risk/Ethics/Compliance) wurden gegeneinander argumentiert und zu einer finalen Spezifikation synthetisiert. Fundament: Hermes_Trading_Build_Guide.md (vollständige Architektur + Setup) — dieses Playbook setzt darauf auf und referenziert ihn, ohne ihn zu duplizieren.
Vorwort — Das Agency-Modell in Kürze
Section titled “Vorwort — Das Agency-Modell in Kürze”Die Trading-Agency ist ein Hermes-orchestrierter, FOSS-basierter Multi-Agenten-Stack für US-Aktien/ETFs auf einer gehärteten Ubuntu-VM. Sie verteilt den Trade-Lifecycle auf 11 spezialisierte Rollen — von der Universums-Definition über Daten, Screening, adversariale Debatte, Reconciliation, Risk-Sizing, Execution und Exit-Monitoring bis zu den Querschnittsrollen Compliance, Quant-Validierung und Orchestration.
Das Leitprinzip ist eine strikte Gewaltenteilung: LLMs denken und schlagen vor (Screening, Debatte), aber Sicherheit ist Code, nicht Prompt — jede sicherheits- oder rechtskritische Entscheidung läuft durch deterministische Python-Gates, niemals durch ein Modell. Der Orchestrator ist Hermes Agent (NousResearch, MIT) mit vier Primitiven: Tool, MCP-Client, Subagent und Cron. Die „Brains” sind ai-hedge-fund (breites, billiges Persona-Screening) → Shortlist → TradingAgents (tiefe Bull/Bear/Risk-Debatte). Die Ausführung läuft über den offiziellen alpaca-mcp-server.
Das Mandat ist kompromisslos: Long-only, kein Leverage, kein Short, keine Optionen; Paper-first mit Doppel-Gate (ALPACA_PAPER_TRADE=True und LIVE_TRADING_ENABLED=false), Echtgeld erst nach ≥4 Wochen (faktisch ≥3 Monate Eval) und explizitem Go/No-Go; ethisch-utopischer Tilt auf Wachstums-Themen (Sustainability/CleanTech, AI, Tech, Space, Peace/defensive Cybersecurity, Robotics, Biotech) mit Zero-Tolerance-Exclusion für Rüstung/Fossil/Tobacco/Gambling. Mandatory HITL (Telegram) vor jeder Order, ein globaler Datei-Kill-Switch, point-in-time-Daten gegen Look-ahead-Bias, gepinnte Modellversionen und ein lückenloser Audit-Trail (SQLite + append-only JSONL) sind nicht verhandelbar. Bei jeder Unsicherheit defaultet das System hart auf HOLD / no-trade. Rechtsrahmen: Österreich/EU (WAG 2018, FMA, MiFID II, MAR), ausschließlich Eigenhandel.
Inhaltsverzeichnis
Section titled “Inhaltsverzeichnis”- Teil A — Agency-Gesamtbild: Lifecycle-Diagramm + Rollen-Übersichtstabelle
- Teil B — Die 11 Rollen im Detail (je in sich geschlossen, mit 9-Punkte-Spezifikation)
- Rolle 1 — Universe Architect
- Rolle 2 — Data & Signal Engineer
- Rolle 3 — Breadth Screener
- Rolle 4 — Deep Analyst / Debate
- Rolle 5 — Reconciler / Chief Investment Officer
- Rolle 6 — Risk Manager & Position Sizer
- Rolle 7 — Execution Trader
- Rolle 8 — Portfolio Monitor & Exit Strategist
- Rolle 9 — Compliance & Ethics Officer
- Rolle 10 — Quant Validator / Backtest & Eval
- Rolle 11 — Orchestration & Reliability Engineer
- Teil C — Rollen-Zusammenspiel & Daten-Contracts: durchgehende Pipeline + Schema-Vereinheitlichung
- Teil D — finance-skills-Integration: Votum, JA/NEIN-Listen, Auflagen, Skill→Rolle-Zuordnung
- Teil E — Querschnitts-Prinzipien: die wiederkehrenden Safety-/Ethik-Prinzipien an einer Stelle
- Teil F — Offene Fragen & Gesamt-Risiken: priorisierte, deduplizierte Gesamtliste
Kanonische Benennung (gilt durchgehend): Wo Rollen ursprünglich leicht abweichende Namen für dasselbe Artefakt verwendeten, vereinheitlicht dieses Playbook sie. Die maßgebliche Pipeline lautet:
universe_db.json(≙allowed_tickers.json) →feature_snapshot→screen_result→debate_thesis(DebateResult) →reconciled_signal(CIODecision) →sized_order(Risk-Manager-Order) →ApprovedOrderRequest→ExecutionResult→position_health(PositionHealthReport). Die genauen Gleichsetzungen und verbleibenden Abweichungen sind in Teil C dokumentiert.
Teil A — Agency-Gesamtbild
Section titled “Teil A — Agency-Gesamtbild”A.1 — Trade-Lifecycle-Diagramm
Section titled “A.1 — Trade-Lifecycle-Diagramm”Alle 11 Rollen entlang des Lifecycles. Die Querschnittsrollen Compliance (9), Validator (10) und Orchestration (11) wirken auf jeden Schritt.
flowchart TB subgraph LIFECYCLE["Trade-Lifecycle (Long-only, Paper-first)"] direction TB R1["1 · Universe Architect\nEthik+Liquidität-Gate\n→ universe_db.json"] R2["2 · Data & Signal Engineer\nPoint-in-time Features\n→ feature_snapshot"] R3["3 · Breadth Screener\n5 ai-hedge-fund-Personas\n→ screen_result (Shortlist)"] R4["4 · Deep Analyst / Debate\nBull/Bear/Risk (Claude/GPT/Gemini)\n→ debate_thesis"] R5["5 · Reconciler / CIO\nSupermajority ≥2/3 + Kalibrierung\n→ reconciled_signal (CIODecision)"] R6["6 · Risk Manager & Sizer\nATR-1%-Sizing, Caps, Stops\n→ sized_order"] R7["7 · Execution Trader\nplace_order-Gate, GTC-Bracket\n→ ExecutionResult"] R8["8 · Portfolio Monitor & Exit\nChandelier, Max-Hold, Gap-Schutz\n→ position_health"] R1 --> R2 --> R3 --> R4 --> R5 --> R6 --> R7 --> R8 R8 -. "Re-Entry-Cooldown / Exit-Request" .-> R7 end
subgraph CROSS["Querschnitt (auf jeden Schritt)"] direction LR R9["9 · Compliance & Ethics\nHITL-Gate, MAR, KESt, Audit"] R10["10 · Quant Validator\nBacktest, Overfitting-Trias, Go/No-Go"] R11["11 · Orchestration & Reliability\nCron/TZ, Kill-Switch, Budget, Secrets"] end
R9 -. "HITL vor jeder Order" .-> R7 R9 -. "Audit-Trail" .-> LIFECYCLE R10 -. "Edge-Beweis / Kalibrierung" .-> R3 R10 -. "Go/No-Go Paper→Live" .-> R5 R11 -. "Gates / HOLD-Default / Pins" .-> LIFECYCLELesart: Universe → Data → Screen → Debate → Reconcile → Risk → Execution → Monitor/Exit. Compliance (HITL + Audit), Validator (statistischer Edge-Beweis + Go/No-Go) und Orchestration (Betriebssicherheit, Budget, Kill-Switch) sind keine Lifecycle-Stationen, sondern Querschnitts-Wächter, die jeden Schritt einrahmen.
A.2 — Rollen-Übersichtstabelle
Section titled “A.2 — Rollen-Übersichtstabelle”| # | Rolle | Mission (1 Satz) | Hermes-Primitiv | LLM? | Output-Artefakt |
|---|---|---|---|---|---|
| 1 | Universe Architect | Definiert, prüft und versioniert die einzige autorisierte, ethisch saubere & liquide Handelsliste. | Tool + Cron (Subagent nur offline) | Nein (nur offline Classification-Assistant, HITL-gated) | universe_db.json (+ PiT-Archiv, exclusion_audit.sqlite) |
| 2 | Data & Signal Engineer | Liefert den einzigen zulässigen, point-in-time & auditierbaren Daten-/Feature-Snapshot. | Tool + MCP + Cron (Subagent nur Sentiment) | Teilw. (nur grounded Sentiment-Classifier) | feature_snapshot (+ Batch-Summary) |
| 3 | Breadth Screener | Billiges Wide-Screening über 5 Investor-Personas, erzeugt Consensus/Controversy-Shortlist. | Subagent (Async-Fan-out) | Ja (quick_think, T=0) | screen_result (Shortlist) |
| 4 | Deep Analyst / Debate | Adversariale Bull/Bear/Risk-Debatte je Kandidat, quellengestützte Investment-These. | Subagent (Council-Fan-out) + Tool (Aggregation) | Ja (deep_think, heterogen) | debate_thesis (DebateResult) |
| 5 | Reconciler / CIO | Fusioniert die 3 Council-Voten zu einer kalibrierten, auditierbaren CIO-Entscheidung. | Tool (Subagent nur optionaler Judge) | Primär nein (optionaler Veto-Judge) | reconciled_signal (CIODecision) |
| 6 | Risk Manager & Position Sizer | Transformiert ein Buy-Signal deterministisch in Positionsgröße + Stop, vetot bei Limit-Verletzung. | Tool (Hard-coded Middleware) | Nein | sized_order (Order) |
| 7 | Execution Trader | Einziges deterministisches Gateway zum Markt; erzwingt Gates, platziert atomare GTC-Brackets. | Tool (place_order) + MCP + Cron | Nein | ExecutionResult |
| 8 | Portfolio Monitor & Exit Strategist | Überwacht offene Longs, ratchet Stops, erzwingt Max-Hold & Gap-Schutz via Exit-Requests. | Cron + Tool (Subagent nur Notiz) | Nein (optional quick_think nur Erklärung) | ExitRequest + position_health |
| 9 | Compliance & Ethics Officer | Normativer Wächter: HITL-Workflow, MAR/FMA, Audit-Trail, KESt-Steuerdoku. | Tool + MCP + Cron | Nein | HITL-Request, Audit-Record, Tax-Log |
| 10 | Quant Validator | Epistemisches Go/No-Go-Tor: beweist statistischen Edge vs. Momentum-Baseline. | Cron + Tools (Subagent nur Interpretation) | Berechnung nein; optionaler read-only Council | backtest_report + go_no_go_verdict |
| 11 | Orchestration & Reliability | Deterministisches Nervensystem: Cron/TZ, Kill-Switch, Budget, Secrets, Observability. | Cron + Tools + Watchdog | Nein (nur sanitized Postmortems) | orchestration_decision + Audit-/Cost-/Health-Events |
Muster im Gesamtbild: Nur drei Rollen nutzen LLMs entscheidungsnah (3 Screener, 4 Debate, 5 nur optionaler Judge), und genau dort wo Diversität/Reasoning Edge bringt. Alle sicherheits-, rechts- und kapitalkritischen Rollen (1, 6, 7, 9, 11 sowie die Berechnung in 10) sind bewusst deterministisch — die schadensträchtigsten Punkte (Universe-Gate, Sizing, Execution, Compliance, Backtest-Statistik) enthalten kein Modell.
Teil B — Die 11 Rollen im Detail
Section titled “Teil B — Die 11 Rollen im Detail”Rolle 1 — Universe Architect
Section titled “Rolle 1 — Universe Architect”Wichtigste Council-Entscheidungen dieser Rolle:
- Zwei-Schwellen-Modell für Themen-Zugehörigkeit: ≥20 % geschätzter Themen-Umsatz ODER ETF-Consensus-Core (≥2 Referenz-ETFs); der Ethik-Threshold ist davon entkoppelt und immer strenger (Dual-Use-Revenue >5 % = harter Ausschluss, kontroverse Waffen = Ausschluss ohne jede Schwelle).
- Build-Pfad ist deterministisch: Ein LLM hilft nur offline, pre-build als „Classification Assistant” für Grenzfälle, schreibt nie direkt ins Universum, alles HITL-bestätigt.
- ETF-Holdings sind Kandidaten-Quelle, nie Approval: jeder ETF-Ticker durchläuft das volle Ethik-Gate; explizite ETF-Blacklist (AVAV, SAIC, BAH) gegen das „trojanische Pferd Rüstung” (BOTZ→AVAV, CIBR→SAIC).
- Asymmetrischer Refresh: Ausschlüsse greifen sofort/ereignisbasiert, Aufnahmen nur quartalsweise — raus geht schnell, rein geht langsam.
1 — Mission & Verantwortung
Section titled “1 — Mission & Verantwortung”Der Universe Architect definiert, pflegt und versioniert die einzige autorisierte Handelsliste des gesamten Stacks (ALLOWED_TICKERS): thematisch relevante, ethisch geprüfte, liquide US-Aktien/ETFs gemäß dem Long-only-Utopian-Mandat. Er ist die erste und härteste Verteidigungslinie gegen Waffen-, Fossil-, Tobacco- und Gambling-Exposure und die Quelle der Point-in-Time-Universum-Archive, die spätere Backtests survivorship-frei machen. Kein Ticker betritt das System, ohne dieses Gate passiert zu haben — und das Gate wird im place_order-Pfad (Rolle 7) ein zweites Mal erzwungen.
2 — Inputs / Outputs
Section titled “2 — Inputs / Outputs”Inputs:
| Input | Quelle | Form |
|---|---|---|
| Themen-Definition + Exclusion-Policy | _shared_context.md, universe_policy.yaml | YAML (Themen, GICS-Maps, Schwellen, Blacklist) |
| Kuratierter Seed | universe_seed.yaml (HITL-bestätigt) | Liste {ticker, theme, rationale} |
| Referenz-ETF-Holdings | iShares/Global X/ARK Daily Holdings (CSV/XLSX) | gecacht in SQLite etf_holdings |
| Fundamental-/Segment-Daten | financial-datasets.ai (Segmented Financials) | JSON (Revenue-Split-Schätzung) |
| Markt-/Liquiditätsdaten | Alpaca Market Data | OHLCV, mcap, ADV, Spread |
| Exclusion-Referenzen | SIPRI Top-100, kontroverse-Waffen-Liste | statisch + jährlich aktualisiert |
Primär-Output — universe_db.json (täglich geschrieben, versioniert; kanonisch identisch mit dem von Rolle 3/10 referenzierten allowed_tickers.json, siehe Teil C):
{ "version": "2026-05-30", "generated_at_utc": "2026-05-30T06:00:00Z", "policy_hash": "sha256:...", "tickers": { "PANW": { "theme": ["peace_cyber"], "gics_sub_industry": "45103010", "theme_revenue_pct_est": 0.92, "in_etf_consensus_core": true, "etf_sources": ["BUG", "CIBR"], "ethics": { "dual_use_stage1_revenue": "pass", "dual_use_stage2_customer": "pass", "dual_use_stage3_intent": "pass", "exclusion_hit": false, "sipri_top100": false, "verdict": "INCLUDE" }, "liquidity": { "market_cap_usd": 1.1e11, "adv_usd_20d": 4.2e8, "spread_pct": 0.0004, "last_price": 312.5, "verdict": "pass" }, "status": "APPROVED", "last_reviewed": "2026-04-01", "next_review": "2026-07-01" } }, "excluded": { "AVAV": {"reason": "dual_use_stage2_military_customer", "source": "BOTZ", "blacklist": true} }}Sekundär-Outputs: universe_archive/universe_YYYY-MM-DD.json (PiT-Snapshot, append-only, immutable), pending_review.jsonl (LLM-Vorschläge für HITL), exclusion_audit.sqlite (jede Ausschluss-Entscheidung mit Begründung + Quelle + Timestamp).
3 — Methodik & beste Praktiken
Section titled “3 — Methodik & beste Praktiken”Pipeline (deterministisch, idempotent):
- Kandidaten-Sammlung — Vereinigung aus (a)
universe_seed.yamlund (b) ETF-Holdings aller Referenz-ETFs pro Thema (mind. 3–5 ETFs/Thema): AI/Robotics → ROBO, BOTZ; CleanTech → ICLN, QCLN, ACES; Cyber/Peace → BUG, CIBR; ARK-Innovation → ARKK, ARKW, ARKG (alle als Kandidatenquelle, Overlap-Daten aus ETF Research Center). - GICS-Eingangsfilter — Sub-Industry-Ebene (6-stellig) als grober Schnitt, NICHT als alleiniger Selektor, weil Themen quer über Sektoren liegen (GICS Methodology). Mapping z. B. AI → 45103010/45103020/45201020; CleanTech → 10102010/25203010; Biotech → 35201010.
- Themen-Threshold (zwei Pfade, OR-verknüpft): Pfad A: geschätzter Themen-Umsatz ≥20 % (Robeco-Faustregel, via financial-datasets Segmented Financials) MIT Kerngeschäfts-Begründung; Pfad B: ETF-Consensus-Core (≥2 unabhängige Referenz-ETFs), validiert über FactSet-Multi-Sektor-Kriterium (FactSet, Robeco).
- ETHIK-GATE (HARD BLOCK, immer vor Liquidität):
- Exclusion-Liste: Rüstung (LMT, RTX, NOC, GD, BA, HII, LDOS, ITA, XAR, PPA), Fossil (XOM, CVX, COP, PSX, VLO, OXY, SLB, HAL, MRO, XLE, OIH), Tobacco (MO, PM, BTI), Gambling (MGM, WYNN, LVS, CZR, DKNG) + ETF-Blacklist-Holdings (AVAV, SAIC, BAH).
- SIPRI-Abgleich gegen SIPRI Top-100.
- Kontroverse Waffen (SFDR EU 2022/1288): Antipersonenminen, Streumunition, chem./bio. → Ausschluss ohne Schwelle.
- Drei-Stufen-Dual-Use-Test (konservativ >5 %): Stufe 1 Revenue >5 % aus Rüstung → EXCLUDE; Stufe 2 primärer Militärkunde → EXCLUDE (z. B. AVAV); Stufe 3 beworbene Militäranwendung / keine Export-Control-Compliance → EXCLUDE; alle drei NEIN → CONDITIONAL INCLUDE mit Monitoring (z. B. Planet Labs). PLTR bei DoD-Dominanz konservativ EXCLUDE.
- „Peace ohne Rüstung”: erlaubt sind defensive Cybersecurity (PANW, CRWD, ZS, FTNT, S) und zivile humanitäre/Kommunikations-Infra; CIBR-Konstituenten SAIC/BAH werden trotz ETF-Mitgliedschaft gefiltert, BUG ist „cleaner”.
- Liquiditätsfilter (HARD BLOCK):
mcap ≥ $100M,ADV ≥ $1M,spread ≤ 0,5 %bei Aufnahme (≤0,3 % normal),price ≥ $5. Faustregel: Tagesvolumen ≥10× geplante Positionsgröße. (Hinweis: Rolle 7 verschärft den Spread am Order-Punkt zusätzlich auf <0,1 % — andere Layer, siehe Teil C.) - Survivorship-Schutz: Jeder Build wird als immutabler PiT-Snapshot archiviert (append-only); für Backtests wird das Universum zum Zeitpunkt t rekonstruiert, inkl. delisteter Namen — „the graveyard matters” (Dimensional).
4 — LLM-Council-Design der Rolle
Section titled “4 — LLM-Council-Design der Rolle”Im Kern deterministisch — bewusst KEIN LLM im Build-Hot-Path (das Universum muss reproduzierbar, auditierbar, idempotent sein). Einziger LLM-Einsatz: „Classification Assistant” (offline, pre-build, HITL-gated) — liest grounded SEC-Filing-Auszüge, schlägt Themen-/Ethik-Klassifikation mit Quellenzitat vor, schreibt in pending_review.jsonl; quick_think-Modell, Temperatur 0.0, gepinnt. Bei Unsicherheit defaultet das System auf EXCLUDE + HITL — sicherer als jede Modell-Mehrheit. Prompt strikt grounded („Klassifiziere AUSSCHLIESSLICH auf Basis des Filing-Texts; nenne wörtliches Zitat + Quelle; bei fehlender Evidenz INSUFFICIENT_DATA; fabriziere keine Revenue-Zahlen.”) Das LLM schreibt nie direkt ins Universum.
5 — Konkrete Implementierung
Section titled “5 — Konkrete Implementierung”Hermes-Primitiv-Zuordnung: Tool (tools/registry.py): build_universe(), check_ethics_gate(ticker), get_allowed_tickers() (vom Orchestrator und vom place_order-Gate aufrufbar). Cron: täglicher Build 06:00 Europe/Vienna (TZ-sicher), monatlicher ETF-Drift-Scan, quartalsweises Full-Review-Flag. MCP nur indirekt (über Rolle 2). Subagent nur der offline Classification-Assistant.
REFERENCE_ETFS = { "ai_robotics": ["ROBO", "BOTZ"], "cleantech": ["ICLN", "QCLN", "ACES"], "peace_cyber": ["BUG", "CIBR"], "innovation": ["ARKK", "ARKW", "ARKG"],}EXCLUSION_TICKERS = { # Rüstung / Fossil / Tobacco / Gambling / ETF-Blacklist "LMT","RTX","NOC","GD","BA","HII","LDOS","ITA","XAR","PPA", "XOM","CVX","COP","PSX","VLO","OXY","SLB","HAL","MRO","XLE","OIH", "MO","PM","BTI","MGM","WYNN","LVS","CZR","DKNG", "AVAV","SAIC","BAH",}MIN_MCAP=100_000_000; MIN_ADV=1_000_000; MAX_SPREAD=0.005; MIN_PRICE=5.0DUAL_USE_REVENUE_LIMIT = 0.05 # konservativ
def passes_ethics_gate(ticker, profile): if ticker in EXCLUSION_TICKERS: return False, "exclusion_list" if sipri_top100(ticker): return False, "sipri_top100" if controversial_weapons(profile): return False, "controversial_weapons" # keine Schwelle if profile.defense_revenue_pct > DUAL_USE_REVENUE_LIMIT: return False, "dual_use_stage1_revenue" if profile.primary_customer_is_military: return False, "dual_use_stage2_customer" if profile.markets_military_use or not profile.export_control_compliant: return False, "dual_use_stage3_intent" return True, "pass"
def theme_eligible(ticker, profile): revenue_ok = profile.theme_revenue_pct_est >= 0.20 and profile.core_business_justified consensus_ok = len(profile.etf_sources) >= 2 # Consensus-Core (≥2 ETFs) return revenue_ok or consensus_ok
def liquidity_gate(md): spread = (md.ask - md.bid) / md.mid return (md.market_cap>=MIN_MCAP and md.adv_usd_20d>=MIN_ADV and spread<=MAX_SPREAD and md.last_price>=MIN_PRICE)
def build_universe(): candidates = load_seed_tickers() for etf in flatten(REFERENCE_ETFS): candidates |= fetch_etf_holdings(etf) # SQLite-cached universe, excluded = {}, {} for t in candidates: prof, md = get_profile(t), get_market_data(t) ok_eth, why = passes_ethics_gate(t, prof) if not ok_eth: excluded[t] = {"reason": why, "blacklist": t in EXCLUSION_TICKERS}; continue if not theme_eligible(t, prof): excluded[t]={"reason":"theme_threshold"}; continue if not liquidity_gate(md): excluded[t]={"reason":"liquidity"}; continue universe[t] = build_record(t, prof, md) # status=APPROVED audit_log(t, "INCLUDE", prof, md) write_versioned(universe, excluded) # universe_db.json + PiT-Archiv return universe
def monthly_universe_check(): # asymmetrischer Refresh for etf in flatten(REFERENCE_ETFS): for t in fetch_etf_holdings(etf): ok,_ = passes_ethics_gate(t, get_profile(t)) if t not in universe_db and ok: flag_for_quarterly_review(t, source=etf) if t in universe_db and not ok: immediate_exclusion(t, reason="ethics_violation")Integration mit Nachbarrollen: → Rolle 2 fetcht Daten nur für get_allowed_tickers(). → Rolle 3 screent ausschließlich approved Tickers (HARD BLOCK). → Rolle 7 / place_order-Gate ruft check_ethics_gate(ticker) ein zweites Mal auf (Doppel-Enforcement). → Rolle 9/10 konsumieren exclusion_audit.sqlite bzw. das survivorship-freie Universum.
6 — Failure-Modes & Mitigationen
Section titled “6 — Failure-Modes & Mitigationen”| Failure-Mode | Mitigation (defaultet sicher) |
|---|---|
| ETF-Holding-URL geändert / Parse-Fehler / Rate-Limit | Defensives Parsing; bei Fehler alte versionierte Universum-Version weiterverwenden statt crashen; Alert. Keine Aufnahme aus unvollständigem Feed. |
| Schmutziger Ticker via neuer ETF-Methodik (BOTZ→AVAV, CIBR→SAIC) | Explizite ETF-Blacklist + monatlicher Drift-Scan mit immediate_exclusion; Doppel-Check im place_order-Gate. |
| Revenue-Schätzung ungenau (kein MSCI) | Bei Unsicherheit defaultet Themen-Eligibilität auf robusteren Consensus-Core-Pfad; Dual-Use-Unsicherheit → EXCLUDE + HITL. |
| Theme-Drift (Tech-Firma wird Defense-Contractor, M&A) | Ereignisbasierter Ad-hoc-Review → sofortiger Ausschluss. |
| Survivorship-Bias im Backtest | Immutable PiT-Snapshots; Rekonstruktion zum Zeitpunkt t inkl. delisteter Namen. |
| LLM-Classification-Assistant halluziniert | Grounded-Prompt + Quellenpflicht + INSUFFICIENT_DATA; nie direkter Schreibzugriff; HITL-Pflicht. |
| Liquiditätskollaps eines approved Tickers | Spread auch zum Order-Zeitpunkt prüfen (>1,0 % = warte/limit) (Schwab). |
| Universum leer / zu klein | Mindestgrößen-Alarm; kein Lockern der Ethik-Schwellen — lieber kleineres sauberes Universum. |
7 — Safety / Ethik / Compliance-Hooks
Section titled “7 — Safety / Ethik / Compliance-Hooks”- Ethik-Gate als HARD BLOCK vor allem anderen, gespiegelt im
place_order-Gate (Doppel-Enforcement). - Zero-Tolerance Waffen/Rüstung unabhängig von Umsatzschwellen (values-based, NordSip, KLP); konservativer Dual-Use-Default.
- Long-only-Kontext: keine Inverse-/Leverage-ETFs (Filter auf ETF-Typ).
- Vollständiger Audit-Trail in
exclusion_audit.sqlite+ JSONL (WAG 2018/MiFID II). - HITL für Grenzfall-Aufnahmen; LLM ohne Schreibzugriff. Policy-Hash je Universum-Version.
8 — Eval / KPIs
Section titled “8 — Eval / KPIs”- Ethik-Recall (kritischster KPI): Anteil bekannter schmutziger Namen, die korrekt geblockt werden (Test-Suite AVAV/SAIC/BAH/LMT/XOM…) — Ziel = 100 %, jeder False-Negative ist ein kritischer Bug.
- Themen-Purity-Rate ≥90 %; Liquiditäts-Treffer zum Order-Zeitpunkt ≥95 %; Universum-Stabilität (Turnover/Quartal); Build-Determinismus (gleicher Input/Tag → gleicher
policy_hash); Refresh-Latenz Ethik-Event→immediate_exclusion<24 h.
9 — Offene Fragen / Risiken
Section titled “9 — Offene Fragen / Risiken”- Revenue-Split-Genauigkeit ohne MSCI/Sustainalytics; ggf. günstiger ESG-Feed (Business-Involvement-Scores).
- PLTR/Planet-Labs-Grenzfälle: conditional-include-Linie policy-abhängig, von Sebastian in
universe_policy.yamlzu entscheiden (Default: konservativ EXCLUDE bei DoD-Dominanz). - ETF-Holdings-ToS pro Anbieter (iShares/Global X/ARK) prüfen.
- Delisted-Daten für survivorship-freie Backtests: ab Live-Start eigene tägliche Holdings-Snapshots sammeln.
- „Peace/Humanitär”-Sub-Cluster bleibt dünn (stützt sich praktisch auf defensive Cybersecurity).
Rolle 2 — Data & Signal Engineer
Section titled “Rolle 2 — Data & Signal Engineer”Wichtigste Council-Entscheidungen dieser Rolle:
- Alpaca ist primäre Preisquelle; yfinance nur Fallback/Plausibilitätscheck; financial-datasets für Fundamentals — kein Backtest vertraut yfinance als Wahrheit (Lizenz-/Dividend-Adjustment-Probleme).
- Kleines, robustes Feature-Set (RSI 14, MACD 12/26/9, ATR 14, 20/50/200-MA, anchored VWAP, Bollinger 20/2, RVOL/OBV, Spread/ADV) statt fragiler Alpha-Magie; ATR ist Pflicht für die Stop-/Sizing-Übergabe an Rolle 6.
- LLM-Sentiment ist sekundär & nicht-blockierend, nur auf konkreten gelieferten Texten; fehlende Quellen/Dissens/>10 % Abweichung →
sentiment_status = UNUSABLE.- Live/Paper strikt PiT über
as_of-Snapshots; Backtests in Woche 1 „diagnostisch, nicht beweisend”, bis saubere PiT-/delisted-Daten vorliegen. Jede schwere Unsicherheit →tradability_status = HOLD_DATA_ISSUE.
1 — Mission & Verantwortung
Section titled “1 — Mission & Verantwortung”Der Data & Signal Engineer liefert den einzigen zulässigen, auditierbaren Daten-/Feature-Snapshot für alle nachgelagerten Rollen. Er nimmt ausschließlich vom Universe Architect freigegebene Ticker entgegen, lädt Preis-, Fundamental-, Corporate-Action-, Liquiditäts- und optional Sentimentdaten, normalisiert sie point-in-time, prüft Datenqualität und gibt strukturierte feature_snapshot-Artefakte aus. Er entscheidet nicht über Kauf/Verkauf und platziert nie Orders; seine Verantwortung ist Wahrheit, Zeitkorrektheit, Determinismus, Quellenbindung und Safe-Default: nicht belastbare Daten ⇒ HOLD_DATA_ISSUE.
2 — Inputs / Outputs (mit Schema/Feldern)
Section titled “2 — Inputs / Outputs (mit Schema/Feldern)”Input A — Universe-Input von Rolle 1 (allowed_tickers, kanonisch aus universe_db.json):
{ "run_id": "uuid", "as_of": "2026-05-30T13:30:00-04:00", "universe_version": "2026Q2.4", "allowed_tickers": [ { "ticker": "CRWD", "asset_type": "US_EQUITY", "theme_tags": ["AI", "Peace:defensive_cybersecurity"], "ethics_status": "APPROVED", "ethics_reasons": ["no_weapons_revenue_detected", "commercial_cybersecurity_primary"], "liquidity_minimums": {"min_market_cap_usd": 100000000, "min_adv_usd": 1000000, "max_spread_pct": 0.005, "min_price_usd": 5.0}, "universe_sources": ["ETF_consensus", "manual_revenue_check"] } ], "blocked_tickers_hash": "sha256"}Input B — Runtime-Konfiguration (Auszug): mode: paper, timezone: America/New_York, bar_timeframe: 1Day|15Min|1Min, lookback_days: 260, Provider-Map (prices_primary: alpaca, prices_fallback: yfinance_quality_check_only, fundamentals: financial_datasets, corporate_actions: nasdaq_or_alpaca), feature_params (rsi_period 14, macd [12,26,9], atr_period 14, ma_periods [20,50,200], bollinger [20,2], rvol_period 20, max_staleness_seconds: 900).
Input C — Optionaler Text-Input für grounded Sentiment: Dokumente mit doc_id, source_url, published_at, retrieved_at, title, text, source_type (news|filing|reddit|stocktwits).
Output A — feature_snapshot pro Ticker (kanonisch feature_snapshot.v1; in Backtests als feature_snapshot_{ticker}_{date}.json archiviert):
{ "schema_version": "feature_snapshot.v1", "run_id": "uuid", "ticker": "CRWD", "as_of": "2026-05-30T13:30:00-04:00", "universe_version": "2026Q2.4", "tradability_status": "OK|HOLD_DATA_ISSUE|BLOCKED_UNIVERSE|BLOCKED_ETHICS|BLOCKED_LIQUIDITY", "data_quality_status": "PASS|FAIL|WARN", "data_quality_failures": [], "source_manifest": [ {"provider": "alpaca", "dataset": "bars", "request_id": "...", "retrieved_at": "2026-05-30T13:31:00-04:00", "max_timestamp_used": "2026-05-30T13:29:00-04:00", "license_note": "Alpaca ToS; no redistribution"} ], "market_data": {"last_price": 355.42, "bid": 355.30, "ask": 355.55, "spread_pct": 0.0007, "volume_today": 1200000, "adv_usd_20d": 950000000, "market_cap_usd": 87000000000, "is_stale": false}, "technical_features": {"return_1d": 0.012, "return_5d": 0.034, "return_20d": 0.08, "rsi_14": 61.2, "macd_line": 2.10, "macd_signal": 1.75, "macd_hist": 0.35, "atr_14": 8.4, "atr_pct": 0.0236, "sma_20": 340.1, "sma_50": 330.4, "sma_200": 295.7, "ema_20": 342.0, "anchored_vwap": 348.2, "bollinger_z": 0.9, "rvol_20": 1.35, "obv_slope_20": 0.18, "trend_state": "UPTREND|DOWNTREND|RANGE", "setup_tags": ["trend_above_50_200", "rsi_neutral_positive", "volume_confirmed"]}, "fundamental_features": {"filed_before": "2026-05-30T13:30:00-04:00", "revenue_growth_yoy": 0.28, "gross_margin": 0.74, "fcf_margin": 0.31, "debt_to_equity": 0.45, "valuation_sales_multiple": 18.2, "fundamental_status": "PASS|MISSING|STALE"}, "sentiment_features": {"sentiment_status": "PASS|UNUSABLE|MISSING", "sentiment_score": 0.22, "sentiment_label": "positive|neutral|negative|mixed", "document_count": 8, "model_agreement": 0.83, "evidence_doc_ids": ["news_001", "filing_002"]}, "risk_handoff": {"atr_stop_distance_1_5x": 12.6, "suggested_stop_reference": 342.82, "volatility_bucket": "LOW|MEDIUM|HIGH", "gap_risk_flag": false, "liquidity_bucket": "A|B|C|FAIL"}, "audit": {"code_version": "git_sha", "config_hash": "sha256", "input_hash": "sha256", "output_hash": "sha256", "warnings": []}}Output B — Batch-Summary für Rolle 3 + Orchestrator: tickers_requested, snapshots_ok, hold_data_issue, blocked_universe_or_ethics, provider_errors (je Provider), outputs[], global_status: PASS|DEGRADED|FAIL_SAFE_HOLD.
3 — Methodik & Best Practices
Section titled “3 — Methodik & Best Practices”3.1 Provider-Strategie: Alpaca Market Data als Preis-Primärquelle (Free/IEX für Dev/Paper; Produktion prüft Algo Trader Plus, Alpaca); financial-datasets.ai für Fundamentals (Pricing); yfinance nur sekundäre Plausibilität (Split-/Dividenden-Inkonsistenzen als Backtest-Risiko markiert, quantmod-Issue); Social/News-Sentiment optional, nie primäres Entry-Signal (Reddit/PRAW, StockTwits, nur wenn created_at < as_of und quellengebunden).
3.2 Point-in-Time-Regeln: Jeder Datensatz bekommt observed_at, published_at, retrieved_at, available_at, as_of_used, provider, raw_payload_hash. Feature-Berechnung nutzt nur available_at <= decision_as_of; intraday wird der laufende Bar ausgeschlossen (bar.timestamp < signal_time.floor(timeframe)); Earnings/Fundamentals zählen erst ab Filing-Zeit. LLMs erhalten nie offene Fragen, nur den Snapshot + Anweisung, außerhalb INSUFFICIENT_DATA zu sagen (Glassnode PiT, Look-Ahead-Bench).
def select_point_in_time(records, decision_as_of): usable, rejected = [], [] for r in records: if r.available_at is None: rejected.append((r, "missing_available_at")) elif r.available_at <= decision_as_of: usable.append(r) else: rejected.append((r, "future_data")) return usable, rejected
def build_feature_vector(ticker, decision_as_of): bars = alpaca_adapter.get_bars(ticker, end=decision_as_of - timedelta(minutes=1), adjustment="split") bars, rejected_bars = select_point_in_time(bars, decision_as_of) fundamentals = financial_datasets_adapter.get_financials(ticker, filed_before=decision_as_of) fundamentals, _ = select_point_in_time(fundamentals, decision_as_of) docs = sentiment_store.get_documents(ticker=ticker, before=decision_as_of) docs, _ = select_point_in_time(docs, decision_as_of) if rejected_bars or severe_missing(bars): return hold_snapshot(ticker, "PIT_OR_PRICE_DATA_FAILURE") return compute_all_features(ticker, bars, fundamentals, docs, decision_as_of)3.3 Daten-Qualitäts-Gates (pro Bar): not_null, ohlc_sane, no_zero_volume, single_bar_move_reasonable (<50 %), not_stale (≤max_staleness_seconds), spread_ok (≤0,5 %), price_ok (≥$5), adv_ok (≥$1M). Fail in irgendeinem Check → data_quality_status = FAIL → HOLD_DATA_ISSUE.
def data_quality_gate(ticker, bar, prev_bar, quote, now, cfg): checks = { "not_null": all(x is not None for x in [bar.open, bar.high, bar.low, bar.close, bar.volume]), "ohlc_sane": bar.low <= bar.open <= bar.high and bar.low <= bar.close <= bar.high, "no_zero_volume": bar.volume > 0, "single_bar_move_reasonable": abs(bar.close / prev_bar.close - 1) < 0.50, "not_stale": (now - bar.timestamp).total_seconds() <= cfg.max_staleness_seconds, "spread_ok": ((quote.ask - quote.bid) / ((quote.ask + quote.bid) / 2)) <= cfg.max_spread_pct, "price_ok": bar.close >= cfg.min_price_usd, "adv_ok": rolling_adv_usd(ticker, 20) >= cfg.min_adv_usd} status = "PASS" if all(checks.values()) else "FAIL" return status, {k: v for k, v in checks.items() if not v}3.4 Technische Features: Momentum (RSI 14, 1/5/20d-Returns, MACD 12/26/9), Trend (SMA/EMA 20/50/200, Trend-State), Vola/Risk (ATR 14, ATR%, Bollinger 20/2, Gap-Flags), Volume (RVOL 20, OBV-Slope), Execution-Liquidität (ADV USD 20, Spread%, Quote-Alter), Swing-Confluence als Setup-Tags statt Black-Box-Score. ATR ist Pflicht für den Risk-Handoff:
def risk_handoff_from_atr(entry_ref, atr_14): stop_distance = 1.5 * atr_14 return {"atr_stop_distance_1_5x": stop_distance, "suggested_stop_reference": entry_ref - stop_distance, "target_reference_2r": entry_ref + 2.0 * stop_distance, "atr_pct": atr_14 / entry_ref}Standardparameter bewusst, weil frei optimierte Systeme schnell overfitten (ChartsWatcher, Backtesting Pitfalls).
3.5 Corporate Actions: Splits/Dividenden täglich laden + cachen; Indikatoren split-adjusted; ungeklärte Action → HOLD_DATA_ISSUE; Roh- und bereinigte Daten getrennt (Reddit Corporate Actions).
3.6 Grounded Sentiment: nur Dokumente mit Zeitstempel vor as_of; Dedup über text_hash; LLM erhält nur Text/Titel/Zeit/Quelle; Ausgabe {label, score, confidence, evidence_spans, source_doc_ids}; kein Evidence-Span → ungültig; bei kritischen Kandidaten Dual-Model/Dual-Prompt, Dissens → mixed/UNUSABLE. Prompt-Kern: „Nutze kein Weltwissen/keine Kurskenntnis außerhalb des Snapshots; bei Unklarheit INSUFFICIENT_DATA; jede Begründung mit doc_id + wörtlichem Span.” (Invest with AI, AllianceBernstein).
3.7 Caching/Storage: Hot-Cache SQLite (Quotes, Manifests, Status), Cold-Store Parquet pro Provider/Dataset/Date; Raw-first (JSONL + Hash); Idempotenz über (provider, ticker, dataset, start, end, as_of); Rate-Limit-Backoff mit retry_after/quota_remaining; no silent fallback (Provider-Wechsel muss im source_manifest stehen).
4 — LLM-Council-Design der Rolle
Section titled “4 — LLM-Council-Design der Rolle”Kern deterministisch (Preis-/Fundamental-/Indikator-Berechnung, Gates, Caching, PiT-Filter ohne LLM). LLM nur in zwei engen Bereichen: (1) Grounded Sentiment Classifier (quick_think/lokal, T=0, JSON-Schema, Evidence-Spans Pflicht); (2) Data Incident Explainer (fasst Logs zusammen, erzeugt keine Trading-Empfehlung). Sentiment-Council: Subagent A (Finance-Sentiment), Subagent B (general quick_think, evidence-only), optional C (deep_think nur bei hoch-relevanten Deep-Analyst-Kandidaten); Aggregator akzeptiert nur bei kompatiblem Label + vorhandenen Evidence-Spans, sonst UNUSABLE. Token-Regel: Routine max. 1 Runde / 4.000 Input-Tokens; kritisch max. 2 Modelle, kein freier Dialog; kein LLM ergänzt Performance/Preisziele aus Recall.
5 — Konkrete Implementierung (Hermes-Primitiv + Pseudocode + Nachbarrollen)
Section titled “5 — Konkrete Implementierung (Hermes-Primitiv + Pseudocode + Nachbarrollen)”Tools (registry.py): get_allowed_tickers, fetch_market_data, fetch_fundamentals, fetch_corporate_actions, compute_technical_features, data_quality_gate, build_feature_snapshot, write_feature_snapshot. MCP: Alpaca Market Data (keine Order-Funktion sichtbar). Subagent: nur Sentiment/Incident. Cron: Pre-market warmup, Intraday-15-min-Refresh (Watchlist/Shortlist), EOD full snapshot + Audit-Manifest, Daily Corporate-Action-Sync.
def run_data_signal_cycle(run_id, universe_version, decision_as_of, cfg): allowed = universe_tool.get_allowed_tickers(universe_version) if not allowed: return batch_fail(run_id, "NO_ALLOWED_TICKERS") results = [] for item in allowed: ticker = item["ticker"] if item["ethics_status"] != "APPROVED": results.append(blocked_snapshot(ticker, "BLOCKED_ETHICS", item)); continue try: snapshot = build_feature_snapshot(ticker, item, decision_as_of, cfg) except ProviderRateLimit as e: snapshot = hold_snapshot(ticker, "PROVIDER_RATE_LIMIT", details=e.to_dict()) except ProviderUnavailable as e: snapshot = hold_snapshot(ticker, "PROVIDER_UNAVAILABLE", details=e.to_dict()) except Exception as e: snapshot = hold_snapshot(ticker, "UNEXPECTED_DATA_PIPELINE_ERROR", details=safe_error(e)) audit_store.write_snapshot(snapshot); results.append(snapshot) summary = build_batch_summary(run_id, decision_as_of, universe_version, results) audit_store.write_batch_summary(summary); return summaryIntegration: ← Rolle 1 nur allowed_tickers (Hard Block für alles andere); → Rolle 3 feature_snapshot + Batch-Summary als Ground Truth (keine Parallel-Quellen); → Rolle 4 angereicherte Kandidaten-Snapshots inkl. Manifest/Sentiment-Evidence; → Rolle 6 ATR/ATR%/Liquidity-Bucket/Spread/ADV/Gap-Risk; → Rolle 7 aktuelle Spread-/Staleness-Flags fürs Re-Check; → Rolle 10 archivierte Snapshots + Raw-Hashes; → Rolle 11 Health-/Provider-/Cost-Metriken + global_status.
6 — Failure-Modes & Mitigationen
Section titled “6 — Failure-Modes & Mitigationen”| Failure Mode | Detection | Safe Default |
|---|---|---|
| Look-ahead-Bias durch heutige Fundamentals | available_at > as_of | Verwerfen; HOLD_DATA_ISSUE |
| LLM nutzt Pretraining statt Snapshot | fehlende Evidence-Spans | UNUSABLE; Prompt erzwingt INSUFFICIENT_DATA |
| yfinance falsche Adjusted Prices | Provider-Divergenz | yfinance nie primär; Alpaca/Corp-Action prüfen |
| Stale/delayed Quote | now - quote.ts > max_staleness | HOLD_DATA_ISSUE |
| Spread weitet sich | Spread% > 0,5 % bzw. >1 % Notfall | BLOCKED_LIQUIDITY; Execution Limit/Wait |
| Rate Limit | quota_remaining | Batch DEGRADED; betroffene Ticker hold |
| Corporate Action fehlt | Split-Anomalie / >50 % Bar Move | Sync; bis Klärung hold |
| Survivorship Bias | fehlende delisted/Universe-History | Backtest „diagnostisch”; Snapshot-Archiv ab Tag 1 |
| Timezone-Misalignment | gemischte TZ | intern UTC + NYSE-Kalender; DST-Tests |
| Silent Fallback | Manifest fehlt Fallback | Fallback nur explizit + Warnung |
| Sentiment-Spam/Manipulation | Duplikate, neue Accounts, extreme Sprache | Social Sentiment niedrig gewichtet; Dedup; nie primär |
| ToS/Redistribution-Verstoß | fehlende license_note | Manifest mit Lizenznotiz; keine Roh-Redistribution |
7 — Safety / Ethik / Compliance-Hooks
Section titled “7 — Safety / Ethik / Compliance-Hooks”Universe Hard Block (nur ethics_status=APPROVED); Exclusion Carry-Through (Theme-/Ethics-Metadaten bleiben im Snapshot); Long-only-Unterstützung (keine Short-Signale, negative Features sind Warnungen); Paper-Treue (mode=paper gespeichert); HITL-Unterstützung (Manifest + Quality + Warnings + Evidence); voller Audit (Raw-/Code-/Config-/Input-/Output-Hash); No-Advice-Boundary; Provider-Lizenz nur intern; Default Safe: jede schwere Unsicherheit ⇒ Hold.
8 — Eval / KPIs
Section titled “8 — Eval / KPIs”Datenqualität: snapshot_success_rate ≥90 %, stale_data_rate <2 % intraday, corporate_action_resolution_time <1 Handelstag, provider_divergence_rate. Methodik: pit_violation_count = 0 (blockiert Eval-Freigabe), backtest_reproducibility_rate 100 %. Signal: coverage_ok_for_breadth, atr_handoff_valid_rate, sentiment_usable_rate (Qualität > Menge), feature_latency_p95 <10 min (150 Ticker EOD) / <60 s intraday. Safety: unsafe_signal_count = 0, audit_completeness_rate 100 %, sichtbare hold_on_uncertainty_rate.
9 — Offene Fragen / Risiken
Section titled “9 — Offene Fragen / Risiken”Alpaca Free vs. Paid (IEX/15-min-Delay ausreichend?); financial-datasets-Kosten; echte PiT-Fundamentals (sonst degradieren/ausschließen); delisted-Ticker/Survivorship (ab Tag 1 archivieren); Corporate Actions (ungeklärt ⇒ Hold); Sentiment-Datenzugang (erst nach Eval positiver Faktor); LLM-Bias bekannter Aktien trotz Grounding; Timezone/DST-Komplexität zentral normalisieren; Provider-ToS vs. Redistribution; Feature-Overfitting (Walk-Forward + Parameter-Stabilität Pflicht).
Rolle 3 — Breadth Screener (ai-hedge-fund Investor-Personas)
Section titled “Rolle 3 — Breadth Screener (ai-hedge-fund Investor-Personas)”Wichtigste Council-Entscheidungen dieser Rolle:
- Modell & Kosten: alle Persona-Calls auf
quick_think(z. B. GPT-4o-mini), nicht teure Modelle — ~$0,36 statt ~$3,60 pro Ticker; tiefe Debatte erst in Rolle 4 auf der Shortlist.- 5 statt 12 Personas: diversifiziertes Core-Team (Cathie Wood, Damodaran, Peter Lynch, Druckenmiller, Buffett) — halbiert Kosten/Laufzeit bei erhaltener strategischer Diversität.
- Halluzination/Look-ahead: striktes T=0, PiT-Daten-Zwang,
INSUFFICIENT_DATA-Fallback; jedes „Buy” respektiert die Ethik-Exclusion-Liste — ein nicht-approved Ticker wird gedroppt, selbst bei Persona-Konsens.
1 — Mission & Verantwortung
Section titled “1 — Mission & Verantwortung”Der Breadth Screener ist der breite, kosteneffiziente Vorfilter. Er wendet das ai-hedge-fund-Multi-Agenten-Prinzip an, um das vom Universe Architect freigegebene Universum anhand gegensätzlicher Investment-Philosophien (Personas) zu durchleuchten, identifiziert starken Consensus oder signifikante Controversy und erzeugt eine komprimierte Shortlist für die tiefe Analyse (Rolle 4), ohne teure Tokens zu verschwenden.
2 — Inputs / Outputs
Section titled “2 — Inputs / Outputs”Inputs: feature_snapshot von Rolle 2 (PiT-OHLCV, Fundamentals, Technicals); allowed_tickers von Rolle 1 (ethisch bereinigt).
Output — screen_result (kanonisch; ursprünglich screener_results_{date}.jsonl):
{ "ticker": "CRWD", "date": "2026-05-20", "persona_votes": [ {"persona": "Cathie Wood", "signal": "buy", "confidence": 0.8, "reasoning": "..."}, {"persona": "Damodaran", "signal": "hold", "confidence": 0.6, "reasoning": "..."} ], "consensus_buy_pct": 0.8, "controversy_score": 0.2, "recommendation": "BUY_CANDIDATE" // oder DEEP_ANALYZE, HOLD}3 — Methodik & Best Practices
Section titled “3 — Methodik & Best Practices”- 5-Persona-Setup: Cathie Wood (Growth/Innovation), Aswath Damodaran (Valuation-Disziplin), Peter Lynch (Story/Hidden Gems), Stanley Druckenmiller (Macro-Kontext), Warren Buffett (Quality/Moat-Check).
- Consensus vs. Controversy (MarketSenseAI-Methode): hoher Consensus (≥80 % Buy) →
BUY_CANDIDATE(Shortlist); hohe Controversy (Mix Buy/Sell) →DEEP_ANALYZE(Shortlist für Debatte); Konsens Hold/Sell → Drop. - Kosten-Management: parallele Async-Calls der 5 Personas.
4 — LLM-Council-Design der Rolle
Section titled “4 — LLM-Council-Design der Rolle”Zwingend quick_think-Modelle (GPT-4o-mini / Claude-Haiku-Klasse) wegen Volumen (N Ticker × 5 Personas); temperature=0.0 für deterministische Signale; striktes Grounding („Antworte NUR auf Basis des JSON-Snapshots; fehlen Daten, INSUFFICIENT_DATA”). Alle LLM-Calls laufen über das Kosten-/Tracing-Gate von Rolle 11.
5 — Konkrete Implementierung
Section titled “5 — Konkrete Implementierung”Hermes-Primitiv: Subagent (delegate_tool), orchestriert durch einen iterierenden Python-Wrapper, der die Async-Aufrufe bündelt.
async def run_breadth_screen(ticker: str, feature_snapshot: dict) -> dict: personas = ["Cathie Wood", "Damodaran", "Peter Lynch", "Druckenmiller", "Buffett"] tasks = [ask_persona_agent(p, ticker, feature_snapshot, model="gpt-4o-mini", temp=0.0) for p in personas] results = await asyncio.gather(*tasks) buy_count = sum(1 for r in results if r['signal'] == 'buy') sell_count = sum(1 for r in results if r['signal'] == 'sell') consensus_buy_pct = buy_count / len(personas) controversy_score = min(buy_count, sell_count) / len(personas) if consensus_buy_pct >= 0.8: rec = "BUY_CANDIDATE" elif controversy_score >= 0.3: rec = "DEEP_ANALYZE" else: rec = "HOLD" return {"ticker": ticker, "persona_votes": results, "consensus_buy_pct": consensus_buy_pct, "controversy_score": controversy_score, "recommendation": rec}Integration: empfängt Daten von Rolle 2, übergibt die Shortlist (BUY_CANDIDATE + DEEP_ANALYZE) an Rolle 4 für die deep_think-Debatte. Nur approved Ticker werden je verarbeitet.
6 — Failure-Modes & Mitigationen
Section titled “6 — Failure-Modes & Mitigationen”- LLM halluziniert Fundamentaldaten (Look-ahead) → T=0 + Prompt-Constraint; Rolle 4/5 fangen inkonsistente Begründungen ab.
- API-Rate-Limits durch Fan-out → Semaphore/Batching im Async-Loop.
- Persona ohne klares Signal (Parse-Error) → strikter JSON-Zwang; bei Fehler → Default
HOLD.
7 — Safety / Ethik / Compliance-Hooks
Section titled “7 — Safety / Ethik / Compliance-Hooks”- Ethik-Verriegelung: niemals Ticker außerhalb
allowed_tickers. - Long-only-Enforcement: Sell-Signale einzelner Personas fließen nur als
cautionin den Controversy-Score, nie als auszuführende Short-Order.
8 — Eval / KPIs
Section titled “8 — Eval / KPIs”Cost-per-Screen <$0,50/Ticker; Hit-Rate der Shortlist (Anteil BUY_CANDIDATEs, die nach Rolle 4/10 profitabel wären); Latenz kompletter Universum-Scan <15 min.
9 — Offene Fragen / Risiken
Section titled “9 — Offene Fragen / Risiken”- Reicht die Reduktion 12→5 Personas, oder geht Edge verloren?
- Wie kalibriert man die Personas, damit Buffett/Damodaran unprofitable Themen-Growth-Titel nicht durchgängig als „Sell” abstrafen? Ggf. Prompts leicht ans Long-only-Themen-Szenario anpassen.
Rolle 4 — Deep Analyst / Debate (TradingAgents Bull/Bear/Risk)
Section titled “Rolle 4 — Deep Analyst / Debate (TradingAgents Bull/Bear/Risk)”Wichtigste Council-Entscheidungen dieser Rolle:
MAX_ROUNDS = 2Default, harter Cap 3 — Runde 3 nur bei fortbestehender Signal-Divergenz; simple Früh-Stopp-Heuristik (alle Signale gleich → stopp), kein KS-Test in Woche 1.- Endsignal-Aggregation rein deterministisch (Majority-Vote + Divergenz im Code); ein LLM-as-Judge bewertet höchstens Argumentqualität und ist Phase-2/Reconciler-Sache.
- Heterogene Provider (Claude=Bull, GPT=Bear, Gemini=Risk) gegen Echo-Chamber, mit graceful Degradation: <2 Provider ⇒
hold.confidence_rawwird erhoben, aber als UNKALIBRIERT markiert und nie in Rolle 4 als Entscheidungsgewicht genutzt — Kalibrierung erst in Rolle 5.
1 — Mission & Verantwortung
Section titled “1 — Mission & Verantwortung”Der Deep Analyst führt für jeden Kandidaten der Shortlist (Rolle 3) eine strukturierte adversariale Debatte (Bull vs. Bear vs. Risk) durch und erzeugt eine auditierbare, quellengestützte Investment-These (debate_thesis) mit Pro/Contra und Roh-Handlungssignal (buy/hold/skip) plus Divergenz-Maß. Er erzwingt echte Meinungsverschiedenheit statt konsensueller Rationalisierung, entscheidet nicht final und platziert keine Orders — strikte Gewaltenteilung.
2 — Inputs / Outputs
Section titled “2 — Inputs / Outputs”Inputs: shortlist aus Rolle 3 (mit Consensus/Controversy-Scores); feature_snapshot pro Ticker aus Rolle 2 (strikt PiT, grounded); config (max_debate_rounds: 2 (cap 3), deep/quick-Model-Maps). Verboten im Input: vorgefertigte Analysten-Ratings (Herding-Bias), Live-Kurse aus Web, parametrisches Modellwissen zu aktuellen Preisen.
Output — debate_thesis / DebateResult (JSON-Schema, strikt validiert, bei Parse-Fehler ⇒ hold):
{ "ticker": "NVDA", "analysis_date": "2026-01-15", "debate_rounds_used": 2, "bull_thesis": {"summary": "...", "arguments": [ {"claim": "...", "source": "10-Q Q3 2025", "data_point": "Revenue +122% YoY"}, {"claim": "...", "source": "news:2026-01-14:reuters.com", "data_point": "..."}], "signal": "buy", "confidence_raw": 0.82, "model": "claude-opus-4"}, "bear_thesis": {"summary": "...", "arguments": [], "signal": "hold", "confidence_raw": 0.71, "model": "gpt-5.x"}, "risk_assessment": {"summary": "...", "key_risks": ["Regulatory: EU AI Act", "Valuation: P/E 55x vs 35x Sektor", "Ethics-Greyzone-Flag: false"], "signal": "hold", "confidence_raw": 0.65, "model": "gemini-2.5-pro"}, "final_signal": "buy", "debate_divergence_score": 0.41, "escalation_needed": false, "provider_degraded": false, "data_sources_used": ["financial-datasets/10Q", "alpaca/bars", "reddit/wsb"], "model_versions": {"bull": "claude-opus-4-20250514", "bear": "gpt-...", "risk": "gemini-..."}, "confidence_disclaimer": "confidence_raw is UNCALIBRATED; do not weight directly.", "audit_id": "debate_20260115_NVDA_r02"}Jeder Output wird in SQLite (strukturiert) und JSONL (Roh-Transkript jeder Runde) persistiert.
3 — Methodik & Best Practices
Section titled “3 — Methodik & Best Practices”- Multi-Agent Debate (iMAD-Schema, arXiv 2511.11306): Runde 0 — jeder Agent generiert unabhängig (kein gegenseitiges Lesen); Folgerunden — Input = Originalfrage + eigene Vorrunden-These + alle anderen Thesen. Debatte amplifiziert Korrektheit nur bei erzwungener Korrekturbewegung (arXiv 2510.12697).
- TradingAgents-Referenz (arXiv 2412.20138, GitHub): Bull/Bear + 3er-Risk-Team → kompakt auf Bull/Bear/Risk gemappt.
max_debate_rounds=2Default; deep_think für Debatte, quick_think für Datenabruf. - Rundenanzahl-Konsens: 1 = zu wenig; 2 = Praxis-Optimum; 3 = nur bei messbarer Divergenz; ≥4 = Sycophancy-Drift/Token-Explosion (arXiv 2509.23055).
- Quellenpflicht / Grounded-Only: jedes Argument zitiert eine PiT-Quelle, „Fehlende Quelle = kein Argument”.
- Chain-of-Verification (optional, +28 % FActScore) als Verifikations-Pass; Confirmation-Bias-/Sycophancy-Reduktion über harte Personas, Anti-Herding, λ-Tuning, heterogene Provider, keine Ratings im Prompt (arXiv 2507.20957, arXiv 2605.09106).
- Multi-Modell-Kreuzvalidierung ist die stärkste Einzelmaßnahme gegen Halluzination.
4 — LLM-Council-Design der Rolle
Section titled “4 — LLM-Council-Design der Rolle”Nutzt LLMs intensiv — Kern-Debatte-Council. Modelle (heterogen, Soll): Bull = Claude-Opus-Klasse, Bear = GPT-5-Klasse, Risk = Gemini-2.5-Pro-Klasse. Alle 3 Debattierer = deep_think; Daten-Vorverarbeitung (von Rolle 2) = quick_think. Token/Runden: 2 Runden × 3 Agenten × ~4000 Token ≈ 24.000 Token/Kandidat ≈ ~$0,36; Cap 3 Runden bei Divergenz. Persona-Lambda: Bull λ=2, Bear λ=2 (aktive Troublemaker, dürfen nicht ohne neue Gegenargumente zustimmen), Risk λ=3 (moderat, sucht aktiv Schadenswege). Prompt-Strategie: harte Persona + Snapshot + Verbot vorgefertigter Ratings + JSON-Schema + require_sources; Rebuttal mit Anti-Herding-Klausel; Konfidenz als unkalibriert deklariert.
5 — Konkrete Implementierung (Hermes-Stack)
Section titled “5 — Konkrete Implementierung (Hermes-Stack)”Subagent (delegate_tool.py): jeder Debattierer = ein Hermes-Subagent (eigenes Modell/Context, gleicher Snapshot) — der Council-Fan-out. Tool (registry.py): deterministische Aggregation, Schema-Validierung, Audit-Persistenz. MCP nur indirekt (Daten kommen vorverarbeitet von Rolle 2; kein Live-Markt-/Web-Call — Look-ahead-Schutz). Cron: getriggert durch die Pipeline nach R3-Shortlist.
class DebateCouncil: DEBATE_ROLES = { "bull": {"model": "claude-opus-4", "persona_lambda": 2}, "bear": {"model": "gpt-5.x", "persona_lambda": 2}, "risk": {"model": "gemini-2.5-pro", "persona_lambda": 3}, } MAX_ROUNDS = 2 # TradingAgents-Default; cap 3 nur bei Divergenz
def run_debate(self, ticker, snapshot) -> DebateResult: if not snapshot_is_grounded(snapshot): # P3-Gate return DebateResult.hold(ticker, reason="missing/ungrounded data") positions = {} for role, cfg in self.DEBATE_ROLES.items(): # Runde 0: unabhängig, parallel try: positions[role] = delegate_tool.run( agent_prompt=self._build_initial_prompt(role, snapshot, cfg["persona_lambda"]), model=cfg["model"], require_sources=True) except ProviderError: continue # graceful degradation if len(positions) < 2: return DebateResult.hold(ticker, reason="<2 providers available", provider_degraded=True) degraded = len(positions) < len(self.DEBATE_ROLES) for round_n in range(1, self.MAX_ROUNDS + 1): signals = [p["signal"] for p in positions.values()] if len(set(signals)) == 1 and round_n > 1: break # Früh-Stopp bei echtem Konsens for role in list(positions): others = {k: v for k, v in positions.items() if k != role} positions[role] = delegate_tool.run( agent_prompt=self._build_rebuttal_prompt(role, positions[role], others, self.DEBATE_ROLES[role]["persona_lambda"]), model=self.DEBATE_ROLES[role]["model"]) if round_n == self.MAX_ROUNDS: if len(set(p["signal"] for p in positions.values())) > 1 and round_n < 3: self.MAX_ROUNDS = 3 # eine Extra-Runde NUR bei Divergenz return self._aggregate_signals(positions, ticker, degraded)
def _compute_divergence(self, positions) -> float: # 0.0=Konsens .. 1.0=max Divergenz signals = [p["signal"] for p in positions.values()] if len(set(signals)) == 1: return 0.0 return 1.0 - (signals.count(signals[0]) / len(signals))
def _aggregate_signals(self, positions, ticker, degraded) -> DebateResult: # DETERMINISTISCH from collections import Counter signals = [p["signal"] for p in positions.values()] majority = Counter(signals).most_common(1)[0][0] divergence = self._compute_divergence(positions) return DebateResult(ticker=ticker, final_signal=majority, bull_thesis=positions.get("bull"), bear_thesis=positions.get("bear"), risk_assessment=positions.get("risk"), divergence_score=divergence, provider_degraded=degraded, escalation_needed=(divergence > 0.6))Integration: Input von Rolle 3 (Shortlist) + Snapshot von Rolle 2; Output (debate_thesis × Kandidat) an Rolle 5, die aggregiert/kalibriert/Tie-Breaking/HITL macht. escalation_needed/divergence_score triggert in Rolle 5 verschärfte Prüfung. Kein Pfad zu Rolle 7.
6 — Failure-Modes & Mitigationen
Section titled “6 — Failure-Modes & Mitigationen”| Failure-Mode | Mitigation |
|---|---|
| Halluzination unter Prompt-Druck | Grounded-Data-Only; require_sources=True; fehlende Daten ⇒ hold |
| Sentiment-Fabrikation | alle Sentiment-Inputs aus datierten News-Quellen (von Rolle 2) |
| Sycophancy / Premature Consensus | Runden-Cap 2–3; Anti-Sycophancy/Anti-Herding-Prompts; λ-Tuning |
| Look-ahead-Bias | strikt PiT; gepinnte Modellversionen; kein Web-Access in der Debatte |
| Echo-Chamber | Multi-Provider (Claude/GPT/Gemini) |
| Token-Overhead ohne Gewinn | adaptiver Früh-Stopp; max 3 Runden |
| Falsche Konfidenz-Zahlen | confidence_raw als unkalibriert markiert; Kalibrierung erst in Rolle 5 |
| JSON-Parse-Fehler / Schema-Bruch | strikte Validierung; bei Fehler ⇒ hold, kein Auto-Repair |
| Provider-Ausfall | graceful Degradation ≥2 Modelle + Flag; <2 ⇒ hold |
7 — Safety / Ethik / Compliance-Hooks
Section titled “7 — Safety / Ethik / Compliance-Hooks”Long-only-Relevanz (nur buy/hold/skip, keine Short-Thesen); kein Order-Pfad (finale Entscheidung + place_order-Gate + Universe-Recheck liegen außerhalb; HITL bleibt vorgelagert); Grounded-Only & Quellenpflicht (fehlende Daten ⇒ hold); Ethik-Greyzone-Flag (Risk-Agent muss Dual-Use/Rüstungs-/Fossil-Nähe als key_risk flaggen — das harte Gate bleibt bei Rolle 1/9); voller Audit (Runden-Transkript JSONL + strukturierter Output SQLite, model_versions/audit_id/data_sources_used); Determinismus-Insel (Aggregation im Code).
8 — Eval / KPIs
Section titled “8 — Eval / KPIs”| KPI | Zielwert |
|---|---|
| Source-Coverage-Rate | >95 % aller Claims mit Quelle |
| Halluzinations-Spot-Check | <5 % ungegrundete Fakten |
| Divergence-Score bei finalen Buys | Median >0.3 |
| Token-Kosten/Kandidat | <$0,50 |
| Debate-Zeit | <3 min/Kandidat |
| Hit-Rate Buy-Signale (Backtest via Rolle 10) | >55 % positive 5d-Returns |
| Schema-Validitätsrate | >99 % |
9 — Offene Fragen / Risiken
Section titled “9 — Offene Fragen / Risiken”Adaptiver Beta-Binomial/KS-Stopp (Phase 2, braucht Kalibrierungshistorie); LLM-as-Judge für Argumentqualität (Rolle 4 oder 5?); Provider-Bias-Drift bei Modell-Updates; Divergenz-Schwellen-Tuning erst nach ≥50 Live-Debatten; Chain-of-Verification-Kosten; Snapshot-Vollständigkeit als Durchsatz-Engpass.
Quellen u. a.: TradingAgents (arXiv 2412.20138), iMAD (arXiv 2511.11306), Debate-Amplifikation (arXiv 2510.12697), Sycophancy (arXiv 2509.23055), Overconfidence (arXiv 2512.16030), Investment-Bias (arXiv 2507.20957), Agent-as-Judge (arXiv 2508.02994).
Rolle 5 — Reconciler / Chief Investment Officer
Section titled “Rolle 5 — Reconciler / Chief Investment Officer”Wichtigste Council-Entscheidungen dieser Rolle:
- Primär Supermajority ≥2/3, nicht confidence-weighted Voting — rohe LLM-Konfidenz ist als Standalone-Zuverlässigkeit ungeeignet; Gewichtung erst nach ≥100 gelabelten Entscheidungen, dann nur fürs Tie-Breaking.
- Optionaler Argument-Quality-Judge ist Veto-only (
quality_fail/source_gap/contradiction_flag) — darf degradieren, nie eine Buy-Erlaubnis erteilen.- HITL bei definierten Unsicherheits-/Risikozuständen verpflichtend, Timeout-Default
hold.- Phase-1-Kalibrierung = konservative Shrinkage (
0.80 × raw); echte Platt/Temperature-Kalibrierung (Brier/ECE) erst ab ≥100 CIO-Entscheidungen.
1 — Mission & Verantwortung
Section titled “1 — Mission & Verantwortung”Der Reconciler / CIO aggregiert die drei unabhängigen Deep-Analyst-/Debate-Ergebnisse zu einer einzigen, auditierbaren CIO-Entscheidung (reconciled_signal / CIODecision): buy, hold, skip oder ESCALATE_HITL. Er ist kein weiterer Alpha-Generator, sondern ein kalibrierter Entscheidungs- und Safety-Gate-Layer, der Supermajority-Agreement, Quellenqualität, Divergenz, kalibrierte Konfidenz, Risk-Flags und Ethik-/Compliance-Hooks zusammenführt. Er platziert nie Orders — er gibt nur das CIODecision-Artefakt an Rolle 6 weiter; jede Order läuft später ausschließlich über das deterministische place_order-Tool.
2 — Inputs / Outputs (mit Schema/Feldern)
Section titled “2 — Inputs / Outputs (mit Schema/Feldern)”Inputs (pro Kandidat genau ein PiT-Datenstand + drei debate_thesis aus Rolle 4): candidate (ticker, theme_tags, universe_version, ethics_status, liquidity_status), snapshot_meta (as_of_utc, point_in_time_asserted, sources_manifest_hash), debate_results[] (je model_family, model_version, final_signal, confidence_raw, divergence_score, bull/bear/risk-Thesen, source_coverage_rate, unsupported_claim_count), portfolio_context_for_gating (current_equity_exposure_pct, cash_pct, existing_theme_exposure_pct, estimated_position_pct_if_max_size, portfolio_drawdown_pct, paper_trading, live_trading_enabled), system_flags (global_kill_switch, alpaca_paper_trade, mandatory_hitl_enabled, raw_mcp_order_tools_visible_to_llm).
Input-Invarianten: genau drei Debate-Resultate von heterogenen Modellfamilien (Claude/GPT/Gemini); jeder Claim quellenbelegt („fehlende Quelle = kein Argument”); keine Kandidaten mit ethics_status != "allowed", nicht-PiT-Snapshot oder verletzten Paper/Live-Flags.
Output — reconciled_signal / CIODecision (deterministisch; SQLite-Zeile + JSONL):
{ "decision_id": "cio_20260515_NVDA_1337", "run_id": "run_2026-05-15_am", "ticker": "NVDA", "created_at_utc": "2026-05-15T13:37:22Z", "action": "buy", "action_class": "candidate_signal_only", "agreement": {"majority_signal": "buy", "majority_count": 2, "total_models": 3, "agreement_ratio": 0.6667, "individual_signals": ["buy", "buy", "hold"]}, "confidence": {"raw_agreeing_avg": 0.76, "calibration_mode": "phase1_shrinkage", "calibrated_confidence": 0.608, "confidence_bucket": "medium", "calibration_history_n": 37, "brier_score_latest": null, "ece_latest": null}, "quality_gates": {"source_coverage_min": 1.0, "unsupported_claims_total": 0, "avg_divergence_agreeing": 0.39, "judge_quality_flag": "not_run", "contradiction_flag": false}, "safety_gates": {"ethics_gate": "pass", "paper_gate": "pass", "long_only_gate": "pass", "kill_switch_gate": "pass", "extreme_risk_gate": "pass", "position_pct_gate": "pass", "hitl_required": true, "hitl_reason": "mandatory_before_order"}, "routing": {"next_role": "risk_manager_position_sizer", "if_hitl_timeout": "hold", "valid_until_utc": "2026-05-15T20:00:00Z"}, "human_readable_reason": "2/3 Debate-Councils für buy; konservativ geschrumpfte Konfidenz 0.608; keine Quellenlücken; kein extremes Risk-Flag.", "audit": {"input_hash": "sha256:...", "decision_hash": "sha256:...", "model_versions": ["claude-opus-4-20250514", "gpt-5.4", "gemini-2.5-pro"], "source_audit_ids": ["debate_..._claude", "debate_..._gpt", "debate_..._gemini"]}}Erlaubte Actions: buy (nur Kandidatensignal → Risk Manager), hold (keine neue Position), skip (für diesen Run verworfen), ESCALATE_HITL (bei Timeout immer hold).
3 — Methodik & Best Practices
Section titled “3 — Methodik & Best Practices”3.1 Primäre Aggregation: Supermajority ≥2/3. ( \hat{y}=\operatorname{mode}(y_1,y_2,y_3) ), accept only if ( count(\hat{y}) \ge 2 ). buy nur bei ≥2/3 Buy; 3-way-split → immer ESCALATE_HITL. Agreement schlägt rohe Confidence (Nature, Emergent Mind CWMV).
3.2 Konservative Konfidenz-Kalibrierung (Phase 1): ( p_{cal}=\operatorname{clip}(0.80 \times \bar{p}_{raw,agreeing},,0.05,,0.85) ). Die kalibrierte Konfidenz darf in Phase 1 keine Position vergrößern — nur buy→hold/ESCALATE_HITL degradieren. Phase 2 ab ≥100 Entscheidungen: Brier Score (( BS=\frac1N\sum(f_t-o_t)^2 ), Ziel <0.20), ECE (( ECE=\sum_m \frac{|B_m|}{n}|acc(B_m)-conf(B_m)| ), Ziel <0.05), Reliability Diagram, Platt/Temperature Scaling (arXiv 2409.19817, Brier Score).
3.3 Quality Gates vor Signalannahme: verworfen/eskaliert, wenn source_coverage_rate < 0.95, unsupported_claim_count > 0 bei Kernargumenten, avg_divergence_agreeing > 0.50, Judge quality_fail/contradiction_flag/source_gap, oder Risk-Assessment extreme_risk=true bei Buy.
3.4 HITL-Schwellen:
| Situation | Aktion | Default ohne Antwort |
|---|---|---|
| 3-way-split ohne ≥2/3 | ESCALATE_HITL | hold |
| Kalibrierte Konfidenz <0.45 | hold/ESCALATE_HITL | hold |
| Buy-Mehrheit aber extreme Risk | ESCALATE_HITL | hold |
| Divergence >0.70 in allen Modellen | ESCALATE_HITL | hold |
| Ethik-Grauzone / Dual-Use unklar | skip/ESCALATE_HITL | hold |
| Geschätzte Positionsgröße >8 % Portfolio | ESCALATE_HITL vor Risk Manager | hold |
| Globaler Kill-Switch aktiv | hold | hold |
Die 8 %-Schwelle ist bewusst strenger als das spätere 10 %-Hard-Cap von Rolle 6 — der CIO markiert große Einzelrisiken früh.
3.5 Optionaler Argument-Quality-Judge: deep_think-Modell, das nicht an der Debatte teilnahm; bewertet nur Quellenvollständigkeit/-Fit, Widersprüche, Horizont-Relevanz, Sentiment-Fabrikation/parametrisches Wissen — Veto-only (kann degradieren, nie upgraden, arXiv 2508.02994).
4 — LLM-Council-Design der Rolle
Section titled “4 — LLM-Council-Design der Rolle”Primär deterministisch. LLM nur optional: Human-readable Summary (quick_think/Template), Argument-Quality-Judge (deep_think, vierte Modellfamilie wenn verfügbar, Veto-only), Telegram-HITL-Digest. Judge-Systemregeln: „Du darfst keine Kaufentscheidung treffen; bewerte nur Belegqualität/Konsistenz/Snapshot-Treue; fehlende Quelle = source_gap; unklare Ethik = ethics_unclear; nicht-PiT = pit_fail.” Judge-Output: {quality_flag, source_gap, contradiction_flag, pit_fail, ethics_unclear, reason_codes, short_explanation}. Kein Mehr-Runden-Dialog; max. 1 Pass / 2.000–3.000 Token; kein Web-/Datenabruf (Look-ahead-Schutz).
5 — Konkrete Implementierung (Hermes-Primitiv + Pseudocode + Nachbarrollen)
Section titled “5 — Konkrete Implementierung (Hermes-Primitiv + Pseudocode + Nachbarrollen)”Tool (registry.py): reconcile_cio_decision(input) -> CIODecision. Subagent: optionaler argument_quality_judge (nur bei enable_judge=true/Grenzfällen). MCP: kein Trading-Zugriff (Alpaca unsichtbar). Cron: nach Rolle 4 + Weekly Kalibrierungsreport. Persistence: SQLite cio_decisions, cio_calibration_events, cio_hitl_alerts + JSONL.
from collections import CounterACTIONS = {"buy", "hold", "skip"}
class ReconcilerCIO: AGREEMENT_THRESHOLD = 2; MIN_CONF_ACCEPT = 0.45; FAST_TRACK_CONF = 0.65 MAX_AVG_DIVERGENCE_AGREEING = 0.50; MAX_DIVERGENCE_ALL = 0.70 MIN_SOURCE_COVERAGE = 0.95; LARGE_POSITION_ESCALATE_PCT = 0.08 PHASE1_CONFIDENCE_SHRINK = 0.80
def reconcile(self, payload: dict) -> CIODecision: self._assert_schema(payload) results = payload["debate_results"] if (hard := self._hard_safety_precheck(payload)): return self._decision(payload, **hard) if (qual := self._quality_precheck(results)): return self._decision(payload, **qual) signals = [r["final_signal"] for r in results] if any(s not in ACTIONS for s in signals): return self._safe_hold(payload, "Invalid signal in debate results") majority_signal, majority_count = Counter(signals).most_common(1)[0] if majority_count < self.AGREEMENT_THRESHOLD: return self._escalate_hitl(payload, reason="3-way-split: no 2/3 supermajority", default_if_timeout="hold") agreeing = [r for r in results if r["final_signal"] == majority_signal] cconf = self._calibrated_confidence(agreeing, payload) avg_div = sum(r["divergence_score"] for r in agreeing) / len(agreeing) max_all_div = max(r["divergence_score"] for r in results) if cconf < self.MIN_CONF_ACCEPT: return self._decision(payload, action="hold", reason=f"Low calibrated confidence {cconf:.3f}") if avg_div > self.MAX_AVG_DIVERGENCE_AGREEING: return self._escalate_hitl(payload, reason=f"High divergence among agreeing {avg_div:.3f}", default_if_timeout="hold") if max_all_div > self.MAX_DIVERGENCE_ALL: return self._escalate_hitl(payload, reason=f"Extreme divergence {max_all_div:.3f}", default_if_timeout="hold") if majority_signal == "buy" and self._any_extreme_risk(results): return self._escalate_hitl(payload, reason="Buy majority but extreme risk", default_if_timeout="hold") if majority_signal == "buy" and self._estimated_position_pct(payload) > self.LARGE_POSITION_ESCALATE_PCT: return self._escalate_hitl(payload, reason="Estimated position >8%", default_if_timeout="hold") hitl_required = (majority_signal == "buy") return self._decision(payload, action=majority_signal, calibrated_confidence=cconf, hitl_required=hitl_required, hitl_reason="mandatory_before_order" if hitl_required else None)
def _hard_safety_precheck(self, p): c, flags, snap = p["candidate"], p["system_flags"], p["snapshot_meta"] if flags.get("global_kill_switch"): return {"action":"hold","reason":"Global kill-switch active"} if not flags.get("alpaca_paper_trade"): return {"action":"hold","reason":"Paper-trading flag not asserted"} if flags.get("live_trading_enabled"): return {"action":"hold","reason":"Live trading enabled during paper phase"} if flags.get("raw_mcp_order_tools_visible_to_llm"): return {"action":"hold","reason":"Raw MCP order tools visible to LLM"} if c.get("ethics_status") != "allowed": return {"action":"skip","reason":"Ethics gate failed/unclear","hitl":True} if not snap.get("point_in_time_asserted"): return {"action":"hold","reason":"PiT snapshot not asserted"} return None
def _calibrated_confidence(self, agreeing, payload): n = self._calibration_history_n(payload) raw_avg = sum(float(r.get("confidence_raw", 0.50)) for r in agreeing) / len(agreeing) if n < 100: return max(0.05, min(0.85, raw_avg * self.PHASE1_CONFIDENCE_SHRINK)) return self._apply_persisted_calibration(raw_avg, agreeing) # Phase 2SQLite-Skizze (Auszug): cio_decisions(decision_id PK, run_id, ticker, action CHECK IN ('buy','hold','skip','ESCALATE_HITL'), majority_count, calibrated_confidence, hitl_required, reason, input_hash, decision_hash, full_json); cio_calibration_events(decision_id PK, horizon_days, predicted_action, predicted_confidence, outcome_direction_correct, realized_return, brier_component).
Telegram-HITL-Digest (knapp, strukturiert, nicht manipulativ): Reason, Snapshot-Zeit + PiT-OK, je Modell signal/conf_raw/div, je 1 belegter Bull-/Bear-/Risk-Satz, Ethics/Paper/Live-Status, „Default in 5 min: HOLD”, Buttons APPROVE_FOR_RISK_MANAGER / HOLD / SKIP.
Integration: ← Rolle 4 drei debate_thesis; → Rolle 6 nur action ∈ {buy,hold,skip} + Confidence/Flags (Rolle 6 sizt deterministisch); kein direkter Pfad zu Rolle 7; → Rolle 9 volle Auditdaten/Ethik-Flags/HITL-Status; → Rolle 10 gelabelte Decisions für Brier/ECE/Hit-Rate; → Rolle 11 Kill-Switch/Cost-Meter/Healthchecks/Timeout-Defaults.
6 — Failure-Modes & Mitigationen
Section titled “6 — Failure-Modes & Mitigationen”| Failure-Mode | Mitigation |
|---|---|
| Rohe LLM-Konfidenz als Wahrheit | Phase-1-Shrinkage 0.80; keine Confidence-only-Buys; Brier/ECE erst nach Outcome-Historie |
| 2/3-Mehrheit durch identischen Bias herdiert | Pflicht heterogene Modellfamilien; keine Ratings im Prompt; Quellen-/Divergenz-Gates |
| 3-way-split zufällig entschieden | immer ESCALATE_HITL, Timeout hold |
| Judge überschreibt Safety | Judge ist Veto-only; deterministischer Code finalisiert |
| Quellen fehlen / nicht PiT | source_coverage_rate, unsupported_claim_count, point_in_time_asserted, Manifest-Hash; Fail → hold/skip |
| Buy trotz extremem Risk | extreme_risk=true erzwingt HITL/hold |
| Paper/Live-Flag inkonsistent | ALPACA_PAPER_TRADE/LIVE_TRADING_ENABLED geprüft; sonst hold |
| Persistenz fällt aus | Fail-closed: Decision ungültig ohne SQLite/JSONL-Write |
| Telegram nicht erreichbar | Timeout hold; Alert-Failure auditierbar |
| High-Beta-Themen kollabieren gemeinsam | Theme-/Exposure-Flags an Rolle 6; CIO markiert Cluster-Risiko |
7 — Safety / Ethik / Compliance-Hooks
Section titled “7 — Safety / Ethik / Compliance-Hooks”Long-only (nur buy/hold/skip/ESCALATE_HITL); Paper-Gate (gültig nur bei alpaca_paper_trade=true & live_trading_enabled=false); No Direct Execution; Mandatory HITL (hitl_required=true für jedes buy); Ethik-Gate (Exclusion + Universe-Status erneut geprüft); voller Audit (Input-/Decision-Hash, Modellversionen, Gate-Ergebnisse); EU/AT-Kontext (Eigenhandels-Research, keine Anlageberatung); Fail-Closed Defaults; Model-Version Pinning; Data Lineage (sources_manifest_hash + snapshot_id für Rolle-10-Leakage-Checks).
8 — Eval / KPIs
Section titled “8 — Eval / KPIs”Brier <0.20 (≥100 Entscheidungen, wöchentlich); ECE <0.05; HITL-Eskalationsrate 10–25 %; Agreement ≥2/3 >75 %; Directional Hit-Rate 5d >55 %; Source-Coverage 100 % bei akzeptierten Buys; Fail-Closed-Compliance 100 %; Persistence 100 %; Reconcile-Latenz <5 s (ohne Judge) / <45 s (mit Judge); Cost/Candidate <$0,05 (ohne) / <$0,20 (mit Judge); Post-HITL-Timeout <10 %.
9 — Offene Fragen / Risiken
Section titled “9 — Offene Fragen / Risiken”Outcome-Definition für Kalibrierung (Empfehlung: direction_correct_5d + realized_trade_pnl parallel speichern, Brier zunächst auf 5d-Direction); Kalibrierung pro Modellfamilie vs. Ensemble; hold vs. skip-Semantik konsistent über R3/4/10; Judge-Kosten/Nutzen (nur bei Grenzfällen); HITL-Mensch als Bias-Quelle (Overrides separat taggen); High-Beta-Korrelation (endgültige Cluster-Logik bei Rolle 6); regulatorische Grenze bei Produktisierung; Modell-Drift als neues Kalibrierungssegment; Snapshot-Staleness (valid_until_utc); Paper→Live-Go/No-Go (≥4 Wochen Paper + Compliance + Rolle 10/11/9). Chairperson-Urteil: Woche-1-CIO = konservativer, deterministischer Gatekeeper mit Supermajority, Shrinkage, harter Quellen-/Safety-Prüfung, HITL-Default hold.
Rolle 6 — Risk Manager & Position Sizer
Section titled “Rolle 6 — Risk Manager & Position Sizer”Wichtigste Council-Entscheidungen dieser Rolle:
- ATR-basiertes Volatility Targeting (1 % Risk) statt (Fractional) Kelly — Kelly braucht verlässliche Gewinnwahrscheinlichkeiten, und LLM-
p-Schätzungen sind systematisch überkonvergent.- Simple Hard-Caps in Phase 1 statt HRP/PyPortfolioOpt — komplexe Optimizer maximieren bei kleinen Portfolios (N<50) nur den Schätzfehler („Markowitz’s Curse”).
- Aggressive Drawdown-Tiers — die Asymmetrie von Drawdowns erzwingt frühes Abwürgen systemischer Schocks.
- Kein LLM — rein deterministischer Python-Code (LLMs rechnen fehlerhaft mit Floats und halluzinieren Begründungen zum Ignorieren von Caps).
1 — Mission & Verantwortung
Section titled “1 — Mission & Verantwortung”Der Risk Manager empfängt das positive CIO-Signal (reconciled_signal, action=buy) und transformiert es in eine konkrete, risiko-adjustierte Positionsgröße samt Stop-Loss (sized_order). Er operiert als 100 % deterministischer Algorithmus (kein LLM) und schützt das Portfolio rücksichtslos vor Konzentrationsrisiken, Cluster-Korrelationen und katastrophalen Drawdowns. Bei Limit-Verletzung vetot er den Trade (no_order).
2 — Inputs / Outputs
Section titled “2 — Inputs / Outputs”Inputs: cio_decision (aus Rolle 5, z. B. {"ticker":"NVDA","action":"buy"}); portfolio_state (Total Equity, Cash, offene Positionen mit Themen-Tags/Gewichten); market_data (Preishistorie 20d, aktueller Kurs, (ATR_{14}), Korrelationsmatrix bestehender Positionen — aus dem risk_handoff des feature_snapshot).
Output — sized_order (Order):
{ "action": "buy", "ticker": "NVDA", "shares": 145, "stop_loss_price": 102.50, "position_value": 15500.00, "pct_of_portfolio": 0.08, "sizing_method": "ATR-1pct-Risk", "risk_per_trade_dollars": 850.00, "rejection_reason": null}(Bei Ablehnung: action="no_order", rejection_reason gefüllt, Shares/Werte = 0.)
3 — Methodik & Beste Praktiken
Section titled “3 — Methodik & Beste Praktiken”- Volatility Targeting: ATR-basiertes Sizing — Positionsgröße = Risikobudget (1 % Gesamtkapital) / Stop-Abstand (2 × (ATR_{14})) (Quantified Strategies).
- Hard-Caps: max. 10 % pro Einzelposition, max. 30 % pro Themen-Cluster, max. 80 % Total Equity (Long-only).
- Cash-Buffer: permanent 20 % Cash (Liquiditätsreserve bei Gaps, dämpft Drawdowns, verhindert Margin-Calls).
- Drawdown-Kontrolle: Tier-System — ab −5 % halbes Risiko für Neupositionen, ab −20 % Full Exit in Cash (Zwischenstufe −15 % → reduce all).
- Korrelations-Limit: max. Pearson-Korrelation 0.70 zu bestehenden Positionen.
4 — LLM-Council-Design der Rolle
Section titled “4 — LLM-Council-Design der Rolle”Kein LLM. Rein deterministisch — klassisches Python-Modul, das im Orchestrator/Execution-Pfad aufgerufen wird.
5 — Konkrete Implementierung
Section titled “5 — Konkrete Implementierung”Hermes-Primitiv: Standard-Tool (registry.py), nicht vom LLM aufgerufen, sondern als Hard-Coded-Middleware zwischen Rolle 5 (Reconciler) und Rolle 7 (Execution) geschaltet.
class RiskManager: LIMITS = { "max_single_position_pct": 0.10, "max_theme_cluster_pct": 0.30, "max_total_equity_pct": 0.80, "min_cash_buffer_pct": 0.20, "max_correlation": 0.70, "atr_risk_pct": 0.01, "atr_multiplier": 2.0, } def compute_size(self, ticker, signal, portfolio, market_data): if signal != "buy": return Order(action="no_order", reason="Not a buy signal") if portfolio.cash_pct() < self.LIMITS["min_cash_buffer_pct"]: return Order(action="no_order", reason="Insufficient cash buffer") theme = get_theme(ticker) if portfolio.theme_exposure(theme) >= self.LIMITS["max_theme_cluster_pct"]: return Order(action="no_order", reason=f"Theme {theme} maxed out") if self._check_correlation(ticker, portfolio, market_data) > self.LIMITS["max_correlation"]: return Order(action="no_order", reason="Correlation limit exceeded") current_price = market_data["price"]; atr_14 = market_data["atr_14"] risk_dollars = portfolio.total_capital * self.LIMITS["atr_risk_pct"] stop_dist = atr_14 * self.LIMITS["atr_multiplier"] shares = risk_dollars / stop_dist pos_value = shares * current_price pos_value = min(pos_value, portfolio.total_capital * self.LIMITS["max_single_position_pct"]) allowed_new_equity = (portfolio.total_capital * self.LIMITS["max_total_equity_pct"]) - portfolio.current_equity pos_value = min(pos_value, max(0, allowed_new_equity)) final_shares = int(pos_value / current_price) if final_shares == 0: return Order(action="no_order", reason="Position too small after caps") stop_loss_price = round(current_price - stop_dist, 2) assert (final_shares * current_price) <= (portfolio.total_capital * 0.12), "CRITICAL: Sizing overflow" return Order("buy", ticker, final_shares, stop_loss_price, pos_value)Integration: ← Rolle 5 Buy-Signal; nutzt ATR/Liquidity-Bucket aus dem feature_snapshot (Rolle 2); → Rolle 7 liefert sized_order mit zwingendem stop_loss_price (serverseitiger Stop). Ganzzahlige shares werden erzwungen (Voraussetzung für Bracket-Schutz bei Rolle 7).
6 — Failure-Modes & Mitigationen
Section titled “6 — Failure-Modes & Mitigationen”- Vollständige Korrelation im Krisenfall (thematische ETFs korrelieren im Crash bis ~0.90) → 20 % Cash-Buffer + Drawdown-Tiers (−15 % → reduce all) entkoppeln teilweise vom Marktbeta.
- Falsche ATR-Schätzung (Splits/Gaps) → Hard-Cap (max. 10 %) verhindert massive Position aus winziger fehlerhafter ATR.
- Floating-Point/Sizing-Overflow → harter
assertblockiert ausnahmslos jede Order >12 % Gesamtkapital (Anti-Fat-Finger).
7 — Safety / Ethik / Compliance-Hooks
Section titled “7 — Safety / Ethik / Compliance-Hooks”- Deterministisches Veto-Recht: verwirft jede KI-Entscheidung geräuschlos bei Limit-Riss.
- Mandatory Stops: jede Order muss mit
stop_loss_pricean Rolle 7 (serverseitiger Stop). - GICS-Sektor-Kontrolle: abschließende Prüfung gegen die globale Exclusion-Liste (z. B. Aerospace & Defense), falls Rolle 1 etwas übersehen hat — dritte Verteidigungslinie nach Rolle 1 und Rolle 7.
8 — Eval / KPIs
Section titled “8 — Eval / KPIs”Max Portfolio Drawdown <20 %; Regelkonformität 100 % (per SQLite-Audit); Cash-Buffer-Resilience >95 % der Zeit ≥15 % Cash; ATR-Stop-Hit-Rate <40 % (kalibriert den ATR-Multiplikator).
9 — Offene Fragen / Risiken
Section titled “9 — Offene Fragen / Risiken”Markowitz-Phase-2-Transition (wann sind Kovarianz-Schätzungen robust genug für HRP?); Gap-Risiko bei Earnings (Earnings-Calendar-Filter, der Sizing vor Quartalszahlen halbiert?); Beta-Drift (rollierender Portfolio-Beta-Check <1.5 zur NASDAQ-Proxy-Vermeidung). (HRP-/Markowitz-Befund: Columbia HRP-Studie; Overconfidence: arXiv 2512.16030.)
Rolle 7 — Execution Trader
Section titled “Rolle 7 — Execution Trader”Wichtigste Council-Entscheidungen dieser Rolle:
- GTC-Bracket als einziger Order-Standard (Entry + TP + SL atomar, serverseitig, überlebt VM-Crash, MAR-konform); Entry = Limit (kalibriert), Stop-Loss = Stop-Market (garantierter Fill bei Gap), Take-Profit = Limit.
- Genau ein deterministisches
place_order-Tool wird den Modellen exponiert; die rohen ~43 MCP-Tools bleibeninternal_onlyund LLM-unsichtbar — die wichtigste Sicherheitsentscheidung der Rolle.- Ein-Schuss-Re-Pricing via atomarem
replace_orderauf die Pending-Entry-Leg (kein Loop, max. 1 Replace), dann Cancel +HOLD.- Gestaffelte Redundanz: Long-only, Ethik-Exclusion, Paper-Mode-Live-Verifikation, Kill-Switch und frischer HITL-Token werden immer im Gate geprüft; Sizing bleibt Single-Source bei Rolle 6 mit nur einer groben Notbremse. PDT-Felder werden nirgends gelesen (Entfernung aus API ab 6. Juli 2026).
1 — Mission & Verantwortung
Section titled “1 — Mission & Verantwortung”Der Execution Trader ist das einzige deterministische Gateway zwischen LLM-Empfehlung und realer Marktinteraktion. Er empfängt einen von Rolle 5/6 freigegebenen, gesizten, HITL-approbierten ApprovedOrderRequest, erzwingt unabhängig Long-only, Ethik-Exclusion, Exposure-Notbremse, Paper-Mode und Kill-Switch, platziert dann eine atomare GTC-Bracket-Order über den alpaca-mcp-server und protokolliert jede Aktion (ExecutionResult). Bei jeder Unsicherheit → HOLD / no-trade. Kein LLM — bewusst das langweiligste, prüfbarste Stück der Agency.
2 — Inputs / Outputs
Section titled “2 — Inputs / Outputs”Input — ApprovedOrderRequest (von Rolle 5/6 via delegate_tool, nach HITL):
@dataclass(frozen=True)class ApprovedOrderRequest: trace_id: str # UUID, durchgängig durch alle Rollen symbol: str side: Literal["buy"] # NUR buy — alles andere wird hart geblockt qty: int # ganzzahlige Shares (von Rolle 6 gesizt) entry_order_type: Literal["limit"] = "limit" limit_price: float take_profit_price: float stop_loss_price: float # SL-Leg (Stop-Market by default) stop_limit_buffer: float | None = None # nur wenn Rolle 8 Stop-Limit will time_in_force: Literal["gtc","day"] = "gtc" hitl_token: str # signierter, zeitlich begrenzter Approval-Token hitl_issued_at: str # ISO 8601 — Frische-Check (max 15 Min) risk_snapshot: dict # Exposure-Kontext von Rolle 6 data_snapshot_hash: str # SHA256 der zugrundeliegenden Daten (Audit) model_version: str # gepinnte Modellversion(en) der EmpfehlungOutput — ExecutionResult (an Rolle 8 für Exit-Tracking + Rolle 9 für Audit):
@dataclass(frozen=True)class ExecutionResult: trace_id: str status: Literal["SUBMITTED","FILLED","PARTIAL","REJECTED","BLOCKED","HOLD","REPRICED","EXPIRED"] symbol: str; requested_qty: int; filled_qty: int avg_fill_price: float | None bracket_order_id: str | None; tp_leg_id: str | None; sl_leg_id: str | None client_order_id: str # Idempotenz-Schlüssel = f"{trace_id}-entry" block_reason: str | None slippage_bps: float | None # Implementation Shortfall (für Rolle 10) submitted_at: str raw_alpaca_response: dictJeder Output (auch jeder BLOCKED) wird als Audit-Event (actor="execution_gate") in SQLite + JSONL geschrieben.
3 — Methodik & Best Practices
Section titled “3 — Methodik & Best Practices”3.1 GTC-Bracket als alleiniger Standard. Entry + TP + SL in einem Aufruf (order_class="bracket"): (a) von Alpacas Wash-Trade-Schutz ausgenommen (Alpaca Forum); (b) GTC-Legs leben serverseitig, überleben VM-Crashes (Alpaca Orders); (c) MAR-Compliance. Kein Position-Open ohne Stop.
3.2 Order-Type-Matrix: Entry = limit (kalibriert, Slippage-Kontrolle); Take-Profit = limit; Stop-Loss = stop (Market-on-Trigger, garantierter Schutz-Fill bei Gap; Stop-Limit nur auf explizite Rolle-8-Anweisung via stop_limit_buffer) (Alpaca 13 Order Types).
3.3 Limit-Kalibrierung & Slippage-Gate: get_stock_snapshot ziehen; spread_pct = (ask−bid)/bid. Hard-Gate spread_pct < 0,1 % (sonst BLOCKED). Entry-Limit folgt Rolle-6-Preis; sonst bid + 0,5·spread. slippage_bps = 10000·(avg_fill − decision_price)/decision_price → Rolle 10.
3.4 Ein-Schuss-Re-Pricing: nach FILL_TIMEOUT=10min genau ein replace_order auf die Entry-Leg, Limit um min(0,15 %, 0,5·spread_now) aggressiver; danach cancel_order_by_id → HOLD. Kein Loop.
3.5 Idempotenz: client_order_id = f"{trace_id}-entry"; bei Timeout get_orders(client_order_id=...) statt Neuplatzierung.
3.6 Liquid-Universe-Pflicht: nur >$1M Tagesvolumen und Spread <0,1 % (Trade That Swing).
3.7 IMD-Hygiene: liest nur buying_power/cash aus frischem get_account_info; PDT-Felder (daytrade_count, pattern_day_trader) werden nirgends referenziert (Entfernung bis 6. Juli 2026); Order abgelehnt, wenn Notional > buying_power (verhindert IMD-Erzeugung) (Alpaca FINRA Retires PDT).
4 — LLM-Council-Design der Rolle
Section titled “4 — LLM-Council-Design der Rolle”Kein LLM. Execution ist der schadensträchtigste Punkt; Non-Determinismus/Halluzination/Sentiment-Fabrikation sind untragbar (eine halluzinierte side oder ein erfundener Ticker = realer Kapitalverlust). Das „Council-Denken” lebt in den Validierungsschichten (Defense-in-Depth), nicht in Modell-Voten. Die LLM-Voten sind upstream (R3–5) bereits in ApprovedOrderRequest eingefroren. Rohe MCP-Order-Tools internal_only; nur deterministisches place_order exponiert.
5 — Konkrete Implementierung
Section titled “5 — Konkrete Implementierung”Tool (registry.py): place_order — das EINZIGE exponierte Execution-Tool. MCP (mcp_tool.py): Bindung an alpacahq/alpaca-mcp-server (via uvx), alle Tools internal_only. Subagent: Rolle 7 wird von 5/6 delegiert, meldet ExecutionResult an Rolle 8. Cron: Re-Pricing-Timeout-Check + Pending-Order-Reconcile.
class ExecutionGate: """Einziges exponiertes Execution-Tool. Deterministisch, kein LLM.""" EXCLUDED = frozenset([ # gespiegelt aus Universe (Rolle 1) "LMT","RTX","NOC","GD","BA","LHX","HII","TDG","ITA","XAR", "XOM","CVX","COP","OXY","PSX","VLO","MPC","XLE","USO", "MO","PM","BTI","DKNG","MGM","WYNN","CZR","LVS","PENN","PLTR", ]) EXCLUDED_SIC = frozenset([2911, 1311, 3812, 2111]) # Petroleum, Crude, Defense, Tobacco FILL_TIMEOUT = timedelta(minutes=10) HITL_MAX_AGE = timedelta(minutes=15) HARD_MAX_NOTIONAL = 25_000.0 # absolute Notbremse, unabh. von Rolle 6
def place_order(self, req: ApprovedOrderRequest) -> ExecutionResult: if kill_switch_active(): # 0. Kill-Switch zuerst return self._blocked(req, "Globaler Kill-Switch aktiv") if req.side != "buy": # 1. Long-only HART return self._blocked(req, f"Nur Long erlaubt. side={req.side}") if req.symbol in self.EXCLUDED: # 2. Ethik-Exclusion unabhängig re-checken return self._blocked(req, f"{req.symbol} im Ethik-Exclusion-Set") asset = mcp.get_asset(req.symbol) # internal_only if asset.sic_code in self.EXCLUDED_SIC: return self._blocked(req, f"SIC {asset.sic_code} ausgeschlossen") if not asset.tradable: return self._blocked(req, "Asset nicht handelbar") acct = mcp.get_account_info() # 3. Paper-Mode LIVE verifizieren if not LIVE_TRADING_ENABLED and acct.account_type != "paper": return self._blocked(req, "Paper-Mode nicht bestätigt (account_type!=paper)") if not verify_hitl_token(req.hitl_token, req.trace_id): # 4. HITL frisch & gültig return self._blocked(req, "HITL-Token ungültig/fehlt") if now_utc() - parse_iso(req.hitl_issued_at) > self.HITL_MAX_AGE: return self._blocked(req, "HITL-Token abgelaufen (>15 Min)") snap = mcp.get_stock_snapshot(req.symbol) # 5. Slippage-/Liquiditäts-Gate spread_pct = (snap.quote.ask - snap.quote.bid) / snap.quote.bid if spread_pct >= 0.001: return self._blocked(req, f"Spread {spread_pct:.4f} zu weit (illiquide)") notional = req.qty * req.limit_price # 6. Exposure-Notbremse + Buying-Power if notional > self.HARD_MAX_NOTIONAL: return self._blocked(req, f"Notional {notional} > Hard-Cap") if notional > float(acct.buying_power): # verhindert IMD return self._blocked(req, "Notional > Buying Power") # ---- PLATZIERUNG: atomare GTC-Bracket, idempotent ---- client_oid = f"{req.trace_id}-entry" stop_leg = {"stop_price": req.stop_loss_price} if req.stop_limit_buffer is not None: stop_leg["limit_price"] = req.stop_loss_price - req.stop_limit_buffer try: resp = mcp.place_stock_order( symbol=req.symbol, side="buy", quantity=req.qty, order_type="limit", limit_price=req.limit_price, time_in_force=req.time_in_force, order_class="bracket", take_profit={"limit_price": req.take_profit_price}, stop_loss=stop_leg, client_order_id=client_oid) except DuplicateOrderError: resp = mcp.get_orders(client_order_id=client_oid) except (APITimeout, ConnectionError): existing = mcp.get_orders(client_order_id=client_oid) if not existing: return self._hold(req, "API-Timeout, keine Order gefunden — hold") resp = existing result = self._to_result(req, resp, decision_price=req.limit_price) audit_log(actor="execution_gate", action="ORDER_SUBMITTED", result=result) notify_role8(result) schedule_fill_timeout(client_oid, self.FILL_TIMEOUT) return result
def on_fill_timeout(self, client_oid: str): # Cron: genau EIN Re-Price, dann Cancel order = mcp.get_orders(client_order_id=client_oid) if order.status in ("filled","partially_filled","canceled"): return if order.replaced_once: mcp.cancel_order_by_id(order.id) audit_log(actor="execution_gate", action="HOLD", reason="kein Fill nach Reprice"); return snap = mcp.get_stock_snapshot(order.symbol) spread = snap.quote.ask - snap.quote.bid new_limit = order.limit_price * (1 + min(0.0015, 0.5*spread/order.limit_price)) mcp.replace_order(order.id, limit_price=new_limit) audit_log(actor="execution_gate", action="REPRICED", new_limit=new_limit) schedule_fill_timeout(client_oid, self.FILL_TIMEOUT)Integration: ← Rolle 5/6 ApprovedOrderRequest (Sizing + HITL-Token); → Rolle 8 jeder Fill (inkl. Partial!) sofort gemeldet (Bracket-Legs auf filled_qty, nicht requested_qty); → Rolle 9 jede Aktion als Audit-Event; → Rolle 10 slippage_bps; ← Rolle 8 Exit-Signale nicht über place_order (buy-only), sondern über ein separates deterministisches close_position/replace_order-Tool mit derselben Audit-/Kill-Switch-Disziplin.
6 — Failure-Modes & Mitigationen
Section titled “6 — Failure-Modes & Mitigationen”| Failure-Mode | Mitigation |
|---|---|
| LLM empfiehlt Short/Sell | Schritt 1: side != "buy" → hard BLOCK, vor allem |
| Ethik-Ticker durchgerutscht | Schritt 2: unabhängiger Frozenset- + SIC-Recheck |
| 403 Wash-Trade | ausschließlich atomare Bracket-Orders |
| Doppelte Order bei Retry | client_order_id-Idempotenz; bei Timeout get_orders statt Replatzierung |
| Stop feuert nicht bei Gap | Default Stop-Market auf SL-Leg |
| Kein Fill (Limit) | Ein-Schuss-Reprice, dann Cancel + HOLD |
| Partial Fill falsch gebucht | Bracket-Legs auf filled_qty; ExecutionResult.filled_qty an Rolle 8 |
| IMD-Restriktion (ab Juni 2026) | Pre-Trade buying_power-Check; kein Leverage; keine PDT-Felder |
| Code bricht ab 6. Juli 2026 | PDT-Felder nirgends referenzieren |
| Live statt Paper gefeuert | account_type aus frischem Live-API-Response prüfen |
| Order ohne HITL | signierter Token + 15-Min-Frische-Check |
| MCP-Server down | Exception → HOLD + Audit; nie blind retry-feuern |
Default bei JEDER Unsicherheit: HOLD / no-trade.
7 — Safety / Ethik / Compliance-Hooks
Section titled “7 — Safety / Ethik / Compliance-Hooks”Long-only-Enforcement (harter erster Check, nicht delegierbar); Ethik-Exclusion-Doppel-Check (statisches Set + SIC); Paper-First/Doppel-Gate (ALPACA_PAPER_TRADE=True und LIVE_TRADING_ENABLED=false; Live-account_type bei jedem Aufruf verifiziert; Übergang nur via 3-Schritt-Go/No-Go); HITL mandatory (frischer signierter Token ≤15 Min); Kill-Switch (vor allem geprüft; cancel_all_orders/close_all_positions als Notfall); MAR-Compliance (Bracket-Standard + 1-Handelstag-Re-Entry-Mindestabstand); Audit (jede Aktion inkl. BLOCK, 5-Jahr-Retention); LLM-Unsichtbarkeit roher MCP-Order-Tools.
8 — Eval / KPIs
Section titled “8 — Eval / KPIs”Fill-Rate >85 % (innerhalb 2×FILL_TIMEOUT); Slippage <0,1 % (10 bps) bei Liquid-Caps; 403-Rate = 0 % (Bracket-Standard); Gate-Reject-Rate kategorisiert (Anomalie-Monitoring); Idempotenz-Verletzungen = 0; Stop-Coverage = 100 % (kein nackter Long); Reprice-Erfolgsquote; Paper→Live-Divergenz (mittlere slippage_bps-Differenz).
9 — Offene Fragen / Risiken
Section titled “9 — Offene Fragen / Risiken”Fractional Shares vs. Bracket (Bracket nicht für Fractionals — ganzzahlige Qty erzwungen); Reprice-Aggressivität (1 Schritt genug?); Stop-Market-Gap-Slippage quantifizieren (>2 % → selektive Stop-Limit-Politik mit Rolle 8); IMD-Detailverhalten ab 4. Juni 2026 (in Paper verifizieren vor 6. Juli); MCP-Server als Single Point of Failure (SLA mit Rolle 11); replace_order-Wash-Trade-Edge-Case mit echtem 403-Monitoring in Paper bestätigen. (Quellen: Alpaca MCP, GitHub, User Protection.)
Rolle 8 — Portfolio Monitor & Exit Strategist
Section titled “Rolle 8 — Portfolio Monitor & Exit Strategist”Wichtigste Council-Entscheidungen dieser Rolle:
atr_at_entrywird eingefroren:effective_atr = max(atr_at_entry, atr_recent)für die Distanz, finaler Stop bleibtmax(old_stop, new_stop)— reagiert auf höhere Vola, lockert nie, vermeidet Whipsaw durch künstlich schrumpfende ATR.- Serverseitige GTC-Bracket Pflicht beim Entry + zusätzlicher VM-Chandelier-Cron, der Stop-Legs nur enger ersetzt — bei VM-Ausfall bleibt der initiale Broker-Schutz aktiv.
- Earnings/Wochenende präventiv schließen (Earnings <48 h vollständig/eskaliert; Freitag Reduktion 30–50 % großer Positionen; Earnings übers Wochenende → Full Exit) — Gap-Schutz schlägt Earnings-Optionalität.
- Kein LLM-Veto gegen harte Exits (Stop/Max-Hold/Earnings); ein quick_think-LLM darf nur eine
context_note/review_flagliefern.
1 — Mission & Verantwortung
Section titled “1 — Mission & Verantwortung”Der Portfolio Monitor & Exit Strategist überwacht alle offenen Long-Positionen nach dem Fill bis zur vollständigen Schließung und hält für jede Position einen deterministischen Exit-State. Er berechnet/aktualisiert Stop-, Take-Profit-, Time- und Gap-Risk-Exits — Kernregeln: Chandelier-Exit mit eingefrorenem Entry-ATR, serverseitiger Initial-Stop, Max-Hold 7 Handelstage. Er sendet keine rohen Broker-Orders, sondern strukturierte ExitRequests an Rolle 7 und erzeugt position_health (PositionHealthReport) + vollständige Audit-Ereignisse für Rolle 9.
2 — Inputs / Outputs (mit Schema/Feldern)
Section titled “2 — Inputs / Outputs (mit Schema/Feldern)”Inputs: (A) Fill-/Position-Events von Rolle 7 (event_type, symbol, side, filled_qty, avg_fill_price, filled_at, entry_order_id, stop_order_id, take_profit_order_id, order_class, paper_mode_confirmed); (B) Broker-/Portfolio-State via Rolle-7-MCP-Fassade (positions[], open_orders[]); (C) Market-Data-Features von Rolle 2 (bars, latest_quote, atr_14, vix_level, data_snapshot_hash); (D) Corporate-Action-/Calendar-Inputs (earnings_next_date, earnings_time bmo|amc|unknown, macro_events_next_48h, market_calendar); (E) Policy-Inputs von Rolle 6/9.
Policy-Defaults (E):
{ "max_hold_trading_days": 7, "initial_stop_atr_mult": 2.0, "chandelier_period": 14, "chandelier_mult": 2.5, "min_single_stock_stop_pct": 0.03, "take_profit_pct_default": 0.08, "weekend_reduction_pct": 0.50, "weekend_exposure_cap_pct_nav": 0.03, "earnings_exit_window_hours": 48, "global_kill_switch": false, "paper_mode_required": true, "hitl_required_for_exit": true, "no_reentry_same_symbol_days": 1}Persistenter State pro Position (ExitState): trace_id, symbol, entry_at, entry_trading_date, entry_price, qty_open, atr_at_entry (eingefroren), highest_high_since_entry, initial_stop_price, current_stop_price, take_profit_price, max_hold_exit_date, earnings_exit_deadline, stop_order_id, take_profit_order_id, status: open|exit_pending|closed|needs_reconcile, data_snapshot_hash.
Output A — ExitRequest an Rolle 7:
{ "trace_id": "uuid", "request_type": "CLOSE_POSITION|REDUCE_POSITION|REPLACE_STOP|REPLACE_TAKE_PROFIT|CANCEL_REPLACE_BRACKET", "symbol": "MSFT", "qty": 15.0, "percentage": null, "side_effect": "sell_existing_long_only", "reason_code": "STOP_HIT|CHANDELIER_RATCHET|TAKE_PROFIT|MAX_HOLD|EARNINGS_RISK|WEEKEND_GAP|KILL_SWITCH|RECONCILIATION_MISMATCH", "new_stop_price": 406.30, "urgency": "normal|pre_close|immediate", "requires_hitl": true, "broker_order_ref": "alpaca-stop-leg-id", "valid_until": "ISO-8601", "data_snapshot_hash": "sha256", "deterministic_rule_version": "exit-policy-v1.0"}Output B — AuditEvent an Rolle 9 (action: EXIT_EVALUATED|EXIT_REQUESTED|STOP_RATCHETED|PREVENTIVE_CLOSE_REQUESTED|NO_ACTION, mit reasoning, rule_inputs, data_snapshot_hash, model_version: none|quick_think_model_id).
Output C — position_health (PositionHealthReport) an Rolle 5/6/10: portfolio_exit_health: green|yellow|red, positions_without_server_stop, positions_past_max_hold, positions_with_earnings_risk_48h, avg_distance_to_stop_pct, weekend_exposure_pct_nav, exceptions[].
3 — Methodik & Best Practices
Section titled “3 — Methodik & Best Practices”3.1 Exit-Hierarchie (Priorität): (1) Kill-Switch/Compliance-Block, (2) Position ohne serverseitigen Stop, (3) Earnings-/Event-Gap (Standard 48 h, unbekannte Earnings-Time konservativ), (4) Max-Hold (spätestens 7. Handelstag), (5) Hard/Initial Stop, (6) Chandelier-Ratchet (nur nach oben), (7) Take-Profit/Profit-Protection, (8) Weekend-Gap-Reduction, (9) No-Action (State + Audit aktualisieren).
3.2 ATR-Definition & Entry-Freeze: TR_t = max(high-low, |high-close_{t-1}|, |low-close_{t-1}|); ATR_n = mean(TR); effective_atr = max(atr_at_entry, atr_recent); initial_stop = entry − max(initial_stop_atr_mult × atr_at_entry, min_single_stock_stop_pct × entry) (nie enger als 3 %). Chandelier klassisch 22/3.0, für kurze Swings 10–14 / 2.0–2.5 (CFI Chandelier Exit, Quantified Strategies).
3.3 Chandelier-Exit (Long-only): raw_chandelier_stop = highest_high_since_entry − chandelier_mult × effective_atr; new_stop = max(current_stop_price, raw_chandelier_stop). Stop nur steigend; nie über aktuellen Bid (sonst Close-Request); Ersatz über Rolle 7; nach +2×ATR Gewinn mindestens auf Breakeven+.
3.4 Take-Profit-Logik: Initial-TP als Bracket-Leg (Standard entry × 1.08); Profit-Protection statt mechanischem Nachziehen — bei VIX>25 oder +8–12 % TP enger/Teilgewinn; bei Earnings <48 h überstimmt Gap-Exit.
3.5 Earnings-/Wochenend-Gap-Schutz: Stop-Market schützt bei Overnight-Gaps nur zum Open, nicht zum Stop-Level (Trading Setups Review). Earnings <48 h → präventiver Exit (unbekannt = wie bmo); Freitag 15:30 ET Weekend-Gap-Job (Earnings übers Wochenende → Full Exit; große Positionen über Cap → 30–50 % Reduktion); Makro-Events (FOMC/CPI/NFP) als Portfolio-Risk-Flag an Rolle 6.
3.6 Serverseitige Stops als Basisschutz: Alpaca-GTC bleibt brokerseitig aktiv bei VM-Ausfall; Daily-Reconciliation prüft Ablaufregeln; keine offene Position ohne bestätigte serverseitige Stop-/Bracket-Struktur; VM-Chandelier ist zweite, engere Schutzschicht (Alpaca Orders, User Protection).
4 — LLM-Council-Design der Rolle
Section titled “4 — LLM-Council-Design der Rolle”Deterministisch-first. Chandelier/ATR/Max-Hold/Earnings/Weekend/Reconciliation/Stop-Ratchet laufen in Python ohne LLM. Erlaubte LLM-Nutzung: optional_quick_think_only, nach dem deterministischen Exit-Signal, vor der menschenlesbaren Notification — Output nur human_explanation/risk_note/review_flag; harte Limits: may_veto_stop=false, may_veto_max_hold=false, may_veto_earnings_exit=false, may_lower_stop=false, may_create_order=false. Prompt: „Du erklärst eine bereits deterministisch getroffene Exit-Entscheidung; du darfst die Aktion nicht ändern, keinen Stop lockern, keine Order erfinden.” Keine deep_think-Modelle.
5 — Konkrete Implementierung (Hermes-Primitiv + Pseudocode + Nachbarrollen)
Section titled “5 — Konkrete Implementierung (Hermes-Primitiv + Pseudocode + Nachbarrollen)”| Funktion | Hermes-Primitiv | Bemerkung |
|---|---|---|
| Intraday-Positionsmonitor | Cron | alle 5–15 Min während Marktzeiten |
| Daily Reconciliation | Cron + MCP-Fassade Rolle 7 | Broker-State vs. lokaler Exit-State |
| Friday Gap Check | Cron | Freitag 15:30 ET, Early-Close-kalenderfähig |
| Max-Hold Check | Cron | täglich vor Close + bei Open |
| Exit-State-Store | Tool | SQLite primär + JSONL |
| Broker-Aktion | Subagent/Tool an Rolle 7 | nur strukturierte ExitRequests |
| Optionale Erklärung | Subagent quick_think | keine Entscheidungsrechte |
def on_fill(fill_event, md, policy) -> ExitState: assert fill_event.side == "buy", "Rolle 8 trackt nur Long-Entries" assert fill_event.paper_mode_confirmed is True atr_entry = Decimal(str(md.atr_14)); entry = Decimal(str(fill_event.avg_fill_price)) stop_distance = max(policy.initial_stop_atr_mult * atr_entry, policy.min_single_stock_stop_pct * entry) initial_stop = round_to_tick(entry - stop_distance) take_profit = round_to_tick(entry * (Decimal("1") + Decimal(str(policy.take_profit_pct_default)))) state = ExitState(trace_id=fill_event.trace_id, symbol=fill_event.symbol, entry_at=fill_event.filled_at, entry_trading_date=ny_trading_date(fill_event.filled_at), entry_price=entry, qty_open=Decimal(str(fill_event.filled_qty)), atr_at_entry=atr_entry, highest_high_since_entry=entry, # ATR eingefroren initial_stop_price=initial_stop, current_stop_price=initial_stop, take_profit_price=take_profit, max_hold_exit_date=add_trading_days(ny_trading_date(fill_event.filled_at), policy.max_hold_trading_days), stop_order_id=fill_event.stop_order_id, take_profit_order_id=fill_event.take_profit_order_id, status="open") if not fill_event.stop_order_id: emit_exit_request(type="CLOSE_POSITION", reason="NO_SERVER_SIDE_STOP_AFTER_FILL", urgency="immediate", symbol=fill_event.symbol, qty=fill_event.filled_qty) save_exit_state(state); audit("EXIT_STATE_CREATED", state, md.data_snapshot_hash) return state
def evaluate_position(state, md, calendar, policy) -> ExitDecision: if global_kill_switch_active(): return close_or_hold_protected(state, reason="KILL_SWITCH") if state.status not in {"open", "needs_reconcile"}: return no_action(state, "STATE_NOT_OPEN") if not broker_confirms_position_and_stop(state.symbol, state.qty_open, state.stop_order_id): return reconcile_or_close(state, reason="BROKER_STATE_MISMATCH") current_bid = Decimal(str(md.latest_quote.bid)) state.highest_high_since_entry = max(state.highest_high_since_entry, max(Decimal(str(b.high)) for b in md.bars_since(state.entry_at))) h = hours_until_next_earnings(state.symbol) if h is not None and h <= policy.earnings_exit_window_hours: return close_position(state, reason="EARNINGS_RISK", urgency="pre_close") if h is None and earnings_data_required_today(state.symbol): return close_position(state, reason="EARNINGS_DATA_MISSING_CONSERVATIVE", urgency="pre_close") if trading_days_between(state.entry_trading_date, calendar.today_ny) >= policy.max_hold_trading_days: return close_position(state, reason="MAX_HOLD", urgency="normal") if current_bid <= state.current_stop_price: return close_position(state, reason="LOCAL_STOP_BREACHED_BEFORE_BROKER_FILL", urgency="immediate") effective_atr = max(state.atr_at_entry, Decimal(str(md.atr_14 or state.atr_at_entry))) raw_stop = state.highest_high_since_entry - Decimal(str(policy.chandelier_mult)) * effective_atr ratcheted_stop = round_to_tick(max(state.current_stop_price, raw_stop)) if current_bid >= state.entry_price + Decimal("2.0") * state.atr_at_entry: ratcheted_stop = max(ratcheted_stop, round_to_tick(state.entry_price)) # Breakeven+ if ratcheted_stop > state.current_stop_price: if ratcheted_stop >= current_bid: return close_position(state, reason="CHANDELIER_STOP_ABOVE_MARKET", urgency="immediate") return replace_stop(state, new_stop=ratcheted_stop, reason="CHANDELIER_RATCHET") return no_action(state, "NO_EXIT_RULE_TRIGGERED")
def friday_gap_check(portfolio, policy) -> list[ExitRequest]: assert is_friday_or_pre_holiday_close_window(now_ny()) requests = [] for state in load_open_exit_states(): if has_earnings_before_next_regular_open(state.symbol): requests.append(close_position(state, reason="EARNINGS_OVER_WEEKEND", urgency="pre_close")); continue if portfolio.position_value(state.symbol) / portfolio.nav > Decimal(str(policy.weekend_exposure_cap_pct_nav)): requests.append(reduce_position(state, percentage=policy.weekend_reduction_pct, reason="WEEKEND_GAP_EXPOSURE_REDUCTION", urgency="pre_close")) return requestsDaily Reconciliation gleicht Broker-Positionen/Orders gegen lokale States ab: fehlende Position → closed; abweichende Qty → update_qty_after_partial_exit; fehlender Stop → sofortiger CLOSE_POSITION; Broker-Stop unter Policy-Stop → REPLACE_STOP.
Integration: ← Rolle 6 Sizing/Stop-/Event-Risk-Policy; → Rolle 7 einzige Order-Instanz (nur ExitRequest); → Rolle 9 jedes Evaluate/No-Action/Replace/Close + Re-Entry-Cooldown; → Rolle 10 Exit-Qualität/Whipsaw/Gap-Avoidance; ← Rolle 11 Cron/Healthchecks/Locking/Paper-Mode-Guards.
6 — Failure-Modes & Mitigationen
Section titled “6 — Failure-Modes & Mitigationen”| Failure-Mode | Mitigation | Safe Default |
|---|---|---|
| Position ohne serverseitigen Stop | Bracket-Pflicht; Daily Reconciliation; sofortiger Close-/Stop-Request | Exit an Rolle 7 |
| ATR täglich enger | atr_at_entry einfrieren; effective_atr=max(entry,recent) | Stop nicht lockern |
| Chandelier bewegt Stop nach unten | new_stop=max(old,raw) als Assertion | Reject Update |
| Earnings-Daten fehlen | konservativ bei Kalender-Unsicherheit | Pre-Close Exit |
| Stop-Market bei Gap | präventive Earnings-/Weekend-Regeln | Reduzieren/schließen |
| Broker-Order-ID veraltet | Reconciliation über Symbol/Qty/Side/Type; Idempotency-Key | needs_reconcile, keine Lockerung |
| Partial Fill/Exit | Fill-Events verarbeiten; Broker-State täglich abgleichen | Qty auf Broker-Wahrheit |
| Wash-Trade-Rejection | Bracket/OCO bevorzugen; Rolle 7 prüft offene Orders | Cancel/Replace über Rolle 7 |
| Cron doppelt | Distributed Lock + idempotente trace_id:rule:bar_ts-Keys | zweiter Request no-op |
| VM offline | GTC Initial-Stop brokerseitig; Healthcheck-Alert | Broker-Stop bleibt |
| Kill-Switch aktiv | vor jeder Evaluation/Request prüfen | keine Risikoerhöhung; Exit-Policy |
| LLM halluziniert Exit-Grund | LLM nur Erklärung, keine Aktionsrechte | LLM-Note weglassen |
| Re-Entry direkt nach Exit | Rolle-9-Cooldown 1 Handelstag | Re-Entry blocken |
7 — Safety / Ethik / Compliance-Hooks
Section titled “7 — Safety / Ethik / Compliance-Hooks”Long-only (qty_to_sell <= broker_qty_long als harte Assertion; nie netto short); keine rohen MCP-Tools (alles über Rolle 7); Paper-Mode (paper_mode_confirmed in jedem ExitRequest); HITL (jede nicht rein brokerseitige Exit-Order mit Telegram-Vorlage + Timeout); Mandatory Audit (auch NO_ACTION); keine Stop-Lockerung (außer technisch notwendiger Tick-Rundung, explizit geloggt); Exits auf ausgeschlossene Ticker erlaubt (Risikoabbau), neue Entries bleiben blockiert; Market-Abuse-Schutz (cooldown_until nach Exit); Steuer-Doku (Realized-PnL-Events an Rolle-9-TaxLog); Eigenhandel, keine Anlageberatung.
8 — Eval / KPIs
Section titled “8 — Eval / KPIs”Max-Hold-Compliance 100 % (Verstoß = Sev-1); Server-Side-Stop-Coverage 100 % (Sev-1); Stop-Lockerungs-Verstöße = 0; Chandelier-Capture (Review bei <40 %); Whipsaw-Rate (>30 % → Parameter backtesten); Gap-Avoidance-Rate >95 %; Reconciliation-Lag <15 min intraday/<1 Tag daily; HITL-Timeout-Rate <5 %; Exit-Slippage <0,1 % (Review >0,3 %); Audit-Completeness 100 %. Rolle 10 wertet diese KPIs erst nach ≥4 Wochen Paper über mehrere Regime aus, bevor Parameter geändert werden.
9 — Offene Fragen / Risiken
Section titled “9 — Offene Fragen / Risiken”Earnings-Datenquelle-Zuverlässigkeit (get_corporate_actions); Order-Replacement-Semantik bei Alpaca-Brackets (Paper-Testfälle Pflicht); Stop-Limit vs. Stop-Market; Parameter-Regime (10–14/2.0–2.5 pro Universe/Vola validieren); Wochenend-Reduktion kostet evtl. Montag-Up-Gaps; Makro-Event-Risiko (Long-only/keine Optionen → keine Portfolio-Hedges); VM-/Cron-Zeitzonenrisiko; HITL-Verzögerung bei schnellen Stops (ist auto-approve risk-reducing exit im Paper erlaubt?); steuerliche Detailtiefe (FIFO/FX mit Rolle 9); Re-Entry-Cooldown vs. Signalqualität.
Bottom Line: Rolle 8 ist kein Alpha-Orakel, sondern der Sicherheits- und Gewinnschutz-Regler: deterministisch, idempotent, brokerseitig abgesichert, konservativ bei Events.
Rolle 9 — Compliance & Ethics Officer
Section titled “Rolle 9 — Compliance & Ethics Officer”RECHTLICHER HINWEIS: Alle rechtlichen/steuerlichen Aussagen (FMA, WAG 2018, MAR, EU AI Act, KESt) dienen ausschließlich der allgemeinen Information im Rahmen der Systemarchitektur und stellen KEINE Rechts- oder Steuerberatung dar. Für den Einzelfall ist zwingend ein zugelassener Rechtsanwalt/Steuerberater zu konsultieren.
Wichtigste Council-Entscheidungen dieser Rolle:
- HITL-Friction mit Substanz: separates Telegram-Approval je Trade, 15-Min-Timeout; Reaktionszeit wird geloggt, Approve <5 s erzeugt eine „Rubber-Stamping”-Warnung im Audit.
- LLM-Ethik-Veto entfernt aus dem Execution-Flow: Layer-1/2 (Ticker + SIC) sind deterministisch; der LLM-Fuzzy-Check (Layer 3) lebt asynchron in der Vorselektion (Rolle 1).
- Steuer-Automatisierung: kontinuierlicher
TaxLogger, der jeden Fill sofort mit EUR/USD-Referenzkurs anreichert und E1kv-ready wegschreibt (Alpaca führt keine österreichische KESt ab).
1 — Mission & Verantwortung
Section titled “1 — Mission & Verantwortung”Der Compliance & Ethics Officer ist der normative Wächter des gesamten Stacks. Er garantiert Einklang mit der FMA-Eigenhandelsausnahme, MAR (Marktmanipulation), und den ethischen Exclusion-Kriterien, erzwingt den HITL-Workflow vor jeder Order, führt einen lückenlosen, manipulationssicheren Audit-Trail und automatisiert die Nachweispflichten für das österreichische Steuerreporting (27,5 % KESt).
2 — Inputs / Outputs
Section titled “2 — Inputs / Outputs”Inputs: Signal-Objekte (debate_thesis/reconciled_signal inkl. Reasoning/Council-Vote); Order-Requests von Rolle 6 (sized_order); Alpaca Trade-Fills + Asset-Metadaten (SIC-Codes); Telegram Callback-Queries.
Outputs: HITL-Request (Telegram: Symbol, Action, Entry/Stop/Take-Profit, Reasoning, Trace-ID, Inline-Buttons /approve,/reject); Audit-Record (JSONL/SQLite: trace_id, timestamp, actor, action, symbol, reasoning, data_snapshot_hash, hitl_decision, outcome); Tax-Log-Eintrag (symbol, entry_date, exit_date, gain_loss_eur, kest_at_27_5pct, dividends_eur).
3 — Methodik & Best Practices
Section titled “3 — Methodik & Best Practices”- FMA & WAG 2018: striktes Eigenhandelsprinzip (nur Privatvermögen, keine Konzession); keine externen Abonnenten/Signal-Kopierer.
- MAR: Wash-Trading-Prävention durch zwingende Bracket-Orders (keine gleichzeitigen konträren Orders auf denselben Ticker) + 1-Handelstag-Re-Entry-Cooldown (mit Rolle 8).
- EU AI Act (Art. 50, ab August 2026): Transparenzpflicht — alle Telegram-Benachrichtigungen/Logs tragen „🤖 Trading-Entscheidung durch KI-Agenten generiert”.
- Österr. Steuerrecht: manuelle KESt (27,5 %), keine Spekulationsfrist; Kursgewinne/Dividenden in EUR (Tageskurs) ins E1kv-Format.
4 — LLM-Council-Design der Rolle
Section titled “4 — LLM-Council-Design der Rolle”Vollständig deterministisch (Python, SQLite, Telegram-API). LLMs kommen nicht aktiv zum Einsatz, um regulatorische/ethische Prüfungen (Ticker-Matching, SIC-Ausschluss, HITL-Routing) robust und vorhersehbar zu halten. Die Rolle formatiert lediglich LLM-Outputs früherer Rollen für die HITL-Präsentation.
5 — Konkrete Implementierung
Section titled “5 — Konkrete Implementierung”Hermes-Primitive: mcp_tool (SQLite-Interaktion), tools/registry.py (Telegram-HITL), cron/ (tägliche Tax-Logs + E1kv-Rollups). Integration: Rolle 7 (Execution) ruft das HITL-Gate von Rolle 9 auf, bevor place_stock_order getriggert wird.
class ComplianceOfficer: def __init__(self, db_conn, telegram_bot): self.db = db_conn; self.bot = telegram_bot self.excluded_sic = ["2911", "1311", "3812", "2111"] # Oil, Crude, Defense, Tobacco self.excluded_tickers = {"LMT", "XOM", "MO", "DKNG"} # etc. (gespiegelt aus Rolle 1)
def ethical_gate_check(self, symbol: str, sic_code: str) -> tuple[bool, str]: if symbol in self.excluded_tickers: return False, f"Ethics Violation: {symbol} in Ticker-Blocklist" if sic_code in self.excluded_sic: return False, f"Ethics Violation: SIC {sic_code} blockiert" return True, "OK"
def request_hitl_approval(self, order_proposal: dict) -> bool: start_time = time.time() msg = (f"🤖 TRADING SIGNAL (KI-generiert) - HITL REQUIRED\n" f"Symbol: {order_proposal['symbol']} | Side: BUY\n" f"Reasoning: {order_proposal['reasoning'][:200]}...\n" f"Disclaimer: Keine Rechts-/Anlageberatung.") response = self.bot.send_and_wait(msg, buttons=["Approve", "Reject"], timeout_min=15) if response == "TIMEOUT": self.log_audit(order_proposal['symbol'], "BLOCKED_BY_TIMEOUT"); return False if response == "APPROVE": if time.time() - start_time < 5.0: self.log_audit(order_proposal['symbol'], "WARNING_RUBBER_STAMPING") self.log_audit(order_proposal['symbol'], "HITL_APPROVED"); return True self.log_audit(order_proposal['symbol'], "HITL_REJECTED"); return False
def log_audit(self, symbol, action, details=None): record = {"trace_id": generate_uuid(), "timestamp": datetime.now(timezone.utc).isoformat(), "actor": "HITL" if "HITL" in action else "SYSTEM", "symbol": symbol, "action": action, "details": json.dumps(details or {})} self.db.insert("audit_trail", record); append_to_jsonl("audit_backup.jsonl", record)Konsistenz-Hinweis (vereinheitlicht): Die SIC-Exclusion-Codes wurden über die Rollen vereinheitlicht auf
{2911 Petroleum, 1311 Crude Oil/Gas, 3812 Defense/Search&Navigation, 2111 Tobacco}(identisch mit Rolle 7). Die ursprünglich in Rolle 9 genannte „3760”-Variante (Guided Missiles) wurde durch den präziseren Defense-Code 3812 ersetzt; Guided-Missiles-Hersteller sind ohnehin über die Ticker-Blocklist und SIPRI-Top-100 abgedeckt. Die Ticker-Blocklist ist mit Rolle 1/7 deckungsgleich zu halten (Single-Source:universe_policy.yaml).
6 — Failure-Modes & Mitigationen
Section titled “6 — Failure-Modes & Mitigationen”- Telegram-API down: keine HITL-Requests → System defaultet deterministisch zu hold/no-trade.
- Rubber-Stamping: HITL-Reaktionszeit getrackt; Approve <5 s → Warn-Log → Audit-Trigger.
- Fehlender Währungskurs: ECB-API-Ausfall → Trade-Log
EUR_RATE_MISSING, Cron pflegt am Folgetag nach. - Ethics-Exclusion-Miss: doppeltes Gate (Ticker + SIC) fängt die meisten Lücken.
7 — Safety / Ethik / Compliance-Hooks
Section titled “7 — Safety / Ethik / Compliance-Hooks”- Audit-Trail-Vollständigkeit: jede Iteration, jedes Modell-Votum, jeder Trade unwiderruflich in SQLite + JSONL.
- Disclaimer Injection: jeder Output nach außen (Telegram) mit KI-Hinweis (AI Act) + Anlageberatungs-Ausschluss.
- Wash-Trading Protection (MAR): Bracket-Order-Enforcement über Rolle 7 verunmöglicht simultanes Buy/Sell.
8 — Eval / KPIs
Section titled “8 — Eval / KPIs”HITL-Response-Metriken (Approve/Reject-Anteil; Prüfungszeit Soll >10 s, <15 min); Audit-Abdeckungsquote 100 % (jeder Trade auf HITL-Approve + AI-Votum mit Trace-ID rückführbar); Tax-Reporting-Latenz 100 % der Fills innerhalb 24 h mit EUR-Äquivalent (E1kv-ready).
9 — Offene Fragen / Risiken
Section titled “9 — Offene Fragen / Risiken”Professionalitätsmerkmal (bei hoher Frequenz/Volumen Grenze zum „gewerblichen Handel” — regelmäßige Rechtsprüfung); EU-AI-Act-Klassifizierung (High-Risk-Annex-III-Guidelines erst 2026, bis dahin vorsorgliche Doku); GDPR in LLM-Prompts (keine PII/Kontostände an externe APIs leaken).
Rolle 10 — Quant Validator / Backtest & Eval
Section titled “Rolle 10 — Quant Validator / Backtest & Eval”Wichtigste Council-Entscheidungen dieser Rolle:
- Overfitting-Trias gestaffelt: PBO (via CSCV) + White’s Reality Check sind Pflicht-Gates ab Woche 1 (auf deterministischen Backtests); DSR läuft mit, gilt aber bis MinTRL (~750 Tage) nur informativ.
- Zweigleisige Eval: voller historischer vectorbt-Backtest NUR für die deterministischen Komponenten (Momentum-Baseline D + Regel-Komponenten); für die LLM-Systeme A/B/C zählt als echtes OOS ausschließlich Forward-Paper nach dokumentiertem Modell-Cutoff (historische LLM-Backtests sind Pretraining-kontaminiert).
- Berechnung 100 % deterministisch, kein LLM; ein optionaler read-only 3-Modell-Council interpretiert nur den fertigen Report und kann das Verdikt nur verschärfen, nie lockern.
- Slippage-Sensitivitäts-Sweep {0,05/0,1/0,2/0,5/1,0 %}; Go-Gate verlangt positiven Edge bei konservativen 0,2 %, 1,0 %-Stresszeile ist Pflicht.
1 — Mission & Verantwortung
Section titled “1 — Mission & Verantwortung”Der Quant Validator ist der epistemische Wächter und das Go/No-Go-Tor: Er beantwortet als Einziger rigoros, ob eine Strategie echten, statistisch signifikanten Edge über einer deterministischen Momentum-Baseline besitzt — oder bloß Overfitting ist. Er betreibt den deterministischen vectorbt-Backtest-Harness (Walk-Forward, Multi-Regime, Slippage-Sensitivität), berechnet die Overfitting-Trias (PBO/DSR/White’s RC) und das A/B/C/D-Framework und liefert ein auditiertes, HITL-pflichtiges Verdikt, das niemals automatisch Echtgeld freischaltet.
2 — Inputs / Outputs
Section titled “2 — Inputs / Outputs”Inputs: universe_db.json/allowed_tickers.json (Rolle 1, inkl. delisteter Ticker, survivorship-frei); feature_snapshot (Rolle 2, PiT, Indikatoren mit .shift(1)); paper_trades.jsonl + decisions_audit.jsonl (Rolle 7/9 via Orchestration); model_registry.json (Rolle 11, gepinnte Versionen + Cutoff-Daten); optional param_grid.json.
Outputs: backtest_report_{date}.json; SQLite backtest_results.db (jede Parameterkombo inkl. verworfener — für Trial-Zählung); validation_audit_{date}.jsonl; go_no_go_verdict_{date}.json.
backtest_report (Auszug): data_snapshot_sha256 (Lockbox-Beweis), survivorship_free, walk_forward (n_splits 30, is_days 730, oos_days 180, purge 10, embargo 10), systems (D_momentum mit vollen Stats; A/B/C eval_type: forward_paper_only), regime_breakdown (bull/bear/chop), overfitting_trias (pbo/pbo_pass, dsr/dsr_pass/dsr_note, whites_rc_pvalue/whites_rc_pass, n_trials_logged), slippage_sensitivity (5 Stufen), system_comparison (z_stat/p_value), cost_efficiency (cost_per_signal_usd, alpha_per_dollar).
go_no_go_verdict:
{ "verdict": "NO_GO", // GO | NO_GO | CONDITIONAL_GO "gate_checks": { "min_30_completed_trades": {"value": 14, "required": 30, "pass": false}, "min_3_months_paper": {"value_days": 28, "required_days": 90, "pass": false}, "pbo_below_threshold": {"value": 0.12, "threshold": 0.20, "pass": true}, "whites_rc_significant": {"value": 0.03, "pass": true}, "edge_at_conservative_slippage": {"value": 0.01, "pass": true}, "positive_in_all_regimes_or_neutral_bear": {"pass": true}, "ethics_universe_clean": {"pass": true}, "no_oos_contamination": {"pass": true} }, "blocking_reasons": ["min_30_completed_trades", "min_3_months_paper"], "council_recommendation": "NO_GO — Paper-Sample zu klein; weiterlaufen lassen.", "requires_human_confirmation": true, "auto_live_trigger": false // IMMER false — strukturell unmöglich}3 — Methodik & Best Practices
Section titled “3 — Methodik & Best Practices”3.1 vectorbt Walk-Forward (deterministisch, vektorisiert): 30 rollende Fenster à 2 Jahre IS + 180 Tage OOS, left_to_right=False; Parameter-Optimierung strikt nur auf IS; Portfolio-Sim direction='longonly' (Short strukturell unmöglich), init_cash=10_000 (Walk-Forward).
3.2 Purge + Embargo (López de Prado): je 10 Handelstage Puffer zwischen IS und OOS; für ML-Signale PurgedKFold.
3.3 Multi-Regime (regelbasiert, kein ML): Bull = ADX>25 & close>EMA(200) & DI+>DI−; Bear = ADX>25 & close<EMA(200) & DI−>DI+; Chop = ADX<20. Regime-Labels nur aus Daten bis t (kein ex-post-Wählen). Validierte Fenster: COVID-Crash 2020-03, Liquiditäts-Rallye 2020-04–2021, Rate-Hike-Bär 2022, AI-Boom 2022-11–2024, Yen-Carry-Auflösung 2024-07/08 (StratBase).
3.4 Overfitting-Trias: PBO via CSCV (T×N-Matrix in S=10–16 Chunks, alle C(S,S/2)-Splits → logit → KDE → P(λ<0); Gate <0.20, SSRN 2326253); Deflated Sharpe Ratio (( SR_0 = \sqrt{V[\hat{SR}n]},((1-\gamma)\Phi^{-1}[1-\tfrac1N] + \gamma,\Phi^{-1}[1-\tfrac1{Ne}]) ), ( \text{DSR}=\Phi(\tfrac{\hat{SR}^*-SR_0}{\sigma{SR_0}}) ); Ziel >0.95, erst ab MinTRL, SSRN 2460551); White’s Reality Check (Block-Bootstrap, block_len≈10; Gate p<0.05, Financial Hacker).
3.5 Look-ahead-Vermeidung: Alpaca adjustment='raw', feed='sip'; Indikatoren .shift(1); für A/B/C echtes OOS = nur Forward-Paper nach Cutoff (Glassnode, arXiv LLM Look-ahead).
3.6 Slippage-Sweep (InsightBig: −97 % pro 1 %): Drei-Schichten (Kommission ~0,01 %, Spread 0,03–0,10 %, Market-Impact Square-Root) über {0,05/0,1/0,2/0,5/1,0 %}; Go-Gate bei 0,2 %, 1,0 %-Stresszeile Pflicht.
3.7 A/B/C/D-Framework: A = ai-hedge-fund (breit/billig), B = TradingAgents (tief/teuer), C = A→B kombiniert, D = 12M-1M-Momentum (Fama-French, deterministisch, Ground-Truth, ret_12m − ret_1m, Long Top-Quartil). Vergleich via probabilistischem SR-Diff-Test + Diebold-Mariano (HAC).
3.8 Kurze-Sample-Realismus: Minimum 30 abgeschlossene Trades (CLT), besser 50–100; bei 2–4 Swing-Trades/Woche → 4 Wochen = nur 8–16 Trades = zu wenig → ≥3 Monate Paper vor Go/No-Go, hart.
4 — LLM-Council-Design der Rolle
Section titled “4 — LLM-Council-Design der Rolle”Berechnung = 0 % LLM (Harness + alle Metriken in NumPy/Numba/scipy — Determinismus als Sicherheits-Feature; ein LLM, das Sharpe „schätzt”, ist ein Compliance-Albtraum). Interpretation = optionaler schlanker 3-Modell-Council (read-only): A (Claude), B (GPT), C (Gemini) als deep_think-Subagenten erhalten denselben Report und produzieren je eine qualitative Red-Team-Go/No-Go-Empfehlung („Wo könnte der Report trotz bestandener Gates trügen?”); T=0, gepinnt, strikt grounded auf die Report-JSON. Der Council kann nur verschärfen (ein „NO_GO” eines Modells setzt das Verdikt auf CONDITIONAL + HITL); ≤$5/Session, max. 1 Runde.
5 — Konkrete Implementierung (Hermes-Primitive)
Section titled “5 — Konkrete Implementierung (Hermes-Primitive)”Cron weekly_backtest_job.py (So 18:00 ET via UTC-Cron + flock). Tools (deterministisch): run_walk_forward, compute_pbo, deflated_sharpe, whites_reality_check, run_regime_analysis, compare_systems, build_verdict. Subagent: optionaler Quant-Eval-Council. Output: SQLite + JSONL.
SLIPPAGE_SWEEP = [0.0005, 0.0010, 0.0020, 0.0050, 0.0100]CONSERVATIVE_SLIP = 0.0020; PBO_MAX, RC_ALPHA = 0.20, 0.05MIN_TRADES, MIN_PAPER_DAYS, MINTRL_DAYS = 30, 90, 750
def weekly_backtest_job(): check_kill_switch() # Rolle 11, immer zuerst universe = load_allowed_tickers() # Rolle 1 (survivorship-free!) assert_ethics_clean(universe) # Ethik-Gate VOR Backtest close_raw = load_pit_prices(universe, adjustment='raw', feed='sip') # Rolle 2 data_hash = hashlib.sha256(close_raw.to_json().encode()).hexdigest() split = dict(n=30, window_len=365*2, set_lens=(180,), left_to_right=False) (in_p, in_ix), (out_p, out_ix) = close_raw.vbt.rolling_split(**split) report = {"data_snapshot_sha256": data_hash, "systems": {}, "slippage_sensitivity": {}} for slip in SLIPPAGE_SWEEP: # System D (Momentum), kein LLM-Bias pf_kwargs = dict(direction='longonly', fees=0.0006, slippage=slip, init_cash=10_000) ent, ex = momentum_signal(in_p) # 12M-1M, Top-Quartil, .shift(1) best = optimize_on_IS(in_p, ent, ex, pf_kwargs) # Grid NUR auf IS pf_oos = run_on_OOS(out_p, best, pf_kwargs) # frozen params auf OOS log_all_trials_to_sqlite(best.all_trials) # JEDE Combo (auch verworfene) report["slippage_sensitivity"][str(slip)] = {"sharpe": float(pf_oos.sharpe_ratio().mean()), "edge_vs_D": 0.0} if slip == CONSERVATIVE_SLIP: report["systems"]["D_momentum"] = full_stats(pf_oos) regimes = classify_regime(close_raw) # bull/bear/chop, nur Daten bis t report["regime_breakdown"] = {r: regime_stats(out_p, best, r, regimes) for r in ("bull","bear","chop")} R = build_returns_matrix_from_trials() # (T, N) report["overfitting_trias"] = { "pbo": (pbo := compute_pbo(R, S=12)), "pbo_pass": pbo < PBO_MAX, "whites_rc_pvalue": (p := whites_reality_check(R[:, best.idx], R)), "whites_rc_pass": p < RC_ALPHA, "dsr": (dsr := deflated_sharpe(R[:, best.idx], R, T=len(R))), "dsr_pass": dsr > 0.95 and len(R) >= MINTRL_DAYS, "dsr_note": None if len(R) >= MINTRL_DAYS else "MinTRL nicht erreicht — informativ", "n_trials_logged": R.shape[1]} paper = load_paper_trades_post_cutoff(load_model_cutoffs()) # LLM A/B/C: nur Forward-Paper for sys_id in ("A_ai_hedge_fund", "B_trading_agents", "C_combined"): report["systems"][sys_id] = forward_paper_stats(paper, sys_id) report["systems"][sys_id]["eval_type"] = "forward_paper_only" persist_report(report); audit_log(report, data_hash) verdict = build_verdict(report, paper) verdict = tighten_with_council(verdict, quant_eval_council(report)) # read-only, kann nur verschärfen notify_telegram_hitl(verdict) # NIE auto-live return verdict
def build_verdict(report, paper) -> dict: t = report["overfitting_trias"]; ss = report["slippage_sensitivity"] checks = { "min_30_completed_trades": count_completed_trades(paper) >= MIN_TRADES, "min_3_months_paper": paper_span_days(paper) >= MIN_PAPER_DAYS, "pbo_below_threshold": t["pbo_pass"], "whites_rc_significant": t["whites_rc_pass"], "edge_at_conservative_slippage": ss[str(CONSERVATIVE_SLIP)]["edge_vs_D"] > 0, "positive_in_all_regimes_or_neutral_bear": regimes_ok(report), "ethics_universe_clean": report.get("ethics_clean", True), "no_oos_contamination": report.get("lockbox_intact", True)} return {"verdict": "GO" if all(checks.values()) else "NO_GO", "gate_checks": checks, "blocking_reasons": [k for k,v in checks.items() if not v], "requires_human_confirmation": True, "auto_live_trigger": False} # strukturell immer falseIntegration: konsumiert survivorship-freies Universum (Rolle 1), PiT-Features (Rolle 2), Paper-Trades + Audit (Rolle 7/9), Modell-Pins/Cutoffs (Rolle 11); A/B/C/D-Report fließt als Kalibrierungs-Feedback an Rolle 3/4 (welches System echtes Alpha liefert) und Rolle 5 (Confidence-Kalibrierung); Verdikt an Rolle 9/11 — nur diese, mit menschlicher Bestätigung, legen das Live-Gate um.
6 — Failure-Modes & Mitigationen
Section titled “6 — Failure-Modes & Mitigationen”| Failure-Mode | Mitigation |
|---|---|
| Slippage=0/zu optimistisch | Pflicht-Slippage-Sweep; Gate bei 0,2 %; 1,0 %-Stresszeile |
| OOS fürs Debugging „angeschaut” | Data-Lockbox: OOS nie vor finalem Eval geladen; Daten-Hash; getrennte IS/OOS-Funktionen |
| Nicht alle Trials gezählt | jede Combo (auch verworfene) in SQLite; N aus DB-Count |
| LLM-Look-ahead | historische LLM-Backtests nie als OOS; nur Forward-Paper post-cutoff; Cutoff dokumentiert |
| Survivorship-Bias | Universum inkl. delisteter Ticker; survivorship_free-Flag |
| Regime ex-post „gewählt” | Regime-Labels nur aus Daten bis t |
| DSR auf zu kurzem Sample als Gate | DSR nur informativ bis MinTRL; harte Gates 30-Trades + 3-Monate + PBO + RC |
| Council halluziniert Zahlen | read-only, T=0, kann nur verschärfen |
| Daten-Lücke/NaN | data_quality_flags; bei >X % fehlend → NO_GO-Default |
| Cron-Doppellauf | flock (Rolle 11) |
Default bei jedem unerwarteten Zustand: NO_GO. Ein Fehler im Validator darf nie zu einem versehentlichen GO führen.
7 — Safety / Ethik / Compliance-Hooks
Section titled “7 — Safety / Ethik / Compliance-Hooks”Long-only im Harness (direction='longonly'); Ethik-Gate VOR Backtest (assert_ethics_clean(universe)); Paper-first, kein Auto-Live (auto_live_trigger strukturell false; Go-Live = ≥30 Trades + ≥3 Monate + HITL); lückenloser Audit (Daten-Snapshot-Hash, Modell-Pins, alle Trial-Counts); Reproduzierbarkeit (gepinnte Daten/Modelle/Seeds); Eigenhandel-Backtest, keine Performance-Versprechen.
8 — Eval / KPIs
Section titled “8 — Eval / KPIs”Reproduzierbarkeit 100 % bit-identisch; Trial-Vollständigkeit 100 %; Slippage-Sweep-Coverage 5/5; OOS-Lockbox-Integrität 0 Verletzungen; False-GO-Rate 0; PBO der freigegebenen Strategie <0.20; White’s-RC p<0.05; Edge bei 0,2 % >0 vs. D; Eval-Laufzeit <30 min; Council-Kosten <$5/Session.
9 — Offene Fragen / Risiken
Section titled “9 — Offene Fragen / Risiken”MinTRL-Lücke (DSR braucht ~750 Tage — reicht 30-Trades + Block-Bootstrap + PBO/RC, oder bewusst „unter-powertes” erstes Go-Live mit kleinerem Kapital?); LLM-OOS-Knappheit (Forward-Paper dauert Monate); Bear-Regime-Stichprobe dünn („neutral im Bär” statt „positiv”?); survivorship-freie Daten (Alpaca vs. CRSP/Compustat-FOSS-Spannung); Council-Mehrwert ($5/Session per A/B-Test prüfen); Param-Grid-Größe vs. Overfitting-Strafmaß.
Rolle 11 — Orchestration & Reliability Engineer (Hermes/DevOps)
Section titled “Rolle 11 — Orchestration & Reliability Engineer (Hermes/DevOps)”Wichtigste Council-Entscheidungen dieser Rolle:
- Cron-TZ: UTC-only — Server + Cron in UTC,
America/New_York/NYSE-Kalender nur in App-Logik; keine kritischen Jobs 01:00–03:00 ET (DST-Doppellauf/Skip-Fenster).- Isolation: gehärtetes Docker Compose jetzt (
cap_drop: ALL,no-new-privileges, Seccomp, AppArmor, Non-root, read-only RootFS, kein Docker-Socket), gVisor Stufe 2, Kata Stufe 3.- Budget-Policy: LiteLLM-Proxy mit 70/90/100/150-%-Leiter — Kostenlimit stoppt LLMs, aber deterministische Checks/Monitoring/Exits/HOLD laufen weiter.
- Graceful Failure: jede Exception/Timeout/invalides JSON/stale Data/Budget-Stop/Kill-Switch/Markt-geschlossen ergibt
HOLD, nie Retry bis zur Order; nurplace_orderlöst Orders aus, und nur nach Gates + HITL.
1 — Mission & Verantwortung
Section titled “1 — Mission & Verantwortung”Der Orchestration & Reliability Engineer ist das deterministische Nervensystem der Hermes-Trading-Agency: er plant Jobs, isoliert Runtime-Umgebungen, schützt Secrets, misst Kosten, erzeugt Observability und erzwingt sichere Defaults. Leitregel: jeder unerwartete Zustand → HOLD/no_trade. Die Rolle betreibt keine Investment-These; sie stellt sicher, dass die Rollen 1–10 nur innerhalb harter Betriebs-, Compliance-, Kosten- und Sicherheitsgrenzen handeln können (Cron/TZ/DST, flock-Dedup, Docker-Härtung, file-basierter Kill-Switch, LiteLLM-Budget-Caps, strukturierte Logs, Healthchecks, Credential-Proxy, gepinnte Modell-/Image-Versionen).
2 — Inputs / Outputs
Section titled “2 — Inputs / Outputs”Inputs: run_request (job_name, scheduled_at_utc, trigger, session_id, requested_by_role, paper_mode_required); runtime_config (env: paper|live_disabled|live_candidate, timezone_server: UTC, market_timezone: America/New_York, alpaca_paper_trade, live_trading_enabled, kill_switch_path, max_llm_daily_budget_usd, max_llm_session_budget_usd, model_registry_version, docker_image_digest); pre_trade_context (ticker, candidate_source, data_snapshot_id, universe_version, risk_ticket_id, hitl_required).
Outputs: orchestration_decision (decision: RUN|SKIP|HOLD|KILL_SWITCH_ACTIVE|BUDGET_BLOCKED|MARKET_CLOSED|FAILED_SAFE, safe_to_continue, reason_code, ts_utc/ts_et); audit_envelope (trace_id, prompt_hash, model_pin, code_git_sha, docker_image_digest, input_snapshot_hash, output_hash); cost_event (agent_id, model, Tokens, cost_usd, daily_spend_usd, budget_state: OK|WARN_70|QUICK_ONLY_90|BLOCKED_100|KILL_150); health_event.
Persistente Artefakte: /app/logs/audit.jsonl (append-only), /app/data/orchestration.db (runs/locks/llm_calls/budget_state/health_events/incidents/model_registry), /app/workspace/heartbeat.txt, /opt/trading/KILL_SWITCH_ACTIVE, /app/reports/eod_reliability_{date}.json.
3 — Methodik & Best Practices
Section titled “3 — Methodik & Best Practices”3.1 Cron/Zeitzonen/DST: Host + Cron in UTC; America/New_York nur in App-Logik; keine kritischen Jobs 01:00–03:00 ET; NYSE-Feiertage/Early-Closes via exchange_calendars (CronMonitor, Stack Overflow).
# /etc/crontab — Server-Zeitzone UTC, alle Jobs via wrapper + flock*/30 13-21 * * 1-5 trading /opt/trading/cron_wrapper.sh market_screener python /opt/trading/jobs/market_screener.py0 22 * * 1-5 trading /opt/trading/cron_wrapper.sh eod_report python /opt/trading/jobs/end_of_day_report.py0 23 * * 0 trading /opt/trading/cron_wrapper.sh weekly_backtest python /opt/trading/jobs/weekly_backtest.py*/5 * * * * trading /opt/trading/cron_wrapper.sh heartbeat python /opt/trading/jobs/healthcheck_heartbeat.py3.2 flock gegen Doppelläufe: jeder Cron-Entry über Wrapper mit nicht-blockierendem Lock; existierender Lock = SKIP/lock_exists (kein Fehler).
#!/usr/bin/env bashset -euo pipefailJOB_NAME="$1"; shiftLOCK_FILE="/var/lock/trading_${JOB_NAME}.lock"exec 200>"$LOCK_FILE"flock -n 200 || { printf '{"event":"lock_exists","job":"%s","action":"skip"}\n' "$JOB_NAME"; exit 0; }trap 'flock -u 200' EXITexec "$@"3.3 Docker-Härtung (Baseline sofort; gVisor Stufe 2, Kata Stufe 3, SandboxEscapeBench, SoftwareSeni):
services: hermes-agent: image: hermes-trading@sha256:PINNED_DIGEST user: "1001:1001" read_only: true tmpfs: ["/tmp:size=100M,mode=1777", "/var/run:size=10M"] volumes: ["./data:/app/data:rw", "./workspace:/app/workspace:rw", "./logs:/app/logs:rw", "./config:/app/config:ro"] security_opt: ["no-new-privileges:true", "seccomp:./seccomp-trading.json", "apparmor:trading-agent"] cap_drop: ["ALL"] pids_limit: 100 mem_limit: 2g cpus: "2.0" networks: ["trading-internal"] environment: ["LIVE_TRADING_ENABLED=false", "ALPACA_PAPER_TRADE=true", "PYTHONDONTWRITEBYTECODE=1"] healthcheck: {test: ["CMD","python","/app/healthcheck.py"], interval: 30s, timeout: 10s, retries: 3, start_period: 15s}networks: trading-internal: {driver: bridge, internal: true}Verboten: --privileged, CAP_SYS_ADMIN, CAP_SYS_MODULE, CAP_NET_RAW, CAP_DAC_READ_SEARCH, Host-PID/IPC, bind mounts auf /, /var/run/docker.sock.
3.4 File-basierter Kill-Switch (absichtlich primitiv — auch bei DB-/Netzwerkausfall lesbar):
| Level | Wirkung | Auslöser |
|---|---|---|
| L1 Soft Stop | keine neuen Orders, Positionen bleiben | 90 % LLM-Tagesbudget, Datenqualität degradiert |
| L2 Hard Stop | offene Orders canceln, keine neuen Analysen | Broker-Fehler, Risk-Gate-Verletzung |
| L3 Emergency | Positionsabbau nur nach separatem HITL/Execution-Protokoll | Daily Drawdown >5 %, Broker-Desync |
| L4 Global Kill | Datei KILL_SWITCH_ACTIVE, alle Jobs HOLD | Secret-Leak, Budget-Monatslimit, Kompromittierungsverdacht |
3.5 Kostenkontrolle (LiteLLM) (LiteLLM Budgets): kein direkter Provider-Key in Subagents; kein LLM-Call ohne agent_id/session_id/purpose/model_pin/trace_id. Leiter: 70 % → Warnung; 90 % → nur quick_think; 100 % → keine neuen LLM-Calls (deterministisches HOLD/Monitoring/Exit läuft weiter); 150 %/unerklärt → Global Kill + Incident.
3.6 Observability: strukturierte JSON-Events (mind. ts_utc, level, event, job_name, run_id, session_id, role_id, trace_id, decision, reason_code, paper_mode, model_pin, cost_usd, sanitized Payload); OpenTelemetry-Spans + optional LangSmith (sanitized, kostenkontrolliert).
3.7 Secret-Hygiene/Credential-Proxy: Agent kennt keine API-Keys; Broker-/LLM-/Messaging-Credentials in Docker Secrets/Proxy; Agenten senden nur signierte Request-Intentionen (Aembit, Render). Log-Sanitizing mandatory:
SENSITIVE_KEYS = {"api_key", "secret", "password", "token", "credential", "bearer", "authorization"}def sanitize(obj): if isinstance(obj, dict): return {k: ("***REDACTED***" if k.lower() in SENSITIVE_KEYS else sanitize(v)) for k, v in obj.items()} if isinstance(obj, list): return [sanitize(x) for x in obj] return obj3.8 Reproduzierbarkeit/Pins: jede Entscheidung protokolliert model_pin, prompt_hash, input_snapshot_hash, code_git_sha, docker_image_digest, requirements_lock_hash, config_version; Modell-Updates nur über expliziten A/B-Test gegen die Vorversion.
4 — LLM-Council-Design der Rolle
Section titled “4 — LLM-Council-Design der Rolle”Keine LLMs im Hot Path (Cron-Gating, Kill-Switch, Budget-Gates, Secret-Sanitizing, Paper/Live-Gates, Locking, Healthchecks, Staleness, place_order-Vorbedingungen sind deterministisch). LLM nur für nicht-handelsauslösende Analysen: tägliche Reliability-Zusammenfassung, Incident-Postmortem, Runbook-Verbesserungen, Anomalie-Erklärung nach deterministischem Alarm. Council: Ops-Reviewer (quick_think), Security-Reviewer (deep_think, nur sanitized Logs), Cost-Reviewer (quick_think) — alle ohne Order-/Secret-/Config-Rechte. Bei kritischer Anomalie → INCIDENT_REVIEW_REQUIRED + betroffene Jobs HOLD.
5 — Konkrete Implementierung
Section titled “5 — Konkrete Implementierung”Tools: check_kill_switch, acquire_job_lock, check_market_window, enforce_paper_and_live_flags, validate_runtime_config, log_llm_cost, check_llm_budget, sanitize_log_event, emit_audit_event, activate_kill_switch, safe_decision-Decorator. MCP: Alpaca nur über place_order-Gate (rohe Order-Tools internal_only). Watchdog: systemd + Heartbeat-Checker + Healthchecks.io/Telegram-Alert.
KILL_SWITCH_PATH = Path("/opt/trading/KILL_SWITCH_ACTIVE")ET = ZoneInfo("America/New_York")
def orchestrate_job(job_name, fn, *, requires_market_open, allows_llm): run_id = str(uuid.uuid7()) if hasattr(uuid, "uuid7") else str(uuid.uuid4()) base = {"run_id": run_id, "job_name": job_name, "ts_utc": datetime.now(timezone.utc).isoformat()} try: emit_audit_event({**base, "event": "job_start"}) gate = preflight_gate(job_name, run_id, requires_market_open, allows_llm) emit_audit_event({**base, "event": "preflight", **gate.__dict__}) if not gate.safe_to_continue: return hold_result(gate.reason_code, run_id) result = fn(run_id=run_id) emit_audit_event({**base, "event": "job_success", "output_hash": hash_payload(result)}) return result except Exception as exc: emit_audit_event({**base, "event": "job_exception", "decision": "FAILED_SAFE", "reason_code": type(exc).__name__, "traceback_hash": hash_payload(traceback.format_exc())}) return hold_result(f"exception:{type(exc).__name__}", run_id)
def preflight_gate(job_name, run_id, requires_market_open, allows_llm) -> GateDecision: if KILL_SWITCH_PATH.exists(): return GateDecision("KILL_SWITCH_ACTIVE", False, "kill_switch_file_exists", run_id) if not acquire_job_lock(job_name): return GateDecision("SKIP", False, "lock_exists", run_id) cfg = load_runtime_config() if cfg["ALPACA_PAPER_TRADE"] is not True: activate_kill_switch("paper_flag_missing_or_false", level="L4") return GateDecision("FAILED_SAFE", False, "paper_flag_invalid", run_id) if cfg.get("LIVE_TRADING_ENABLED") is not False: activate_kill_switch("live_trading_flag_unexpected", level="L4") return GateDecision("FAILED_SAFE", False, "live_flag_invalid", run_id) if requires_market_open and not is_market_open_et(): return GateDecision("HOLD", False, "market_closed", run_id) if allows_llm: budget = check_llm_budget(agent_id=job_name, session_id=run_id) if budget.state in {"BLOCKED_100", "KILL_150"}: if budget.state == "KILL_150": activate_kill_switch("llm_monthly_budget_exceeded", level="L4") return GateDecision("HOLD", False, "llm_budget_blocked", run_id) return GateDecision("RUN", True, "ok", run_id)
def is_market_open_et(now_utc=None) -> bool: now_et = (now_utc or datetime.now(timezone.utc)).astimezone(ET) if 1 <= now_et.hour < 3: return False # DST-Problemfenster if now_et.weekday() >= 5: return False import exchange_calendars as xcals if not xcals.get_calendar("XNYS").is_session(now_et.date()): return False return now_et.replace(hour=9, minute=30) <= now_et < now_et.replace(hour=16, minute=0)Integration: Rolle 1 liefert allowed_tickers/Exclusion-Version (Hash in jedem Order-Audit); Rolle 2 Daten-Snapshots (Job blockiert bei stale/fehlendem Hash); Rollen 3–5 rufen LLMs nur über das Kosten-/Tracing-Gate; Rolle 6 Exposure-/Drawdown-Gates (Soft/Hard Stop); Rolle 7 Orders nur über place_order mit vorangestellten Rolle-11-Gates; Rolle 8 meldet Positionsanomalien an den Watchdog; Rolle 9 erhält volle Audit-/HITL-/Flag-/Secret-Scanner-Berichte; Rolle 10 erhält reproduzierbare Run-Metadaten + Modell-Pins + Cost-per-Signal.
6 — Failure-Modes & Mitigationen
Section titled “6 — Failure-Modes & Mitigationen”| Failure-Mode | Mitigation | Default |
|---|---|---|
| Cron-Doppellauf | flock lock_exists, nicht blockierend skippen | SKIP |
| DST-Sprung | UTC→ET-App-Check, keine kritischen Jobs 01–03 ET, NYSE-Kalender | HOLD |
| Marktfeiertag/Early Close | exchange_calendars | HOLD |
| Kill-Switch-Datei vorhanden | File-Check als erster Schritt | KILL_SWITCH_ACTIVE |
| Docker-Escape-Versuch | Cap-drop, no-new-privileges, non-root, read-only, kein Socket | KILL_SWITCH bei Verdacht |
| Secret im Log | Sanitizer + Pattern-Scanner, Redaction, Rotation | KILL_SWITCH bei echtem Leak |
| LLM-Budget überschritten | 70/90/100/150-Leiter | HOLD für LLM |
| LLM-Timeout | 30 s Timeout, max 3 Retries mit Backoff | HOLD |
| Invalides JSON | Schema-Validation, verwerfen | HOLD |
| Stale Market Data | Timestamp >5 Min | HOLD |
| Modell-Default geändert | Pin fehlt/abweicht, blockieren bis Registry-Fix | HOLD |
| Healthcheck aus | heartbeat >5 Min, systemd restart + Alert | DEGRADED/HOLD |
| DB nicht schreibbar | Write-Test beim Start | HOLD |
| Live-Flag versehentlich true | Config-Gate, Operator-Review | KILL_SWITCH |
| Rohe MCP-Order-Tools sichtbar | Tool-registry-Audit, CI-Test | KILL_SWITCH |
7 — Safety / Ethik / Compliance-Hooks
Section titled “7 — Safety / Ethik / Compliance-Hooks”Paper-first-Gate (ALPACA_PAPER_TRADE=True & LIVE_TRADING_ENABLED=false, sonst Kill-Switch); Long-only-/No-Leverage-Hook (nur deterministisches place_order sichtbar); HITL-Hook (Approval-Receipt mit Hash im Audit, sonst HOLD); Exclusion-Hook (Universe-/Ethik-Versions-Hash im Order-Audit); Secret-Hook (Sanitizer vor jedem Log-Write); Compliance-Hook (append-only JSONL + SQLite); Graceful-Failure-Hook (HOLD bei jeder Unsicherheit); Reproduzierbarkeits-Hook; Incident-Hook (INCIDENT_CRITICAL + Global Kill bei Secret-Leak/Live-Flag/Escape/unerklärten Kosten/Audit-Write-Ausfall).
8 — Eval / KPIs (Auszug)
Section titled “8 — Eval / KPIs (Auszug)”Cron-Run-Erfolgsrate ≥99 % (≥99,5 % vor Live); Doppel-Execution = 0; DST-Test-Abdeckung 100 %; Jobs ohne Audit-Event = 0; Secret-Leakage = 0; LLM-Budget-Überschreitungen = 0; Healthcheck-Alert-Latenz <5 min; MTTR <30 min; ungated LLM-Calls/Orderversuche = 0; Docker-Hardening-Compliance 100 %; HOLD-bei-Fehler-Quote 100 %.
Pflicht-Fault-Injection-Tests: Kill-Switch-Datei → jeder Job HOLD; Lock existiert → zweiter Job SKIP; 2026-03-08 02:30 ET / 2026-11-01 01:30 ET → kritischer Job nicht RUN; LIVE_TRADING_ENABLED=true / ALPACA_PAPER_TRADE=false → Kill-Switch; LLM-Budget 100 % → neue LLM-Calls blockiert, Monitoring läuft; invalides JSON → HOLD; Audit-DB read-only → HOLD; Secret-String im Log → REDACTED; Compose mit privileged:true → CI fail; Modell ohne datierten Pin → CI fail/HOLD.
9 — Offene Fragen / Risiken
Section titled “9 — Offene Fragen / Risiken”Healthchecks.io vs. self-hosted (Datenschutz/Abhängigkeit); LangSmith-Datenabfluss (sanitized + kostenkontrolliert, oder lokaler OTel-Collector); Credential-Proxy-Bauaufwand; gVisor/Kata-Kompatibilität (erst nach Paper-Baseline); NYSE-Early-Close-Handling; UUIDv7-Verfügbarkeit (Fallback); Budget vs. Exit-Sicherheit (Exit-/Risk-/Monitor-Jobs müssen bei Budgetblock weiterlaufen — in CI testen); Manual-Kill-Switch-Governance (Vier-Augen-Prinzip mit Rolle 9); Live-Übergang-Checkliste (≥3 Monate Paper, 0 Secret-Leaks, 0 ungated Orders, 0 Budgetverletzungen, bestandene Fault-Injection-Tests); provider-seitige Modell-Pins (ohne harten Pin → für entscheidungsrelevante Rollen sperren).
Teil C — Rollen-Zusammenspiel & Daten-Contracts
Section titled “Teil C — Rollen-Zusammenspiel & Daten-Contracts”Die 11 Rollen sind durch eine durchgehende Artefakt-Kette verbunden. Jedes Artefakt ist der einzige zulässige Input der nächsten Rolle; Parallel-Quellen für dieselben Felder sind verboten (Single-Source-of-Truth). Dieser Teil dokumentiert die Pipeline, vereinheitlicht die Schema-Namen und benennt die verbleibenden bewussten Abweichungen.
C.1 — Durchgehende Daten-Pipeline
Section titled “C.1 — Durchgehende Daten-Pipeline”flowchart LR A["universe_db.json\n(≙ allowed_tickers.json)\n[Rolle 1]"] --> B["feature_snapshot\n(feature_snapshot.v1)\n[Rolle 2]"] B --> C["screen_result\n(Shortlist)\n[Rolle 3]"] C --> D["debate_thesis\n(DebateResult)\n[Rolle 4]"] B -. Snapshot .-> D D --> E["reconciled_signal\n(CIODecision)\n[Rolle 5]"] E --> F["sized_order\n(Order)\n[Rolle 6]"] F --> G["ApprovedOrderRequest\n(+HITL-Token)\n[Rolle 5/6→7]"] G --> H["ExecutionResult\n[Rolle 7]"] H --> I["position_health\n(PositionHealthReport)\n+ ExitState\n[Rolle 8]"] I -. ExitRequest .-> H| Stufe | Kanonisches Artefakt | Erzeuger → Konsument | Schlüsselfelder (Auswahl) | Idempotenz-/Audit-Schlüssel |
|---|---|---|---|---|
| 1 | universe_db.json (≙ allowed_tickers.json) | R1 → R2, R3, R7-Gate, R10 | tickers{ethics, liquidity, theme, status}, policy_hash, version | policy_hash, version |
| 2 | feature_snapshot (feature_snapshot.v1) | R2 → R3, R4, R6, R8, R10 | tradability_status, technical_features, risk_handoff{atr_14,…}, source_manifest, as_of | input_hash/output_hash, as_of |
| 3 | screen_result (Shortlist) | R3 → R4 | persona_votes, consensus_buy_pct, controversy_score, recommendation | ticker+date |
| 4 | debate_thesis (DebateResult) | R4 → R5 | bull/bear/risk_thesis, final_signal, debate_divergence_score, confidence_raw (UNKALIBRIERT) | audit_id |
| 5 | reconciled_signal (CIODecision) | R5 → R6, R9, R10 | action, agreement, calibrated_confidence, safety_gates, hitl_required | decision_id, decision_hash |
| 6 | sized_order (Order) | R6 → R7 | shares, stop_loss_price, pct_of_portfolio, sizing_method, rejection_reason | (über trace_id) |
| 7 | ApprovedOrderRequest | R5/6 (nach HITL) → R7 | side="buy", qty, limit_price, take_profit_price, stop_loss_price, hitl_token, data_snapshot_hash | trace_id, client_order_id |
| 8 | ExecutionResult | R7 → R8, R9, R10 | status, filled_qty, avg_fill_price, bracket_order_id, slippage_bps | trace_id, client_order_id |
| 9 | ExitRequest / position_health | R8 → R7 (Exit) / R5,R6,R10 | request_type, reason_code, new_stop_price; portfolio_exit_health, exceptions[] | trace_id, deterministic_rule_version |
Der trace_id (UUID) ist der durchgängige Korrelationsschlüssel von der CIO-Entscheidung bis zum Exit; der data_snapshot_hash verkettet jede Entscheidung mit dem exakten feature_snapshot, auf dem sie beruht (Look-ahead-/Leakage-Beweis für Rolle 10).
C.2 — Schema-Vereinheitlichungen (durchgeführt)
Section titled “C.2 — Schema-Vereinheitlichungen (durchgeführt)”Folgende Namens-Abweichungen zwischen den ursprünglichen Rollen-Spezifikationen wurden im Playbook vereinheitlicht:
| Vereinheitlicht auf | Ursprüngliche Varianten | Quelle der Abweichung | Entscheidung |
|---|---|---|---|
universe_db.json | universe_db.json (R1) ↔ allowed_tickers.json (R3, R10) | R1 schreibt versioniert, R3/R10 lesen | Identisches Artefakt; allowed_tickers.json ist die von R2 weitergereichte Lese-Sicht. Beide Namen als Synonyme markiert. |
feature_snapshot | feature_snapshot (R2/R3/R4) ↔ feature_snapshot_{ticker}_{date}.json (R10) | Live-Objekt vs. archivierter Dateiname | Gleiches Schema feature_snapshot.v1; der Dateiname ist die archivierte Variante für Backtests. |
screen_result | screener_results_{date}.jsonl (R3) ↔ „Shortlist” (R4) | Dateiname vs. logischer Begriff | Kanonisch screen_result; die Shortlist ist die Teilmenge mit recommendation ∈ {BUY_CANDIDATE, DEEP_ANALYZE}. |
debate_thesis / DebateResult | DebateResult (R4-Code) ↔ debate_results[] (R5-Input) | Klassen- vs. Listenname | Ein Objekt = ein debate_thesis; R5 erhält genau drei davon (eines je Modellfamilie). |
reconciled_signal / CIODecision | CIODecision (R5) ↔ cio_decision (R6-Input) | Klassen- vs. Feldname | Identisch; R6 konsumiert action + Confidence/Flags. |
sized_order / Order | Order (R6) — nachgelagert in ApprovedOrderRequest überführt | R6 erzeugt Order, R7 erwartet ApprovedOrderRequest | Order (Sizing-Ergebnis) wird nach HITL um hitl_token/limit_price/take_profit_price/Hashes zum ApprovedOrderRequest angereichert. |
position_health / PositionHealthReport | beide in R8 | Synonym | Kanonisch position_health. |
| SIC-Exclusion-Codes | R7 {2911,1311,3812,2111} ↔ R9 {3760,2911,2111} | R9 nannte „3760” (Guided Missiles) | Vereinheitlicht auf {2911,1311,3812,2111}; „3760” durch präziseren Defense-Code 3812 ersetzt (Guided-Missiles-Hersteller über Ticker-Blocklist + SIPRI abgedeckt). |
| Ticker-Exclusion-Liste | R1, R7, R9 leicht unterschiedliche Mengen (R7 enthält zusätzlich PLTR/LHX/TDG/MPC/PENN/USO) | R1 behandelt PLTR conditional, R7 hart | Single-Source ist universe_policy.yaml (R1); R7 hält bewusst eine defensive Obermenge als zweite Verteidigungslinie. PLTR ist im Default konservativ ausgeschlossen (siehe R1, offene Frage). |
C.3 — Bewusst unterschiedliche Schwellen über Layer (keine Inkonsistenz)
Section titled “C.3 — Bewusst unterschiedliche Schwellen über Layer (keine Inkonsistenz)”Manche Zahlen wirken widersprüchlich, sind aber bewusst layer-spezifisch:
| Größe | Rolle 1 (Universum) | Rolle 2 (Daten-Gate) | Rolle 7 (Order-Gate) | Begründung |
|---|---|---|---|---|
| Spread-Limit | ≤0,5 % bei Aufnahme (≤0,3 % normal) | ≤0,5 % Quality-Gate | <0,1 % Hard-Gate am Order-Punkt | Aufnahme darf großzügiger sein; der teure Moment ist die Ausführung — dort am strengsten. >1,0 % = Notfall (warte/limit). |
| Positionsgröße | — | — | Notbremse HARD_MAX_NOTIONAL = $25.000 | R6 ist Single-Source des Sizings (Caps 10 %/30 %/80 %); R5 eskaliert HITL ab geschätzten 8 %; R7 hat nur eine grobe absolute Notbremse. Die 8 % (R5) < 10 % (R6 Hard-Cap) < 12 % (R6 assert) bilden eine gestaffelte Eskalation. |
| Dual-Use-Revenue | >5 % = EXCLUDE | trägt Ethik-Metadaten weiter | re-checkt via Frozenset + SIC | Ein Wert, an drei Stellen erzwungen (Defense-in-Depth). |
| HITL-Token-Alter | — | — | ≤15 Min (R7), 15-Min-Timeout (R9) | Konsistent: R9 stellt den Token aus (15-Min-Fenster), R7 verifiziert seine Frische (≤15 Min). |
C.4 — Determinismus-Grenze („Sicherheit ist Code”)
Section titled “C.4 — Determinismus-Grenze („Sicherheit ist Code”)”Die zentrale Architektur-Linie verläuft an der place_order-Grenze. Links davon dürfen LLMs denken/vorschlagen (R3 Screening, R4 Debatte, optionale Judges in R5/R10, Sentiment in R2). Rechts davon ist alles deterministischer Code: R6 Sizing, R7 Execution-Gate, R8 Exit-Logik, R9 Compliance-Gate, R11 Orchestration-Gates und die gesamte R10-Berechnung. Die finance-skills (Teil D) leben strikt links dieser Grenze und berühren place_order nie.
Teil D — finance-skills-Integration
Section titled “Teil D — finance-skills-Integration”Quelle: himself65/finance-skills (2.589★, MIT, aktiv, v8.0.1, 24 Skills in 6 Plugin-Gruppen, Agent-Skills-Standard agentskills.io). Council-Empfehlung erstellt via Ultrathink-LLM-Council (Opus = Architektur, GPT-5.5 = Quant-Nutzen, Gemini 3.1 Pro = Risk/Ethik/Compliance), einstimmig.
D.1 — Votum: SELEKTIV AUFNEHMEN (einstimmig 3/3)
Section titled “D.1 — Votum: SELEKTIV AUFNEHMEN (einstimmig 3/3)”Ja, aber nur den Methodik-Inhalt ausgewählter Skills als Research-Scaffolding — niemals die mitgelieferte Auto-Trigger-/Live-Daten-Mechanik. Der entscheidende Architektur-Befund: Der Hermes-Stack hat bereits ein natives Skill-Primitiv (attach_skills auf Cron-Jobs, vgl. der geplante trading_runbook). finance-skills ist gattungsgleicher, portierbarer Markdown-Prompt-Content. Daraus folgt das Leitprinzip:
finance-skills dürfen alles vorschlagen/erklären/strukturieren, aber nichts ausführen. Sie leben strikt links der
place_order-Grenze und holen niemals selbst Live-Daten — das bleibt Monopol des Data-Layers (Rolle 2).
Die native Installation (npx skills add mit aktiven Triggern) wird abgelehnt: die SKILL.md-Trigger sind aggressiv („always use even if only a ticker”; sepa triggert auf „should I buy this stock”). In einem autonomen, cron-getriebenen Agenten würde das die feste Lifecycle-Kaskade brechen, den Orchestrator-Context vergiften, Token-Budget/Audit sprengen und die Point-in-time-Pipeline umgehen.
D.2 — Was wir übernehmen (gestrippt, als attach-Skill im Research-Layer)
Section titled “D.2 — Was wir übernehmen (gestrippt, als attach-Skill im Research-Layer)”| Skill | Für Rolle | Warum |
|---|---|---|
| sepa-strategy (Minervini Trend-Template/VCP) | 1, 3, 4 | Top-Pick. Reines Long-Momentum-Swing — exakt Horizont & Long-only-Ethos. Als Entry-/Setup-Linse. Vorbehalt: Trigger strippen; sein Position-Sizing NICHT in den deterministischen ATR-1%-Pfad von Rolle 6 lassen. |
| stock-liquidity (Spreads/Amihud) | 1, 2, 6 | Direkter Match: Rolle 1 hat Liquiditäts-Minima, Rolle 2 berechnet Spreads. Amihud-Methodik wertvoll. |
| stock-correlation | 6 | Nur der Korrelations-Mess-Teil (für max_correlation-Limit). Pair-Trading-Sektion entfernen (Short-Bein verboten). |
| company-valuation (DCF/relativ/SOTP) | 4 | Saubere Bewertungs-Checkliste als Reasoning-Scaffold für die Deep-Analyst-Debatte. |
| earnings-preview / earnings-recap | 4, 8 | Earnings-Risiko ist ein Exit-/Wochenend-Gap-Trigger (Rolle 8). Strukturierte read-only Logik. |
| estimate-analysis | 3, 4 | Estimate-Revision als Confluence-Feature — nur point-in-time geliefert. |
| saas-valuation-compression (bedingt) | 4 | Nur bei SaaS-Tickern im AI/Tech-Universum. |
| skill-creator (Meta, optional) | 11 | Hilft, die eigenen gestrippten Skills sauber zu schreiben/zu bewerten. |
D.3 — Was wir NICHT übernehmen
Section titled “D.3 — Was wir NICHT übernehmen”| Skill | Grund (Constraint-Konflikt) |
|---|---|
| yfinance-data | Zieht Live-Yahoo dynamisch, KEIN point-in-time, keine Lizenz → Look-ahead-Killer; kollidiert mit Rolle 2. |
| options-payoff, etf-premium/gamma_squeeze | Optionen — verstößt gegen „nur Long, keine Optionen”. |
| funda-data (Funda AI), finance-sentiment (Adanos) | Vendor-Lock / kostenpflichtige Fremd-API → verstößt gegen self-hosted/FOSS (wir haben financial-datasets-MCP). |
| hormuz-strait | Öl-Krisen-Trading-Angle → verstößt gegen das Anti-Fossil-Ethik-Gate. |
| startup-analysis | Private Startups, off-topic für Public-Equity-Swing. |
| generative-ui | Claude-show_widget-spezifisch; Hermes ist modell-agnostisch (HITL-Dashboard selbst bauen). |
| Social-Reader (twitter/discord/telegram/linkedin/yc/opencli/tradingview) | ToS-/Cookie-/Stabilitäts-Risiko im autonomen 24/7-Betrieb. Höchstens als HITL-Recherche AUSSERHALB des Trading-Loops, schwach gewichtet & point-in-time. |
D.4 — Zwingende Sicherheits-Auflagen (für jeden übernommenen Skill)
Section titled “D.4 — Zwingende Sicherheits-Auflagen (für jeden übernommenen Skill)”- Trigger strippen — Frontmatter-Auto-Trigger entfernen; nur explizites
attach_skillsan definierte Jobs/Subagenten. - Code entfernen — kein mitgelieferter Live-Daten-/Netzwerk-Code; Skills sind reiner Markdown-Text.
- Point-in-time-Wrapper — Daten kommen ausschließlich aus dem
feature_snapshot(Rolle 2) mitas_of-Stempel. - Statisches Pinning — extrahierten Inhalt versioniert ins Repo kopieren (kein Laufzeit-
npx-Pull → Supply-Chain-Schutz gegen Prompt-Injection/Repo-Änderungen). - Execution-Grenze — Skills berühren
place_ordernie; alles bleibt links davon. - Eigene Review — jeder Skill durchläuft die skill-creator-Rubrik, bevor er in den Stack kommt.
D.5 — Fazit
Section titled “D.5 — Fazit”Aufnehmen — ja, aber als kuratierte, gestrippte Methodik-Bibliothek, nicht als Plug-in. Größter Einzelgewinn: sepa-strategy als Long-only-Swing-Entry-Linse. Größter Fallstrick: die native Installation mit aktiven Triggern. Aufwand gering (Markdown extrahieren + Trigger/Code strippen), Nutzen solides Reasoning-Scaffolding für die Analyse-Rollen — ohne ein einziges hartes Prinzip zu verletzen.
Teil E — Querschnitts-Prinzipien
Section titled “Teil E — Querschnitts-Prinzipien”Die folgenden Prinzipien wiederholen sich in (fast) jeder Rolle. Sie sind hier einmal konsolidiert und gelten systemweit; in den Rollen-Abschnitten sind sie nur noch rollenspezifisch instanziiert.
E.1 — Long-only-Enforcement
Section titled “E.1 — Long-only-Enforcement”Kein Short, kein Leverage, keine Optionen, keine Inverse-/Leverage-ETFs. Erzwungen mehrfach: R1 filtert ETF-Typ; R3/R4 erzeugen nur buy/hold/skip (Sell-Signale fließen nur als caution); R5 gibt nur buy/hold/skip/ESCALATE_HITL; R6 sizt nur Longs; R7 blockt side != "buy" als allerersten Check (hart, nicht delegierbar); R8 verkauft maximal die bestehende Long-Qty (qty_to_sell <= broker_qty_long); R10-Harness direction='longonly'.
E.2 — Paper-first / Doppel-Gate
Section titled “E.2 — Paper-first / Doppel-Gate”ALPACA_PAPER_TRADE=True und LIVE_TRADING_ENABLED=false müssen gleichzeitig gelten. R5 macht die CIO-Entscheidung nur gültig, wenn beide Flags stimmen; R7 verifiziert account_type aus dem frischen Live-API-Response (vertraut nie der gecachten .env); R11 aktiviert bei Abweichung den Kill-Switch. Live-Übergang nur via manueller 3-Schritt-Go/No-Go-Checkliste nach ≥4 Wochen (faktisch ≥3 Monate / ≥30 Trades, R10).
E.3 — Mandatory HITL (Human-in-the-Loop)
Section titled “E.3 — Mandatory HITL (Human-in-the-Loop)”Vor jeder Order ein frischer, signierter Telegram-Approval-Token (≤15 Min). R5 markiert hitl_required=true für jedes buy und eskaliert Grenzfälle; R9 betreibt den Telegram-Flow (15-Min-Timeout, Default hold, Rubber-Stamping-Warnung bei Approve <5 s); R7 verifiziert die Token-Frische; R11 verlangt ein Approval-Receipt mit Hash im Audit, sonst HOLD.
E.4 — Point-in-time / kein Look-ahead
Section titled “E.4 — Point-in-time / kein Look-ahead”Jeder Datensatz trägt available_at; Feature-Berechnung nutzt nur available_at <= decision_as_of; der laufende Bar wird ausgeschlossen; Indikatoren .shift(1). LLMs erhalten nur den Snapshot + Anweisung, außerhalb INSUFFICIENT_DATA zu sagen (R2, R3, R4). Für die LLM-Systeme zählt als echtes OOS nur Forward-Paper nach dokumentiertem Modell-Cutoff (R10); historische LLM-Backtests sind Pretraining-kontaminiert.
E.5 — Determinismus an der Execution-Grenze
Section titled “E.5 — Determinismus an der Execution-Grenze”Alle sicherheits-/kapital-/rechtskritischen Entscheidungen sind deterministischer, unit-testbarer Python-Code: R1-Build, R6-Sizing, R7-place_order-Gate, R8-Exit-Logik, R9-Compliance-Gate, R10-Berechnung, R11-Gates. LLM-Aggregation in R4 ist eine „Determinismus-Insel” (Majority-Vote im Code). Rohe MCP-Order-Tools sind internal_only/LLM-unsichtbar; nur place_order wird exponiert.
E.6 — Ethik-Exclusion (Defense-in-Depth)
Section titled “E.6 — Ethik-Exclusion (Defense-in-Depth)”Zero-Tolerance für Rüstung/Waffen, Fossil, Tobacco, Gambling; konservativer Dual-Use-Ausschluss (>5 % Revenue / primärer Militärkunde / beworbene Militäranwendung). Erzwungen an drei Stellen: R1 (Universe-Build, härtestes Gate), R6 (abschließende GICS-Sektor-Kontrolle), R7 (place_order-Gate, Frozenset + SIC-Recheck) — plus R10 (assert_ethics_clean vor jedem Backtest). Single-Source der Listen: universe_policy.yaml; R7 hält bewusst eine defensive Obermenge.
E.7 — Audit-Trail
Section titled “E.7 — Audit-Trail”Jede Entscheidung, jedes Modell-Votum, jeder Order-Versuch (auch jeder BLOCK) wird in SQLite + append-only JSONL mit trace_id, data_snapshot_hash, model_version, Input-/Output-Hash und Reason-Code persistiert (5-Jahr-Retention, WAG-2018-/MiFID-II-/FMA-konform). Fail-closed: eine Entscheidung ist ungültig, wenn der Audit-Write fehlschlägt (R5, R11).
E.8 — Graceful Failure → HOLD
Section titled “E.8 — Graceful Failure → HOLD”Jede Exception, jedes Timeout, invalides JSON, stale Data, fehlende Confidence/Quelle, Budget-Stop, Kill-Switch, Markt-geschlossen oder fehlender Audit-Kontext defaultet auf HOLD/no_trade (bzw. HOLD_DATA_ISSUE in R2, NO_GO in R10). Niemals „best-effort buy”, niemals Retry-Loops bis zur Order. Nur place_order löst Orders aus, und nur nach allen Gates + HITL.
E.9 — Gepinnte Modelle & Reproduzierbarkeit
Section titled “E.9 — Gepinnte Modelle & Reproduzierbarkeit”Alle entscheidungsrelevanten LLMs sind auf datierte Versionen gepinnt (z. B. claude-opus-4-20250514, gpt-5.x, gemini-2.5-pro); Temperatur 0 wo deterministisches Verhalten gefordert ist. R11 protokolliert pro Entscheidung model_pin, prompt_hash, input_snapshot_hash, code_git_sha, docker_image_digest, requirements_lock_hash, config_version; Modell-Updates nur via A/B-Test gegen die Vorversion. Ohne harten Pin wird ein Modell für entscheidungsrelevante Rollen gesperrt.
E.10 — Globaler Kill-Switch
Section titled “E.10 — Globaler Kill-Switch”Ein file-basierter Schalter (/opt/trading/KILL_SWITCH_ACTIVE), absichtlich primitiv (auch bei DB-/Netzwerkausfall lesbar), wird als erster Schritt jedes Trading-Jobs geprüft (R7, R8, R10, R11). Vier Eskalationsstufen (L1 Soft → L4 Global Kill); deterministische Monitoring-/Exit-Checks laufen auch bei Budget-Block weiter.
Teil F — Offene Fragen & Gesamt-Risiken
Section titled “Teil F — Offene Fragen & Gesamt-Risiken”Aggregiert und dedupliziert aus den „offene Fragen/Risiken”-Abschnitten aller 11 Rollen, priorisiert nach Schadenspotenzial × Wahrscheinlichkeit.
F.1 — P0: Existenziell / vor Live-Go zwingend geklärt
Section titled “F.1 — P0: Existenziell / vor Live-Go zwingend geklärt”- Paper→Live-Go/No-Go-Härte (R5, R7, R9, R10, R11). Live erst nach ≥3 Monaten Paper, ≥30 abgeschlossenen Trades, bestandener Overfitting-Trias (PBO/RC), 0 Secret-Leaks, 0 ungated Orders, 0 Budgetverletzungen, bestandenen Fault-Injection-Tests und HITL-Bestätigung. Offene Entscheidung: Akzeptieren wir bewusst ein statistisch „unter-powertes” erstes Go-Live (MinTRL ~750 Tage unerreichbar) und kompensieren mit kleinerem Initialkapital?
- MCP-Server als Single Point of Failure (R7, R11). Der gesamte Order-/Exit-Pfad hängt am
alpaca-mcp-server-Prozess; Healthcheck-/Restart-SLA zwischen R7 und R11 muss verbindlich definiert werden. replace_order-Wash-Trade-Edge-Case (R7, R8). Ist verifiziert, dass einreplace_orderauf eine Pending-Entry-Leg nie als MAR-Wash-Trade gewertet wird, während die SL-Leg lebt? Mit echtem 403-Monitoring in Paper bestätigen, bevor Live.- Regulatorische Grenze / Professionalitätsmerkmal (R5, R9). Bei steigender Frequenz/Volumen droht die Grenze zum „gewerblichen Handel” (FMA); jede Produktisierung/Signal-Weitergabe erfordert vorab Rechtsprüfung. Eigenhandel-only ist nicht verhandelbar.
F.2 — P1: Hoch — Edge-/Sicherheitskritisch
Section titled “F.2 — P1: Hoch — Edge-/Sicherheitskritisch”- LLM-Look-ahead-Kontamination (R2, R4, R10). Selbst mit Grounding können Modelle bekannte Narrative bevorzugen; echtes LLM-OOS = nur Forward-Paper → belastbare A/B/C-vs-D-Aussage dauert Monate. Evidence-Spans + Modell-Dissens-Checks Pflicht.
- Survivorship-freie & PiT-Fundamentaldaten (R1, R2, R10). Delisted-Ticker und saubere
filed_before-Fundamentals sind nicht trivial verfügbar; ohne sie bleiben Backtests „diagnostisch”. Ab Tag 1 eigene tägliche Universe-/Holdings-Snapshots archivieren; CRSP/Compustat-Spannung zum FOSS-Ethos prüfen. - Revenue-Split-/Dual-Use-Genauigkeit ohne MSCI/Sustainalytics (R1). Grobe Segment-Schätzungen riskieren falsche Themen-/Ethik-Einstufung; Default bei Unsicherheit = Consensus-Core-Pfad bzw. EXCLUDE + HITL. Günstiger ESG-Feed (Business-Involvement-Scores) erwägen. PLTR/Planet-Labs-Linie explizit in
universe_policy.yamlfestlegen. - Earnings-Datenzuverlässigkeit (R6, R8). Gap-Schutz hängt an verlässlichen Earnings-Kalendern; fehlende/widersprüchliche Daten innerhalb der Max-Hold-Periode → konservativer Entry-Block/Exit. Earnings-Calendar-Filter im Sizing (Halbierung vor Quartalszahlen?) prüfen.
- Stop-Market-Gap-Slippage (R7, R8). Tatsächliche realisierte Gap-Slippage auf Stop-Market-Legs quantifizieren; bei regelmäßig >2 % selektive Stop-Limit-Politik pro Liquiditätsklasse.
- HITL als Engpass & Bias-Quelle (R5, R8, R9). Zu häufige Eskalation senkt Durchsatz; menschliche Overrides können Performance verbessern oder verschlechtern (separat taggen, gegen Auto-Default
holdevaluieren); Exit-Notfälle brauchen evtl.auto-approve risk-reducing exitim Paper. Rubber-Stamping aktiv überwachen.
F.3 — P2: Mittel — Tuning, Kosten, Phase-2-Methodik
Section titled “F.3 — P2: Mittel — Tuning, Kosten, Phase-2-Methodik”- Persona-/Runden-/Divergenz-Tuning (R3, R4). Reicht 5 statt 12 Personas? Sind 2 Debatte-Runden + Divergenz-Schwellen (
escalation>0.6, Median>0.3) optimal? Erst nach ≥50 Live-Debatten nachschärfen. Personas evtl. ans Long-only-Themen-Szenario anpassen (Buffett/Damodaran vs. unprofitable Growth-Titel). - Kalibrierung & Confidence (R5). Outcome-Definition (5d-Direction vs. Trade-P&L), Kalibrierung pro Modellfamilie vs. Ensemble, Übergang von Phase-1-Shrinkage zu Platt/Temperature ab ≥100 Entscheidungen; Modell-Drift als neues Kalibrierungssegment.
- Sizing-Phase-2-Transition (R6). Wann sind Kovarianz-Schätzungen robust genug für HRP/PyPortfolioOpt? Rollierender Portfolio-Beta-Check (<1.5) gegen NASDAQ-Proxy-Drift.
- Exit-Parameter-Regime (R8). 10–14/2.0–2.5 (Chandelier),
earnings_exit_window_hours,weekend_reduction_pctpro Universe/Vola validieren; Overfitting durch R10 vermeiden. Wochenend-Reduktion kann Montag-Up-Gaps verpassen. - Judge-/Council-Mehrwert vs. Kosten (R5, R10). Lohnt der optionale Argument-Quality-Judge (R5) bzw. der read-only Interpretations-Council (R10, $5/Session)? Per A/B-Test über die ersten ~10 Reports klären; Judge nur bei Grenzfällen.
- Sentiment-Datenzugang (R2). Reddit/StockTwits haben API-/Noise-/Spam-Risiken; Sentiment darf erst nach eigener Eval ein positiver Ranking-Faktor werden.
- Provider-/Kosten-Entscheidungen (R2, R11). Alpaca Free vs. $99-Plan (IEX/15-min-Delay ausreichend?); financial-datasets Developer-Plan; LiteLLM-Budget-Tuning; Healthchecks.io vs. self-hosted; LangSmith-Datenabfluss.
F.4 — P3: Niedrig — Betrieb, Hygiene, Skalierung
Section titled “F.4 — P3: Niedrig — Betrieb, Hygiene, Skalierung”- Code-Hygiene gegen API-Deprecations (R7). PDT-Felder verschwinden ab 6. Juli 2026 → nirgends referenzieren; IMD-Detailverhalten ab 4. Juni 2026 in Paper verifizieren.
- Fractional Shares vs. Bracket-Schutz (R6, R7). Bracket-Orders nicht für Fractionals → ganzzahlige Qty erzwungen; falls je fraktioniert, separater serverseitiger Stop nötig.
- Timezone/DST/Early-Close (R2, R8, R11). UTC-Server + App-TZ-Logik +
exchange_calendars; DST-Spring/Fall-Tests; UUIDv7-Fallback; keine kritischen Jobs 01–03 ET. - Sandbox-Eskalation & Secret-Proxy (R11). gVisor/Kata erst nach Paper-Baseline (Kompatibilität/Performance); Credential-Proxy-Bauaufwand über Docker Secrets hinaus.
- Kill-Switch-Governance (R9, R11). Wer darf deaktivieren? Vier-Augen-Prinzip mit Rolle 9 festlegen, Deaktivierung protokollieren.
- EU-AI-Act & GDPR (R9). High-Risk-Annex-III-Guidelines erst 2026 (vorsorgliche Doku); keine PII/Kontostände in externe LLM-Prompts leaken.
- Themen-Wartungslast & „Peace”-Thinness (R1). GICS-Maps/Referenz-ETFs pflegen; das Peace/Humanitär-Sub-Cluster bleibt dünn (stützt sich auf defensive Cybersecurity).
- ETF-Holdings-ToS (R1). Automatisiertes Einlesen täglicher Holdings-Files je Anbieter (iShares/Global X/ARK) rechtlich für Eigennutzung prüfen.
Dieses Dokument ist internes Research/Engineering zur Systemarchitektur und stellt keine Anlage-, Rechts- oder Steuerberatung dar. Eigenhandel, Österreich/EU (WAG 2018, FMA, MiFID II, MAR). — Trading-Agency Master-Playbook (Council-Edition), Stand 31. Mai 2026, für Sebastian Friedrich / plan.ai.