Handelszeiten im Core: DebugTrading handelt nicht mehr in die geschlossene Boerse
Das Modul erzeugte ueber das Wochenende Dutzende wartender Orders - alle 15
Minuten eine, alle von IBKR angenommen und fuer Montag 09:00 vorgemerkt, alle
gleichzeitig ausloesend. Am 2026-09-06 waren es 31.
Die Auskunft gehoert in den Core, nicht ins Modul: Handelszeiten braucht jede
Strategie, und sie ist nichts, was ein Modul selbst wissen kann.
- MarketHours.cs: MarketSession, MarketSchedule (IsOpen, NextOpenUtc), der
Parser TradingHours und der Seam IMarketCalendar. Reine Rechnung, damit die
Formate ohne Broker pruefbar sind - 20 Tests ueber beide Schreibweisen der
TWS-API, Feiertage, Zeitraeume ueber Mitternacht und unbekannte Zonen.
- Die Zeiten kommen aus derselben Kontraktabfrage, die der Adapter ohnehin
macht: contractDetails liefert sie mit, eine eigene Runde waere Verschwendung.
- LiquidHours und nicht TradingHours. Letzteres enthaelt bei US-Werten die vor-
und nachboersliche Zeit; unsere Orders setzen OutsideRth nicht, wuerden dort
also gar nicht ausgefuehrt, sondern warten - genau der Zustand, den das hier
verhindern soll.
- Keine Ersatzzeitzone, wenn TWS eine unbekannte meldet. Mit der falschen Zone
gerechnete Handelszeiten saehen richtig aus und laegen um Stunden daneben.
- Unbekannt gilt als geschlossen. Wer aus fehlender Auskunft auf einen offenen
Markt schloesse, handelte bei jeder Stoerung ins Geschlossene.
DebugTrading.OnlyDuringMarketHours, Vorgabe an. Die Pruefung gilt fuer beide
Richtungen: Auch eine Schliessung erzeugte dieselbe wartende Order. Eine
Testposition ein paar Stunden laenger zu halten kostet dagegen nichts - und die
nicht geschlossene Position belegt ihren Platz weiter, sonst eroeffnete die
Planung ueber die eigene Grenze hinaus.
Auf der Testmaschine am Sonntagabend nachgewiesen:
[20:31:28] Kein Instrument handelbar, naechste Eroeffnung SAP:EUR um
2026-09-07 07:00 UTC.
07:00 UTC ist 09:00 MEZ - dieselbe Zeit, die IBKR heute frueh im Warntext 399
genannt hat. Zwei unabhaengige Quellen, gleiche Antwort. Seither keine neue
Order; der Lauf dauert zwei statt neunzig Sekunden.
524 Tests gruen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,8 @@ namespace IBKRTrader.Core.Trading.Ibkr;
|
||||
/// die sichere Richtung, wenn der Broker nicht erreichbar ist.
|
||||
/// </summary>
|
||||
public sealed class IbkrBrokerClient
|
||||
: IBrokerClient, IBrokerPortfolioReader, IBrokerOrderBook, IOptionMarketData, IQuoteSource, IDisposable
|
||||
: IBrokerClient, IBrokerPortfolioReader, IBrokerOrderBook, IOptionMarketData, IQuoteSource,
|
||||
IMarketCalendar, IDisposable
|
||||
{
|
||||
private const string LogModule = "IBKR";
|
||||
|
||||
@@ -112,6 +113,13 @@ public sealed class IbkrBrokerClient
|
||||
return await _connection!.RequestExecutionsAsync(since, _requestTimeout, ct).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<MarketSchedule?> GetScheduleAsync(InstrumentRef instrument, CancellationToken ct = default)
|
||||
{
|
||||
if (!await IsReadyAsync(ct).ConfigureAwait(false)) return null;
|
||||
|
||||
return await _connection!.RequestMarketScheduleAsync(instrument, _requestTimeout, ct).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<BrokerOrder>> GetOpenOrdersAsync(CancellationToken ct = default)
|
||||
{
|
||||
if (!await IsReadyAsync(ct).ConfigureAwait(false)) return Array.Empty<BrokerOrder>();
|
||||
|
||||
Reference in New Issue
Block a user