================================================================================ G10-4.0 — Read-Site Inventory + Apply-Schema Reality Check KONSOLIDIERTER BERICHT (inkl. LIVE_TRADING_ENABLED-Korrektur) ================================================================================ Datum: 2026-05-09 Status: read-only Audit, keine Mutation Vorgänger: G10-3c Live-E2E Dry-run (succeeded), G10-3c-pre, G10-3b Nachfolger: G10-3.5 PHP createApplyCommand + G10-4.1 Bot-Side Writer/Provider Boundary: kein Code, keine Tests, kein Bot-Restart, kein Worker, keine Orders, kein Apply, kein Mainnet, kein Push, keine Secret-Ausgabe ================================================================================ ================================================================================ 0. EXECUTIVE SUMMARY (für späteres Re-Read) ================================================================================ WICHTIGSTE FAKTEN, die G10-4 betreffen: (0.1) Mainnet-Block-Architektur — KORREKTUR ggü. ursprünglichem G10-4-Scope LIVE_TRADING_ENABLED ist KEIN Mainnet-Blocker, sondern Bot-On-Switch. BINANCE_TESTNET ist der harte Mainnet-Guard. --paper ist im Phase-L-Design kein PaperTrader-Garant. Testnet-Sicherheit kommt über BINANCE_TESTNET=true. (0.2) PHP-Apply-Capability PHP kann dry_run=false NICHT erzeugen. Triple-Layer-Block: - ApplyProfileService hardcoded dry_run => true (3 Stellen) - kein createApplyCommand-Method - CommandTypeRegistry hard-rejects dry_run !== true - Filament Apply-Button permanent disabled => G10-3.5 als Vorbedingung von G10-4.1 erforderlich. (0.3) Read-Site-Mapping (13 Phase-1-Keys) 6 von 13 Keys sauber 1:1 mappbar. 5 von 13 Keys benötigen Pre-Implementation-Klärung (Mapping-Review G10-4.0.1). 2 Keys (max_total_exposure_pct, min_position_value_usdt) haben Doppel-Quellen oder Name-Mismatch. (0.4) Empfohlene Sequenz G10-4.0.1 Mapping-Review (User-Decisions zu 5 problematischen Keys) -> G10-3.5 PHP createApplyCommand (PHP-only) -> G10-4.1 Bot-Side RuntimeConfigWriter + ActiveConfigProvider + Migration -> G10-4.2 Handler-Branch dry_run=false + Live-E2E Apply. ================================================================================ 1. MAINNET-GUARD ARCHITEKTUR (KORREKTUR) ================================================================================ 1.1 LIVE_TRADING_ENABLED — TATSÄCHLICHE Bedeutung -------------------------------------------------------------------------------- Definition: trading/config/settings.py:35 LIVE_TRADING_ENABLED: bool = os.getenv('LIVE_TRADING_ENABLED','false').lower()=='true' Ist-Wert: true (Container .env) Funktion: Bot-Start-Gate. main.py:1116-1123 ruft sys.exit(1) wenn false. Phase L hat den PaperTrader aus dem Pfad entfernt — der Bot läuft AUSSCHLIESSLICH mit LiveTrader, und LiveTrader braucht diesen Flag-Wert true zum Start. WAS LIVE_TRADING_ENABLED NICHT tut: - Es routet KEINE Orders zwischen Testnet und Mainnet. - Es entscheidet NICHT zwischen PaperTrader und LiveTrader (Phase L: immer Live). - Es überschreibt NIEMALS BINANCE_TESTNET. - KEIN einziger Code-Pfad mutiert es zur Laufzeit. KLASSIFIKATION: B) Verwirrend aber sicher (siehe LIVE_TRADING_ENABLED-Audit). 1.2 BINANCE_TESTNET — Der harte Mainnet-Guard -------------------------------------------------------------------------------- Definition: trading/config/settings.py:29 BINANCE_TESTNET: bool = os.getenv('BINANCE_TESTNET','true').lower()=='true' Ist-Wert: true (Container .env) Funktion: EINZIGE Variable, die ccxt-Exchange-Endpoint wählt. live_trade.py:58-59: self._is_testnet = s.BINANCE_TESTNET exchange_id = 'binance_testnet' if self._is_testnet else 'binance' -> binance_testnet (Sandbox, https://testnet.binance.vision) oder binance (Mainnet, echtes Geld) Aktuell BINANCE_TESTNET=true => alle Trades gehen an Testnet-Sandbox. Mainnet bleibt zuverlässig blockiert. 1.3 --paper Flag — KEIN PaperTrader-Garant in Phase L -------------------------------------------------------------------------------- Verarbeitung: main.py:1074-1075 if '--paper' in sys.argv: settings.PAPER_TRADING = True Effekt: Setzt PAPER_TRADING-Flag auf True. Aktiviert main.py-Branches (Z. 599, 697, 800, 1006), die paper_trader.execute_buy(...) aufrufen. ABER: paper_trader = LiveTrader() (main.py:1124-1125) Der Variablenname ist Phase-L-Legacy, die Klasse ist Live. Trade-Ausführung über paper_trader.execute_buy() ist also EINE ECHTE ccxt-Order — nur dass sie wegen BINANCE_TESTNET=true an die Sandbox geht. PHASE-L-DESIGN (Code-Kommentar main.py:1114-1115): "Phase L — Trader-Auswahl: nur LiveTrader (Testnet/Mainnet via BINANCE_TESTNET). PaperTrader ist nicht mehr im aktiven Pfad — Bot stoppt wenn LIVE_TRADING_ENABLED=false." Schlussfolgerung: --paper ist ein "Code-Branch-Flag", kein Trader-Switch. Trade-Sicherheit in der Praxis kommt einzig durch BINANCE_TESTNET=true. 1.4 Defense-in-Depth Mainnet-Guard für G10-4 (NEU) -------------------------------------------------------------------------------- Layer | Bedingung | Ort ------+------------------------------------------+---------------------------------- L1 | Settings.BINANCE_TESTNET == True | Bot-Side, Pre-Apply-Check im | (HARTE Mainnet-Reject) | Handler vor RuntimeConfigWriter.apply() L2 | BOT_ENVIRONMENT == "testnet" | Worker-side env, bereits | | enforced (G10-3b ALLOWED_ENVIRONMENTS) L3 | command.payload.environment == "testnet" | Handler-side, bereits | | enforced (G10-3b validate_payload_basic) L4 | profile.environment == "paper" | PHP-side hard-restrict, bereits | | enforced (G10-2 Phase-1 ALWAYS paper) L5 | Settings.LIVE_TRADING_ENABLED == True | Bot-Side, OPTIONAL als Bot-Run- (opt.)| (NICHT als Mainnet-Guard!) | State-Sanity-Check. Apply gegen | | heruntergefahrenen Bot wäre | | sinnfrei. KRITISCHE REJECT-BEDINGUNG im G10-4-Handler-Code: if not Settings.BINANCE_TESTNET: raise ValueError( "validation/mainnet_blocked_g10_4_phase_1_disallows_mainnet_apply" ) (positives Test-Pattern: "testnet must be on", nicht "live must be off". Schließt den nicht-existenten ursprünglichen Guard endgültig aus.) 1.5 Naming-Cleanup-Empfehlung — eigene Phase, NICHT in G10-4 -------------------------------------------------------------------------------- Phase L hat zwei sehr irreführende Naming-Befunde stehengelassen: (a) paper_trader = LiveTrader() (Variable suggeriert PaperTrader) (b) LIVE_TRADING_ENABLED (Flag-Name suggeriert Mainnet-Live) Beides ist NICHT funktional kaputt, sondern Doku-/Naming-Schuld. Empfehlung: eigene Cleanup-Phase NACH G10-Komplettierung. NICHT G10-4-blocking. Ist als Follow-up im Memory zu notieren. ================================================================================ 2. READ-SITE INVENTORY — Bot-side, 13 Phase-1-Keys ================================================================================ Production-Pfade, ohne tests/__pycache__/Markdown. # | Phase-1-Key | Settings-Konstante | Datei:Zeile | Funktion/Kontext | Hot Path? | Decisions? | Migrations-Empfehlung --+----------------------------+---------------------------------+------------------------------------------------------+-------------------------------------------------+-----------+------------+---------------------------------------- 1a| max_open_positions | MAX_OPEN_POSITIONS | trading/execution/risk_manager.py:16 | RiskManager.__init__: self.max_open_positions | ja | ja | ActiveConfigProvider; Re-Init nötig | = settings.MAX_OPEN_POSITIONS | | | (init-time-capture) 1b| max_open_positions | MULTI_STRATEGY_MAX_OPEN_POSITIONS| trading/execution/multi_strategy_position_sizer.py:122| getattr(self._s, ..., 4) | ja | ja | ActiveConfigProvider 2 | max_risk_per_trade_pct | MAX_RISK_PER_TRADE | trading/execution/risk_manager.py:15 | RiskManager.__init__: self.max_risk_per_trade | ja | ja | ActiveConfigProvider; Re-Init nötig | = settings.MAX_RISK_PER_TRADE | | | 3a| max_total_exposure_pct | MULTI_STRATEGY_MAX_EXPOSURE_PCT | trading/execution/multi_strategy_position_sizer.py:170| max_invested = portfolio_value * MAX_EXPOSURE_PCT| ja | ja | ActiveConfigProvider 3b| max_total_exposure_pct | (HARDCODED MAX_EXPOSURE_PCT=0.80)| trading/execution/position_sizer.py:24, 61, 68 | Module-level Konstante, NICHT env-driven! | ja | ja | REVIEW NÖTIG (Hardcode legacy) | | | | 4 | min_position_value_usdt | MULTI_STRATEGY_MIN_NOTIONAL (?) | trading/execution/multi_strategy_position_sizer.py:227,234| if size < self._s.MULTI_STRATEGY_MIN_NOTIONAL | ja | ja | UNKLAR — Name-Mismatch, semantisch ähnlich 5 | cash_reserve_pct | MULTI_STRATEGY_CASH_RESERVE_PCT | trading/execution/balance_provider.py:122 | getattr(self._s, ..., 0.05) defensive | ja | ja | ActiveConfigProvider 6 | fee_buffer_pct | MULTI_STRATEGY_FEE_BUFFER_PCT | trading/execution/balance_provider.py:123 | getattr(self._s, ..., 0.002) defensive | ja | ja | ActiveConfigProvider 7 | daily_loss_limit_pct | NICHT EXISTIERT | - | - | - | - | REVIEW NÖTIG (Settings-Field fehlt komplett) 8 | weekly_loss_limit_pct | NICHT EXISTIERT | - | - | - | - | REVIEW NÖTIG (wie #7) 9 | tier_high_allocation_pct | MULTI_STRATEGY_TIER_HIGH_PCT | trading/execution/multi_strategy_position_sizer.py:277| _classify_tier(): return ('CORE-HIGH', PCT) | ja | ja | ActiveConfigProvider 10| tier_mid_allocation_pct | MULTI_STRATEGY_TIER_MID_PCT | trading/execution/multi_strategy_position_sizer.py:279| return ('CORE-MID', PCT) | ja | ja | ActiveConfigProvider 11| tier_low_allocation_pct | MULTI_STRATEGY_TIER_LOW_PCT | trading/execution/multi_strategy_position_sizer.py:281| return ('CORE-LOW', PCT) | ja | ja | ActiveConfigProvider 12| log_level | NICHT EXISTIERT | - | setup_logging() in main.py:79 ruft mit | nein | nein | REVIEW NÖTIG. Bot honoriert Key | Default logging.INFO, liest weder .env noch | (init-only)| | aktuell überhaupt nicht; | Settings | | | Apply wäre No-Op ohne Migration 13| decision_log_verbosity | NICHT EXISTIERT | - | - | - | - | REVIEW NÖTIG (wie #12) Init-Time-Capture-Problem: RiskManager (Z. 15-16) und MultiStrategyPositionSizer capturen Settings im __init__. Falls runtime_config.json mid-Lifecycle geschrieben wird, schlagen die Override OHNE Re-Instantiation oder Property-basierten Read NICHT durch. Per-Cycle-Snapshot-Modell muss daher Properties-Lookup pro Verwendung machen, NICHT init-time-capture. Anzahl Production-Read-Sites: ~10 (überschaubar, machbar). ================================================================================ 3. MAPPING-TABELLE (Phase-1, kompakt) ================================================================================ Runtime-Key | Settings-Konstante | Hauptfundstelle | Provider-Property (Vorschlag) | Typ | Default/Fallback | Status ----------------------------+-------------------------------------------------------+----------------------------------+--------------------------------------------+------------------+----------------------+------------ max_open_positions | MULTI_STRATEGY_MAX_OPEN_POSITIONS (4) | sizer:122 + risk_mgr:16 | active_config.max_open_positions | int | 4 (multi) | DOPPELT (legacy single-strategy MAX_OPEN_POSITIONS=5) max_risk_per_trade_pct | MAX_RISK_PER_TRADE (0.02) | risk_mgr:15 | active_config.max_risk_per_trade_pct | float | 0.02 | DOPPELT (MULTI_STRATEGY_MAX_RISK_PCT=0.01 existiert separat) max_total_exposure_pct | MULTI_STRATEGY_MAX_EXPOSURE_PCT (0.40) | sizer:170 | active_config.max_total_exposure_pct | float | 0.40 | DOPPELT + HARDCODE (legacy position_sizer.py:24 = 0.80) min_position_value_usdt | MULTI_STRATEGY_MIN_NOTIONAL (10.0) | sizer:227, 234 | active_config.min_position_value_usdt | float | 10.0 | NAME-MISMATCH cash_reserve_pct | MULTI_STRATEGY_CASH_RESERVE_PCT (0.05) | balance_provider:122 | active_config.cash_reserve_pct | float | 0.05 | OK fee_buffer_pct | MULTI_STRATEGY_FEE_BUFFER_PCT (0.002) | balance_provider:123 | active_config.fee_buffer_pct | float | 0.002 | OK daily_loss_limit_pct | (fehlt) | - | (neu) | float | - | FEHLT weekly_loss_limit_pct | (fehlt) | - | (neu) | float | - | FEHLT tier_high_allocation_pct | MULTI_STRATEGY_TIER_HIGH_PCT (0.08) | sizer:277 | active_config.tier_high_allocation_pct | float | 0.08 | OK tier_mid_allocation_pct | MULTI_STRATEGY_TIER_MID_PCT (0.05) | sizer:279 | active_config.tier_mid_allocation_pct | float | 0.05 | OK tier_low_allocation_pct | MULTI_STRATEGY_TIER_LOW_PCT (0.02) | sizer:281 | active_config.tier_low_allocation_pct | float | 0.02 | OK log_level | (fehlt) | setup_logging() Default INFO | (neu, ändert setup_logging-Param) | str/int | INFO | FEHLT decision_log_verbosity | (fehlt) | - | (neu) | enum (summary/full)| summary | FEHLT Sauberer Mapping-Status: 6 von 13 Keys (cash_reserve_pct, fee_buffer_pct, tier_high/mid/low, max_open_positions multi) -> 1:1 mappbar 5 von 13 Keys (daily/weekly_loss_limit, log_level, decision_log_verbosity, max_total_exposure-doppelt) -> Klärung nötig 2 Keys mit Name-Mismatch / doppelten Quellen. ================================================================================ 4. PHP APPLY CAPABILITY AUDIT ================================================================================ Frage | Antwort | Beleg -------------------------------------------------------------------+--------------+---------------------------------------------------- ApplyProfileService::createApplyCommand vorhanden? | NEIN | gui/app/Services/Apply/ApplyProfileService.php | | enthält nur createDryRunCommand (Z. 75) ApplyProfileService::createDryRunCommand vorhanden? | JA | Z. 75; setzt 'dry_run' => true an 3 Stellen (Z.104, 148, 171) Filament UI kann dry_run=false erzeugen? | NEIN | Apply-Button PERMANENT DISABLED | | (ProfileActionFactory.php:297, 325, 343) CommandTypeRegistry blockt dry_run=false? | JA, HART | CommandTypeRegistry.php:293-296: | | if ($payload['dry_run'] !== true) | | throw "apply_profile_testnet.dry_run_must_be_true_in_phase_1" Wo wird dry_run=false heute abgelehnt? | VIER LAYER | (1) Service hardcoded => true | | (2) kein Apply-Method-Service | | (3) Registry-Validator-Reject | | (4) UI-Button disabled PHP-Dateien für echte Apply-Capability | 3 Dateien | (1) ApplyProfileService.php (neue createApplyCommand) | | (2) CommandTypeRegistry.php (Validator lockern oder Phase-2-Branch) | | (3) ProfileActionFactory.php (Apply-Button enable mit Guards) | | + Filament-Confirmation-Dialog KLASSIFIKATION: B) PHP kann nur Dry-run erzeugen — und zwar mit triple-layer Hard-Restriction. => G10-3.5 als Vorbedingung von G10-4.1 erforderlich. ================================================================================ 5. RUNTIMECONFIGREADER STATUS ================================================================================ Aspekt | Befund ----------------------------------------+------------------------------------------------ Datei vorhanden | OK trading/runtime_config_reader.py | (3199 Bytes, mtime 2026-05-08) Default-Pfad | trading/state/runtime_config.json Verhalten bei missing | {} (defensive) Verhalten bei corrupt JSON | {} + Warning-Log (defensive) Verhalten bei JSON non-dict | {} + Warning-Log (defensive) Verhalten bei OSError | {} + Warning-Log (defensive) Production-Imports | NUR in command_worker.py:1052-1075 | (G10-1 Startup-Heartbeat) | NICHT in main.py, NICHT in settings.py runtime_config.json existiert? | NEIN (Container + Host: nur .gitkeep | in trading/state/) Reader-Defensiveness | AUSREICHEND für G10-4.1 — never-raises, | fallback-empty-dict Bot-Side-Wiring | FEHLT VOLLSTÄNDIG — main.py-Cycle-Loop | liest den Reader nirgends. Reader ist ein REINER STUB und wird vom Bot ignoriert. Bot-Side-Wiring (in main.py cycle-loop oder via ActiveConfigProvider) fehlt vollständig. ================================================================================ 6. RUNTIMECONFIGWRITER — DESIGN-VORSCHLAG (kein Code) ================================================================================ Aspekt | Vorschlag ------------------------------------+------------------------------------------------ File-Pfad | trading/state/runtime_config.json | (matched Reader-Default exakt; Verzeichnis | existiert bereits) Backup-Pfad | trading/state/runtime_config..json.bak | z.B. runtime_config.20260509T100000Z.json.bak | KEIN Auto-Pruning (per Q5-Antwort der Q&A) Atomic-Write | tmp-File mit gleichem Verzeichnis (für same-fs-rename), | JSON-dump, os.fsync, dann os.replace(tmp, target) Validation vor Write | Re-validierung über existente | _g10_3b_validate_schema + | _g10_3b_validate_cross_field | Helper im command_worker -> Fail -> KEIN Write, | command status=failed 13-Key-Whitelist | Hard-coded Set: | _RUNTIME_OUTPUT_ALLOWED_KEYS = | G7_ALLOWED_SUMMARY_KEYS | G9_ALLOWED_RISK_KEYS | Schreiben verweigern, falls payload zusätzliche | Keys enthält Restore-Mechanik | Falls Validation NACH erfolgreichem Write | fehlschlägt (sollte nicht passieren, defensiv): | os.replace(backup, target) | -> audit "apply_rolled_back" Existierende Helper | Pattern aus | trading/scripts/state_recon_1_cleanup.py:229-235 | trading/scripts/b_fee_fix_2_backfill.py:397 | ist Template — gleiche Mechanik tmp+os.replace | KEIN zentraler Helper im Code; G10-4.1 könnte | einen trading/utils/atomic_json_writer.py-Helper | extrahieren. trading/state/ Existenz-Garantie | Verzeichnis existiert (Container + Host) | Writer sollte os.makedirs(..., exist_ok=True) | vor Write defensiv prüfen Output-Schema | { | "summary": {<2 keys>}, | "risk": {<11 keys>}, | "_meta": { | "applied_at": "...", | "command_id": "...", | "profile_id": "...", | "version": N, | "checksum": "..." | } | } Permissions | Datei wird vom Worker (UID node) geschrieben, | vom Bot (UID node) gelesen — beide laufen im | selben Container, kein UID-Konflikt ================================================================================ 7. BOT-HEALTH & BOUNDARY CHECKS (Stand 2026-05-09 ~10:35 UTC) ================================================================================ Check | Wert -------------------------------------+---------------------------------------------------- Bot-cmdline | python3 main.py --paper Bot PID | 14381 (stable seit 2026-05-09 04:31:26 UTC nach | B-FEE-FIX-4-1 Restart) Watchdog PID | bot_watchdog.sh läuft normal clawbot-worker container | nicht aktiv (kein Prozess, kein Container) .env mtime | 1777991334 (2026-05-05 16:28:54) unverändert runtime_config.json existiert | NEIN (nur .gitkeep) BINANCE_TESTNET | true (Mainnet-Block aktiv) LIVE_TRADING_ENABLED | true (Bot-Run-State, NICHT Mainnet-Gate!) PAPER_TRADING | true BINANCE_API_KEY | vorhanden in .env (NICHT ausgelesen) BINANCE_SECRET | vorhanden in .env (NICHT ausgelesen) DB-counts | commands=2 (alle succeeded) | command_audit_log=9 | audit_events=4 | config_profiles=1 | risk_settings=11 | bot_statuses=1800+ live_portfolio.json hash | drifts vom laufenden Bot, NICHT durch G10-4.0 Active Exchange-Klasse | binance_testnet (per live_trade.py:58-60, | weil BINANCE_TESTNET=true) | Mainnet-Endpoint NICHT aktiv ================================================================================ 8. RISIKEN / BLOCKER ================================================================================ ID | Risiko | Schwere | Anmerkung ----+-------------------------------------------------------------------------------------------+-----------+--------------------------------- R1 | 5 von 13 Keys nicht eindeutig im Bot mappbar | HOCH | G10-4.0.1 Mapping-Review nötig | (max_total_exposure_pct Doppel/Hardcode, | | vor Implementation | min_position_value_usdt Name-Mismatch, | | | daily_loss_limit_pct + weekly_loss_limit_pct + log_level + decision_log_verbosity | | | fehlen komplett) | | R2 | PHP kann dry_run=false nicht erzeugen (Triple-Layer-Block) | BLOCKIERT | G10-3.5 Phase nötig | G10-4 | R3 | MAX_EXPOSURE_PCT = 0.80 ist module-level Hardcode in legacy position_sizer.py | MITTEL | Code-Touchup vor G10-4.1 | — nicht-überschreibbar | | oder bewusste "legacy ignored"-Decision R4 | Init-time-Capture-Pattern in RiskManager + MultiStrategyPositionSizer | MITTEL | Migrations-Strategie muss Property- | — Override greifen ohne Re-Init oder Property-Read nicht | | basiert sein, kein einmaliges Capture R5 | log_level und decision_log_verbosity werden vom Bot heute überhaupt nicht gelesen | MITTEL | Entscheidung: | — Apply wäre No-Op | | (a) aus Phase-1-Allowlist entfernen | | (b) Bot-side neue Read-Sites bauen | | (c) G10-4 ohne diese 2 Keys mit | | anschließender Phase-1.1 R6 | MAX_RISK_PER_TRADE (legacy 0.02) vs MULTI_STRATEGY_MAX_RISK_PCT (0.01) | MITTEL | Mapping-Decision User: welcher | — User-Profile mit max_risk_per_trade_pct würde nur die legacy-Konstante setzen, | | Pfad ist "der wahre"? | nicht die multi-Variante | | R7 | LIVE_TRADING_ENABLED=true als Mainnet-Guard ungeeignet | KORREKTUR | Mainnet-Guard ist NICHT | — Bot startet nicht ohne LIVE_TRADING_ENABLED=true (main.py:1116-1120); | erfasst | LIVE_TRADING_ENABLED, sondern | Mainnet wird durch BINANCE_TESTNET=true blockiert | | BINANCE_TESTNET=true (positiv-Test). | | | Defense-in-Depth in Section 1.4. R8 | Anzahl Hot-Path-Read-Sites: ~10 in Production-Code | NIEDRIG | Migration ist überschaubar; | | per-Key Touchpoint-Test machbar R9 | Worker-Daemon noch nicht aktiviert (G10-3d offen) | NIEDRIG | Live-E2E in G10-4.2 läuft via | | --once analog G10-3c R10 | Phase-L Naming-Schuld (paper_trader=LiveTrader, LIVE_TRADING_ENABLED-Naming) | NIEDRIG | Eigene Cleanup-Phase NACH G10 | | NICHT G10-4-blocking ================================================================================ 9. EMPFOHLENE NÄCHSTE ETAPPE (durable Sequenz) ================================================================================ (9.1) G10-4.0.1 Mapping-Review-Schleife (read-only, ohne Code) User entscheidet pro problematischen Key (5 Stück + max_risk + max_open): Q-A | max_open_positions: multi (4) ODER legacy (5) ODER beide? Q-B | max_risk_per_trade_pct: legacy (0.02) ODER multi (0.01) ODER beide? Q-C | max_total_exposure_pct: nur Multi-Pfad? Legacy-Hardcode ignorieren oder mit-mutieren (Code-Cleanup)? Q-D | min_position_value_usdt: maps to MULTI_STRATEGY_MIN_NOTIONAL? Name-Anpassung im Profile oder Bot? Q-E | daily_loss_limit_pct + weekly_loss_limit_pct: (a) aus Phase-1-Allowlist entfernen (b) als neue Bot-Settings-Felder + Read-Sites einführen (c) später als Phase-1.1 nachreichen Q-F | log_level + decision_log_verbosity: (a) aus Phase-1-Allowlist entfernen (b) setup_logging() um Param erweitern + per-Cycle re-init (c) später als Phase-1.1 nachreichen (9.2) G10-3.5 PHP createApplyCommand (PHP-only) - neue Methode ApplyProfileService::createApplyCommand - CommandTypeRegistry-Validator Phase-2-Branch (oder Validation-Lockerung) - Filament-Apply-Button enable mit Confirmation-Dialog + Mainnet-Guards Bot-Side bleibt UNANGETASTET. (9.3) G10-4.1 Bot-Side RuntimeConfigWriter + ActiveConfigProvider + Hot-Path-Migration der 13 Keys gemäß G10-4.0.1 User-Decisions + Mainnet-Guard via BINANCE_TESTNET-Required (Defense-in-Depth Section 1.4) (9.4) G10-4.2 Handler-Branch dry_run=false + Live-E2E Apply + analog G10-3c-Pattern: Container-Sync, Pre-State, --once, Post-Verify + Backup-Verification in trading/state/ (9.5) Naming-Cleanup-Phase (separat, optional, NACH G10) - paper_trader -> live_trader (Variable in main.py) - LIVE_TRADING_ENABLED -> BOT_RUN_ENABLED (oder ähnlich) Reines Refactoring, kein Behaviour-Change. ================================================================================ 10. BOUNDARY-BESTÄTIGUNGEN ================================================================================ Check | Stand vor G10-4.0 | Stand nach G10-4.0 | Bewertung -------------------------------------+-------------------+---------------------+----------- Code geändert | - | nein | OK Tests geändert | - | nein | OK Bot-Restart | - | nein (PID 14381 stable)| OK Worker gestartet | - | nein | OK Orders erzeugt | - | nein | OK live_portfolio.json mutiert | hash drift | hash drift | OK | (laufender Bot) | (laufender Bot) | (nicht durch G10-4.0) runtime_config.json mutiert | nicht existent | nicht existent | OK .env mutiert | mtime 1777991334 | mtime 1777991334 | OK Mainnet-Pfad | nicht aktiv | nicht aktiv | OK (BINANCE_TESTNET=true) Push | - | repo hat kein remote | OK Test-DBs | sauber | sauber | OK commands count | 2 | 2 | OK command_audit_log count | 9 | 9 | OK Secrets in Output | - | KEINE | OK Stop-Regeln getriggert | - | KEINE | OK ================================================================================ KURZFASSUNG / FINAL EMPFEHLUNG ================================================================================ (K.1) LIVE_TRADING_ENABLED ist KEIN Mainnet-Blocker, sondern Bot-On-Switch. BINANCE_TESTNET=true ist der harte Mainnet-Guard. (K.2) G10-4-Mainnet-Guard MUSS umgestellt werden: FALSCH: if Settings.LIVE_TRADING_ENABLED: reject RICHTIG: if not Settings.BINANCE_TESTNET: raise mainnet_blocked Plus 4-Layer Defense-in-Depth (Section 1.4). (K.3) PHP kann dry_run=false NICHT erzeugen. G10-3.5 (PHP createApplyCommand) ist Vorbedingung von G10-4.1. (K.4) 5 von 13 Phase-1-Keys benötigen Mapping-Review (G10-4.0.1). Empfehlung: User-Decisions pro Key VOR jeder Code-Mutation. (K.5) Naming-Cleanup (paper_trader=LiveTrader, LIVE_TRADING_ENABLED-Name) ist eigene Phase NACH G10-Komplettierung. NICHT G10-4-blocking. (K.6) Empfohlene Reihenfolge: G10-4.0.1 Mapping-Review (User-Decisions) -> G10-3.5 PHP createApplyCommand -> G10-4.1 Bot-Side Writer + Provider + Migration -> G10-4.2 Handler-Branch dry_run=false + Live-E2E Apply -> (optional) Naming-Cleanup-Phase ================================================================================ ENDE DES BERICHTS ================================================================================