using IBKRTrader.Core.Trading; namespace IBKRTrader.Modules.DebugTrading.Logic; /// /// Die Sicherungen des Prüfmoduls – reine Rechnung, damit sie ohne Broker und ohne Datenbank /// prüfbar sind. /// /// Die erste ist nicht verhandelbar: Das Modul arbeitet ausschließlich im /// Paper-Modus. Nicht als Einstellung, die jemand umlegen kann, sondern als Bedingung, die bei /// jedem Lauf neu geprüft wird. Ein Testmodul, das auf einem Live-Konto anläuft, wäre der /// teuerste denkbare Fehler dieses Projekts – und Einstellungen werden kopiert, wenn eine /// Instanz von der Test- auf die Live-Maschine umzieht. /// public static class DebugTradingGuard { /// /// Prüft den Handelsmodus. Liefert null, wenn gearbeitet werden darf, sonst den Grund. /// /// Bewusst gegen den geparsten Modus und nicht gegen die Zeichenkette: Ein unbekannter /// Wert fällt in TradingSettings.ParsedMode auf Paper zurück, und genau darauf will /// sich diese Prüfung nicht verlassen. Sie sieht den Rohwert mit an. /// public static string? CheckPaperMode(TradingMode mode, string rawMode) { if (mode != TradingMode.Paper) return $"Handelsmodus ist {mode} – das Prüfmodul arbeitet ausschließlich im Paper-Modus."; // Der Rohwert muss ebenfalls eindeutig Paper sagen. "Papier", "paper-live" oder ein // Tippfehler ergeben sonst über den Rückfall ein stilles Ja. if (!string.Equals(rawMode?.Trim(), nameof(TradingMode.Paper), StringComparison.OrdinalIgnoreCase)) return $"Handelsmodus \"{rawMode}\" ist nicht eindeutig Paper – das Prüfmodul bleibt stehen."; return null; } /// /// Prüft, ob eine neue Position eröffnet werden darf. null = ja. /// /// Aktuell offene Testpositionen. /// Obergrenze. /// Heute eröffneter Nominalwert. /// Tagesbudget. /// Nominalwert der geplanten Position. /// Obergrenze je Position. public static string? CheckOpening( int openPositions, int maxOpen, decimal spentToday, decimal dailyBudget, decimal plannedNotional, decimal maxPerTrade) { if (openPositions >= maxOpen) return $"Bereits {openPositions} offene Testpositionen (Grenze {maxOpen})."; if (plannedNotional > maxPerTrade) return $"Nominalwert {plannedNotional:F0} über der Grenze je Trade ({maxPerTrade:F0})."; if (spentToday + plannedNotional > dailyBudget) return $"Tagesbudget erschöpft: heute {spentToday:F0}, geplant {plannedNotional:F0}, " + $"Budget {dailyBudget:F0}."; return null; } }