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;
}
}