using System.ComponentModel; using IBKRTrader.Core.Trading; namespace IBKRTrader.Core.Settings; // ─── Database ──────────────────────────────────────────────────────────────── [TypeConverter(typeof(ExpandableObjectConverter))] public class DatabaseSettings { [Category("Database")] [DisplayName("Host")] [Description("MySQL-Serveradresse (Hostname oder IP)")] public string Host { get; set; } = "your-db-host"; [Category("Database")] [DisplayName("Port")] [Description("MySQL-Port (Standard: 3306)")] public int Port { get; set; } = 3306; [Category("Database")] [DisplayName("Database")] [Description("Name der MySQL-Datenbank")] public string Database { get; set; } = "your-db-name"; [Category("Database")] [DisplayName("User")] [Description("MySQL-Benutzername")] public string User { get; set; } = "your-db-user"; [Category("Database")] [DisplayName("Password")] [Description("MySQL-Passwort")] [PasswordPropertyText(true)] public string Password { get; set; } = "CHANGE_ME"; public string BuildConnectionString() => $"Server={Host};Port={Port};Database={Database};" + $"User={User};Password={Password};" + $"AllowPublicKeyRetrieval=true;SslMode=Preferred;CharSet=utf8mb4;" + $"ConnectionTimeout=15;DefaultCommandTimeout=30;"; public override string ToString() => $"{User}@{Host}:{Port}/{Database}"; } // ─── IBKR TWS/Gateway (Socket API) ─────────────────────────────────────────── [TypeConverter(typeof(ExpandableObjectConverter))] public class IBKRSettings { [Category("IBKR Gateway")] [DisplayName("Host")] [Description("Adresse des IBKR Gateway (Standard: 127.0.0.1)")] public string Host { get; set; } = "127.0.0.1"; [Category("IBKR Gateway")] [DisplayName("Port")] [Description("IBKR Gateway Port (Paper: 4002, Live: 4001)")] public int Port { get; set; } = 4001; [Category("IBKR Gateway")] [DisplayName("Client ID")] [Description("Eindeutige Client-ID für die API-Verbindung")] public int ClientId { get; set; } = 1; [Category("IBKR Gateway")] [DisplayName("TWS-Broker verwenden")] [Description("Aktiviert den echten TWS-Broker. Aus = NullBroker (handelt nie). " + "Der globale Handelsschalter unter Trading bleibt davon unberührt.")] public bool UseTwsApi { get; set; } = false; [Category("IBKR Gateway")] [DisplayName("Marktdaten-Typ")] [Description("1 = Realtime, 2 = Frozen, 3 = verzögert, 4 = verzögert+Frozen. " + "Paper-Konten ohne Datenabo brauchen 3 oder 4, sonst kommen keine Kurse.")] public int MarketDataType { get; set; } = 4; [Category("IBKR Gateway")] [DisplayName("Verbindungs-Timeout (s)")] [Description("Wartezeit auf Socket-Verbindung und Handshake. TWS braucht nach einem Neustart mehrere Minuten.")] public int ConnectTimeoutSeconds { get; set; } = 15; [Category("IBKR Gateway")] [DisplayName("Anfrage-Timeout (s)")] [Description("Wartezeit auf Kurs-, Kontrakt- und Kontoantworten")] public int RequestTimeoutSeconds { get; set; } = 15; [Category("IBKR Gateway")] [DisplayName("Order-Timeout (s)")] [Description("Wartezeit auf den Endstatus einer Order. Danach gilt sie als fehlgeschlagen, " + "kann bei IBKR aber weiterhin aktiv sein.")] public int OrderTimeoutSeconds { get; set; } = 60; public override string ToString() => $"{Host}:{Port} (Client {ClientId}){(UseTwsApi ? "" : " – TWS-Broker aus")}"; } // ─── IBKR Web API (Client Portal Gateway) ──────────────────────────────────── [TypeConverter(typeof(ExpandableObjectConverter))] public class IBKRWebApiSettings { [Category("IBKR Web API")] [DisplayName("Aktiviert")] [Description("Aktiviert die IBKR Web API Marktdaten-Worker")] public bool Enabled { get; set; } = false; [Category("IBKR Web API")] [DisplayName("Gateway URL")] [Description("URL des Client Portal Gateway (Standard: https://localhost:5000)")] public string GatewayUrl { get; set; } = "https://localhost:5000"; [Category("IBKR Web API")] [DisplayName("History-Zeitraum")] [Description("Zeitraum für den ersten historischen Import (z.B. 2Y, 5Y, 1Y)")] public string HistoryPeriod { get; set; } = "2Y"; [Category("IBKR Web API")] [DisplayName("Max Requests/Sek")] [Description("Maximale API-Anfragen pro Sekunde (IBKR-Limit: 10, empfohlen: 5)")] public int MaxRequestsPerSecond { get; set; } = 5; public override string ToString() => Enabled ? $"Aktiv – {GatewayUrl}" : "Deaktiviert"; } // ─── Logging ───────────────────────────────────────────────────────────────── [TypeConverter(typeof(ExpandableObjectConverter))] public class LoggingSettings { [Category("Logging")] [DisplayName("Log Level")] [Description("Minimales Log-Level: Info, Warn oder Error")] public string Level { get; set; } = "Info"; [Category("Logging")] [DisplayName("Max. Dateigröße (MB)")] [Description("Maximale Größe einer Log-Datei in Megabyte")] public int MaxFileSizeMb { get; set; } = 10; [Category("Logging")] [DisplayName("Aufbewahrung (Tage)")] [Description("Anzahl Tage, nach denen Log-Dateien gelöscht werden")] public int RetentionDays { get; set; } = 30; public override string ToString() => $"Level: {Level}"; } // ─── Webserver ─────────────────────────────────────────────────────────────── [TypeConverter(typeof(ExpandableObjectConverter))] public class WebserverSettings { [Category("Webserver")] [DisplayName("Port")] [Description("Port des internen Webservers (Web-UI)")] public int Port { get; set; } = 5001; [Category("Webserver")] [DisplayName("Aktiviert")] [Description("Webserver und REST-API beim Start aktivieren")] public bool Enabled { get; set; } = false; public override string ToString() => Enabled ? $"Aktiv auf Port {Port}" : "Deaktiviert"; } // ─── Workers ───────────────────────────────────────────────────────────────── [TypeConverter(typeof(ExpandableObjectConverter))] public class WorkerSchedule { [Category("Worker")] [DisplayName("Aktiviert")] public bool Enabled { get; set; } = true; [Category("Worker")] [DisplayName("Interval (Minuten)")] public int IntervalMinutes { get; set; } = 30; public override string ToString() => Enabled ? $"alle {IntervalMinutes} min" : "Deaktiviert"; } [TypeConverter(typeof(ExpandableObjectConverter))] public class WorkerSettings { [Category("Workers")] [DisplayName("BackupWorker")] [Description("Zeitplan für den automatischen Backup-Worker")] public WorkerSchedule BackupWorker { get; set; } = new(); [Category("Workers")] [DisplayName("IBKR Instrument-Sync")] [Description("Zeitplan für die IBKR Stammdaten-Synchronisation (alle 30 Tage)")] public WorkerSchedule InstrumentSyncWorker { get; set; } = new() { IntervalMinutes = 43200 }; // 30 Tage [Category("Workers")] [DisplayName("IBKR Preishistorie")] [Description("Zeitplan für den täglichen IBKR Preishistorie-Abruf")] public WorkerSchedule PriceHistoryWorker { get; set; } = new() { IntervalMinutes = 1440 }; // 24h public override string ToString() => "Worker-Konfiguration"; } // ─── Trading ───────────────────────────────────────────────────────────────── [TypeConverter(typeof(ExpandableObjectConverter))] public class TradingSettings { [Category("Trading")] [DisplayName("Modus")] [Description("Handelsmodus: Paper (Test-Account, Port 4002) oder Live (Port 4001)")] public string Mode { get; set; } = "Paper"; [Category("Trading")] [DisplayName("Betriebszeitzone")] [Description("Zeitzone dieser Instanz in IANA-Schreibweise, z. B. \"Europe/Berlin\" (EU) oder " + "\"America/New_York\" (US). Gilt für Anzeige, Logdatei-Tagesgrenzen, Berichtszeiten " + "und Buchungsperioden; gespeichert wird immer UTC. VOR den ersten Trades festlegen " + "und danach nicht mehr ändern – ein Wechsel verschiebt rückwirkend alle Tagesgrenzen. " + "Leer = Zeitzone des Systems (nicht empfohlen). Wirkt erst nach einem Neustart.")] public string ApplicationTimeZoneId { get; set; } = "Europe/Berlin"; [Category("Trading")] [DisplayName("Trading aktiv")] [Description("Globaler Hauptschalter. Nur wenn aktiv werden Orders ausgeführt.")] public bool TradingEnabled { get; set; } = false; [Category("Trading")] [DisplayName("Max. je Trade (%)")] [Description("Maximaler Nominalwert einer einzelnen Position in % des Kontowerts")] public double MaxTradePercent { get; set; } = 5.0; [Category("Trading")] [DisplayName("Max. je Modul (%)")] [Description("Maximaler Gesamt-Nominalwert aller Positionen eines Moduls in % des Kontowerts")] public double MaxPositionPercentPerModule { get; set; } = 20.0; [Category("Trading")] [DisplayName("Max. Slippage (%)")] [Description("Maximal erlaubte Abweichung zwischen Limit-Preis und aktuellem Kurs")] public double MaxSlippagePercent { get; set; } = 5.0; [Category("Trading")] [DisplayName("Gewinnziel (%)")] [Description("Ziel-Gewinn einer Position in Prozent (für spätere Exit-Logik)")] public double ProfitTargetPercent { get; set; } = 50.0; /// Parst den Modus in das Enum (Fallback: Paper). public TradingMode ParsedMode => Enum.TryParse(Mode, true, out var m) ? m : TradingMode.Paper; public override string ToString() => $"{Mode} – {(TradingEnabled ? "aktiv" : "inaktiv")}"; } // ─── Accounting ────────────────────────────────────────────────────────────── [TypeConverter(typeof(ExpandableObjectConverter))] public class AccountingSettings { [Category("Accounting")] [DisplayName("Basiswährung")] [Description("Kontobasiswährung für die Abrechnung (Standard: USD)")] public string BaseCurrency { get; set; } = "USD"; [Category("Accounting")] [DisplayName("Ingest-Intervall (Stunden)")] [Description("Abstand der automatischen Kontoauszug-Abrufe (Live-Quelle; offline ungenutzt)")] public int IngestIntervalHours { get; set; } = 6; [Category("Accounting")] [DisplayName("Flex Query-Id")] [Description("IBKR Activity Flex Query-Id (Zielland – Live-Abruf; leer = offline)")] public string FlexQueryId { get; set; } = ""; [Category("Accounting")] [DisplayName("Flex-Token")] [Description("IBKR Flex Web Service Token (Zielland; verschlüsselt ablegen, nicht im Klartext)")] [PasswordPropertyText(true)] public string FlexToken { get; set; } = ""; public override string ToString() => $"Basis {BaseCurrency}, alle {IngestIntervalHours} h"; } // ─── Supervisor ────────────────────────────────────────────────────────────── [TypeConverter(typeof(ExpandableObjectConverter))] public class SupervisorSettings { [Category("Supervisor")] [DisplayName("Modell")] [Description("OpenRouter-Modell für die Analyse (Standard: openrouter/auto)")] public string Model { get; set; } = "openrouter/auto"; [Category("Supervisor")] [DisplayName("Token-Budget/Analyse")] [Description("Weiches Token-Budget je Analyse-Lauf (Hinweis; harte Grenze = max. Tool-Iterationen)")] public int TokenBudgetPerRun { get; set; } = 60000; public override string ToString() => Model; } // ─── Deploymentcenter ──────────────────────────────────────────────────────── [TypeConverter(typeof(ExpandableObjectConverter))] public class DeploymentcenterSettings { [Category("Deploymentcenter")] [DisplayName("API Token")] [Description("Authorization: Bearer . Ohne Token: keine Heartbeats, keine Fehlermeldungen.")] [PasswordPropertyText(true)] public string ApiToken { get; set; } = ""; [Category("Deploymentcenter")] [DisplayName("Heartbeat aktiv")] [Description("Dead-Man's-Switch an/aus")] public bool HeartbeatEnabled { get; set; } = true; [Category("Deploymentcenter")] [DisplayName("Monitor Source")] [Description("Monitor-Name im Dashboard. Leer = Rechnername (Auto-Registrierung beim ersten Ping)")] public string MonitorSource { get; set; } = ""; [Category("Deploymentcenter")] [DisplayName("Monitor Instance")] [Description("Für mehrere Instanzen desselben Dienstes (z. B. EU/US)")] public string MonitorInstance { get; set; } = "default"; [Category("Deploymentcenter")] [DisplayName("Heartbeat-Intervall (Sekunden)")] [Description("warning nach 2×, down nach 4× dieses Intervalls")] public int HeartbeatIntervalSeconds { get; set; } = 60; [Category("Deploymentcenter")] [DisplayName("Fehler melden")] [Description("Error/Fatal an den Fehler-Stream (/api/errors/v1/report)")] public bool ReportErrors { get; set; } = true; [Category("Deploymentcenter")] [DisplayName("Update-Prüfung beim Start")] [Description("Prüft nur, installiert nichts von selbst")] public bool CheckUpdatesOnStart { get; set; } = true; [Category("Deploymentcenter")] [DisplayName("Update-Kanal")] [Description("prod, beta oder dev")] public string UpdateChannel { get; set; } = "prod"; [Category("Deploymentcenter")] [DisplayName("Lizenzschlüssel")] [Description("Nur Rückfall, falls noch kein Schlüssel im verschlüsselten Cache liegt")] [PasswordPropertyText(true)] public string LicenseKey { get; set; } = ""; public override string ToString() => HeartbeatEnabled ? "Aktiv" : "Deaktiviert"; } // ─── Root ──────────────────────────────────────────────────────────────────── public class AppSettings { [Category("Database")] [DisplayName("Datenbank")] [Description("MySQL-Verbindungseinstellungen")] public DatabaseSettings Database { get; set; } = new(); [Category("IBKR Gateway")] [DisplayName("IBKR")] [Description("Interactive Brokers Gateway-Verbindung (Socket API)")] public IBKRSettings IBKR { get; set; } = new(); [Category("IBKR Web API")] [DisplayName("IBKR Web API")] [Description("Client Portal Gateway für Marktdaten")] public IBKRWebApiSettings IBKRWebApi { get; set; } = new(); [Category("Logging")] [DisplayName("Logging")] [Description("Log-Level und Datei-Einstellungen")] public LoggingSettings Logging { get; set; } = new(); [Category("Webserver")] [DisplayName("Webserver")] [Description("Interner HTTP-Server und REST-API")] public WebserverSettings Webserver { get; set; } = new(); [Category("Workers")] [DisplayName("Worker-Einstellungen")] [Description("Zeitpläne der einzelnen Core-Worker")] public WorkerSettings WorkerSettings { get; set; } = new(); [Category("Trading")] [DisplayName("Trading")] [Description("Handelsmodus und Risiko-Parameter")] public TradingSettings Trading { get; set; } = new(); [Category("Accounting")] [DisplayName("Accounting")] [Description("Buchhaltung/Reporting (unabhängiger Kontoauszug-Ingest)")] public AccountingSettings Accounting { get; set; } = new(); [Category("Supervisor")] [DisplayName("Supervisor")] [Description("KI-Analyse/Forensik (OpenRouter, read-only)")] public SupervisorSettings Supervisor { get; set; } = new(); [Category("Deploymentcenter")] [DisplayName("Deploymentcenter")] [Description("Lizenz, Watchdog, UpdateService, Fehler-Stream (https://dc.mhdf.de)")] public DeploymentcenterSettings Deploymentcenter { get; set; } = new(); }