diff --git a/src/IBKRTrader.Core/Trading/Ibkr/IbkrConnection.cs b/src/IBKRTrader.Core/Trading/Ibkr/IbkrConnection.cs index 0aca3b1..d32385b 100644 --- a/src/IBKRTrader.Core/Trading/Ibkr/IbkrConnection.cs +++ b/src/IBKRTrader.Core/Trading/Ibkr/IbkrConnection.cs @@ -346,11 +346,17 @@ internal sealed class IbkrConnection : DefaultEWrapper, IDisposable _accounts[id] = slot; try { - // $LEDGER liefert zusaetzlich die Bargeldbestaende je Waehrung. Sie werden fuer die + // $LEDGER:ALL liefert die Bargeldbestaende JE WAEHRUNG. Sie werden fuer die // Waehrungsdeckung gebraucht (Kapitalmodell ยง4 Schicht C): ein Kauf in X darf nur aus // Cash in X finanziert werden, sonst entsteht ein Sollsaldo in X - ein Margin-Kredit, // auch wenn das Konto in Summe positiv aussieht. - _socket.reqAccountSummary(id, "All", "NetLiquidation,AvailableFunds,TotalCashValue,$LEDGER"); + // + // ":ALL" ist noetig und nicht kosmetisch. Das nackte "$LEDGER" liefert nur die + // Zusammenfassung in Kontobasiswaehrung, und die traegt als Waehrungskennung "BASE" - + // also genau den Wert, den die Auswertung ueberspringen muss, damit dasselbe Geld nicht + // zweimal zaehlt. Ergebnis war eine leere Aufschluesselung und damit eine Ablehnung + // jedes Kaufs durch Schicht C (am 2026-09-04 gegen das Paper-Gateway beobachtet). + _socket.reqAccountSummary(id, "All", "NetLiquidation,AvailableFunds,TotalCashValue,$LEDGER:ALL"); if (!await WaitAsync(slot.Done.Task, timeout, ct).ConfigureAwait(false)) { @@ -363,6 +369,16 @@ internal sealed class IbkrConnection : DefaultEWrapper, IDisposable return null; } + // Was der Broker an Waehrungen gemeldet hat, gehoert ins Log: ohne diese Zeile ist eine + // Ablehnung durch Schicht C ("verfuegbar 0") von aussen nicht von einem echten + // Geldmangel zu unterscheiden. + _logger.Info(LogModule, slot.Cash.Count == 0 + ? "Konto: keine Bargeldaufschluesselung je Waehrung erhalten - Schicht C lehnt Kaeufe " + + "deshalb ab. Antwortet das Gateway nicht auf $LEDGER:ALL?" + : "Konto: Bargeld je Waehrung " + string.Join(", ", + slot.Cash.Select(kv => string.Create(CultureInfo.InvariantCulture, + $"{kv.Key} {kv.Value:N2}"))) + "."); + return new AccountState( ReadDecimal(slot.Values, "NetLiquidation"), ReadDecimal(slot.Values, "AvailableFunds"),