namespace IBKRTrader.Core.Trading; /// Kauf oder Verkauf. public enum TradeSide { Buy, Sell } /// Order-Typ. public enum OrderType { Market, Limit } /// Handelsmodus – Paper-Account (Test) oder Live. public enum TradingMode { Paper, Live } /// /// Signal, das ein Modul an den übergibt. /// Das Modul liefert nur die Absicht – Sizing, Risiko und Ausführung macht der Core. /// public sealed record TradeSignal { /// Ticker-Symbol (z. B. "AAPL"). public required string Symbol { get; init; } /// Kauf oder Verkauf. public required TradeSide Side { get; init; } /// Kürzel des auslösenden Moduls (z. B. "CT"). public required string SourceModule { get; init; } /// Begründung des Signals (für Logging/Buchführung). public string Reason { get; init; } = ""; /// Optionaler Limit-Preis. null = Market-Order. public decimal? LimitPrice { get; init; } /// Optionaler Nominalwert-Wunsch; sonst greift das Risiko-Sizing. public decimal? SuggestedNotional { get; init; } } /// Konkrete Order-Anforderung an den Broker. public sealed record OrderRequest { public required string Symbol { get; init; } public required TradeSide Side { get; init; } public required int Quantity { get; init; } public required OrderType Type { get; init; } public decimal? LimitPrice { get; init; } } /// Ergebnis einer Order-Platzierung. public sealed record OrderResult { public bool Success { get; init; } public string? OrderId { get; init; } public int FilledQuantity { get; init; } public decimal AvgFillPrice { get; init; } public string? Error { get; init; } public static OrderResult Filled(string orderId, int qty, decimal price) => new() { Success = true, OrderId = orderId, FilledQuantity = qty, AvgFillPrice = price }; public static OrderResult Fail(string error) => new() { Success = false, Error = error }; } /// Momentaufnahme eines Kurses. public sealed record Quote(string Symbol, decimal Last, decimal Bid, decimal Ask); /// Kontostand-Momentaufnahme des Brokers. public sealed record AccountState(decimal NetLiquidation, decimal AvailableFunds); /// Offene Position eines Moduls. public sealed record Position(string Module, string Symbol, int Quantity, decimal AvgPrice) { public decimal Notional => Quantity * AvgPrice; } /// Kontext für die Risikobewertung eines Signals. public sealed record RiskContext { /// Aktueller Kurs des Symbols. public required decimal Price { get; init; } /// Netto-Liquidationswert des Kontos. public required decimal NetLiquidation { get; init; } /// Aktuell vom Modul gehaltener Nominalwert (Summe offener Positionen). public decimal ModuleExposure { get; init; } /// Bereits gehaltene Stückzahl für das Signal-Symbol. public int ExistingQuantity { get; init; } } /// Aus den Settings abgeleitete Risiko-Parameter. public sealed record RiskParameters( decimal MaxTradePercent, decimal MaxPositionPercentPerModule, decimal MaxSlippagePercent); /// Entscheidung der Risikoprüfung. public sealed record RiskDecision { public bool Approved { get; init; } public int Quantity { get; init; } public string Reason { get; init; } = ""; public static RiskDecision Reject(string reason) => new() { Approved = false, Quantity = 0, Reason = reason }; public static RiskDecision Approve(int quantity, string reason = "OK") => new() { Approved = true, Quantity = quantity, Reason = reason }; } /// Ergebnis einer Signal-Ausführung durch den . public sealed record ExecutionResult { /// "EXECUTE", "SKIP" oder "ERROR". public required string Action { get; init; } public string Reason { get; init; } = ""; public OrderResult? Order { get; init; } public bool Executed => Action == "EXECUTE"; public static ExecutionResult Skip(string reason) => new() { Action = "SKIP", Reason = reason }; public static ExecutionResult Error(string reason, OrderResult? order = null) => new() { Action = "ERROR", Reason = reason, Order = order }; public static ExecutionResult Execute(OrderResult order) => new() { Action = "EXECUTE", Reason = "OK", Order = order }; }