Eigener Seam neben IBrokerClient: Wer handelt, braucht ihn nicht; wer die eigene Buchfuehrung gegen den Broker abstimmt, braucht nur ihn. Zuteilung und Verfall aendern Positionen ohne Order von uns - ohne Abgleich laeuft das Managementbuch zwangslaeufig auseinander. - IBrokerPortfolioReader mit GetPositionsAsync/GetExecutionsAsync; implementiert von IbkrBrokerClient und NullBrokerClient (DI registriert beide Rollen auf derselben Instanz). - IbkrConnection: reqAccountUpdates statt reqPositions (nur dieser Weg liefert Marktwert und unrealisierten G/V), reqExecutions inkl. Zuordnung der verspaetet eintreffenden commissionReport-Callbacks ueber die ExecId. - BrokerPosition/BrokerExecution als Broker-Wahrheit neben Position; IbkrMapping: ParseSide, ParseExecutionTime, FormatExecutionFilterTime (UTC wegen TWS-Warnung 2174) - mit Unit-Tests. - Verifiziert gegen Paper-Konto DUR371528: 2 Positionen, 2 Ausfuehrungen inkl. Kommissionen. Doku: Kapital- und Buchmodell (drei Wahrheiten, Kapitalzuteilung), KONZEPT-Datenlage-und-Strategien (gemessen, was die API auf diesem Konto liefert). Options-Wheel: Greeks bei verzoegerten Daten funktionieren (Feld 83); Earnings-Termine sind ueber die TWS API nicht erreichbar (Fehler 10358) - Behelf ueber IV-Filter statt Fremddatenquelle. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
36 lines
1.5 KiB
C#
36 lines
1.5 KiB
C#
using IBKRTrader.Core.Logging;
|
||
|
||
namespace IBKRTrader.Core.Trading;
|
||
|
||
/// <summary>
|
||
/// Sicherer Standard-Broker: handelt NIEMALS.
|
||
/// Wird registriert, bis der echte IBKR-Adapter angebunden und gegen den
|
||
/// Paper-Gateway verifiziert ist. So kann keine Order versehentlich rausgehen.
|
||
/// </summary>
|
||
public sealed class NullBrokerClient : IBrokerClient, IBrokerPortfolioReader
|
||
{
|
||
private readonly LoggingService _logger;
|
||
|
||
public NullBrokerClient(LoggingService logger) => _logger = logger;
|
||
|
||
public Task<IReadOnlyList<BrokerPosition>> GetPositionsAsync(CancellationToken ct = default)
|
||
=> Task.FromResult<IReadOnlyList<BrokerPosition>>(Array.Empty<BrokerPosition>());
|
||
|
||
public Task<IReadOnlyList<BrokerExecution>> GetExecutionsAsync(DateTime? since = null, CancellationToken ct = default)
|
||
=> Task.FromResult<IReadOnlyList<BrokerExecution>>(Array.Empty<BrokerExecution>());
|
||
|
||
public Task<Quote?> GetQuoteAsync(string symbol, CancellationToken ct = default)
|
||
=> Task.FromResult<Quote?>(null);
|
||
|
||
public Task<AccountState> GetAccountStateAsync(CancellationToken ct = default)
|
||
=> Task.FromResult(new AccountState(0m, 0m));
|
||
|
||
public Task<OrderResult> PlaceOrderAsync(OrderRequest request, CancellationToken ct = default)
|
||
{
|
||
_logger.Warn("Core",
|
||
$"NullBrokerClient: Order NICHT ausgeführt ({request.Side} {request.Quantity}x {request.Symbol}) " +
|
||
"– echter IBKR-Broker noch nicht angebunden.");
|
||
return Task.FromResult(OrderResult.Fail("Broker nicht angebunden (NullBrokerClient)."));
|
||
}
|
||
}
|