Der offene Stand lag ueber sieben Konzepte, zwei Referenzdokumente und die
Phasen-Checkliste der Architektur verteilt. Dieselbe Aufgabe stand teils
doppelt unter zwei Namen - die asynchrone Fill-Verfolgung etwa als "bekannte
Grenze" in IBKR-Integration.md und zugleich als W-2 im OptionsWheel-Konzept.
Wer wissen wollte, was als Naechstes ansteht, musste alles neun lesen.
docs/ROADMAP.md fuehrt das zusammen:
- Fuenf Stufen in Abhaengigkeitsreihenfolge, von "Fundament schliessen" bis
zum OptionsWheel, dazu vier laufende Bahnen (Auslieferung, Accounting,
Supervisor, technische Schulden).
- Jede Zeile traegt ihre Herkunft (W-2, P5, Kapitalmodell 5, ...), damit die
Herleitung im Archiv auffindbar bleibt.
- Eigene Abschnitte fuer Zurueckgestelltes und Verworfenes. Zurueckgestellte
Ideen nennen ausdruecklich, WAS sie wieder aktuell macht; verworfene nennen
den Grund, damit sie nicht in sechs Monaten erneut vorgeschlagen werden.
- Erledigtes bleibt als Zeile mit Datum stehen statt zu verschwinden.
Archiv (git erkennt alle sieben als Umbenennung, Historie bleibt):
docs/konzepte/* -> docs/archiv/
docs/Kapital-und-Buchmodell.md -> docs/archiv/
Jedes archivierte Dokument bekommt oben einen Vermerk, warum es erhalten bleibt
und wo der lebende Stand steht. Inhaltlich ist keines veraendert.
Weiter gepflegt werden ARCHITECTURE.md (Aufbau + Phasen-Historie),
IBKR-Integration.md (Adapter-Design und Grenzen) und die TWS-Setup-Checkliste -
das sind Referenzen, keine Planung. Ihre eigenen Offen-Listen verweisen jetzt
mit Roadmap-Kennung dorthin, statt einen zweiten Stand zu fuehren.
Alle 63 relativen Markdown-Links geprueft, keiner tot. Fuenf Pfadverweise in
Code, csproj und systemd-Unit mitgezogen; die Unit zeigte auf die
Portierungsanalyse, die ausdruecklich den Stand VOR dem Umbau beschreibt - jetzt
auf ARCHITECTURE.md. Build 0 Warnungen, 198/198 Tests gruen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
16 KiB
📦 Archiviert am 2026-08-23
Dieses Dokument wird nicht mehr gepflegt. Was davon noch offen ist, steht in der Roadmap (Stufe 5, dazu die Core-Voraussetzungen in Stufe 3) – dort und nur dort wird der Stand nachgeführt.
Es bleibt erhalten, weil es den Zustandsautomaten, das Regelwerk mit allen Vorgabewerten und die Begruendung enthaelt, warum das Modul nicht additiv auf den heutigen aktienbasierten Core passt. Zum Nachschlagen also weiterhin richtig, als Aufgabenliste nicht mehr.
Konzept: Modul „OptionsWheel" (Covered Call / Cash-Secured Put)
Stand: 2026-08-03 Ziel: Auf einer kleinen Watchlist von Tickern, an deren langfristigen Erfolg wir glauben, systematisch Optionsprämien vereinnahmen – Cash-Secured Put → (Zuteilung) → Aktienbestand → Covered Call → (Abruf) → wieder Cash. Vollautomatisch, delta-basierte Strike-Wahl, aktives Rollen.
Festlegungen (2026-08-03, mit dem Betreiber abgestimmt):
- Put-Seite ist Cash-Secured Put, nicht Covered Put (kein Leerverkauf der Aktie).
- Vollautomatisch von Anfang an – Sicherungen sind Schalter und Limits, keine Klick-Freigabe.
- Strike-Wahl delta-basiert (Zielband 0,15–0,30).
- Bei drohender Zuteilung wird gerollt, solange das per Netto-Kredit möglich ist.
0. Leitprinzipien
- Niemals nackt. Ein Short Call ist nur zulässig mit 100 freien Aktien je Kontrakt, ein Short Put
nur mit reserviertem Cash über Strike × 100 je Kontrakt. Diese Deckungsprüfung gehört in den
Core-
RiskService, nicht ins Modul – ein Modulfehler darf keine ungedeckte Option schreiben können. - Der Broker ist die Wahrheit. Zuteilung und Verfall ändern Positionen ohne eine Order von uns. Ohne regelmäßigen Positionsabgleich gegen IBKR läuft die eigene Buchführung zwangsläufig auseinander.
- Nur Watchlist. Das Modul handelt ausschließlich explizit eingetragene Ticker. Keine Entdeckung, kein Screening, keine Ausweitung zur Laufzeit.
- Jede Entscheidung ist nachlesbar. Kandidatenbewertung, Zustandsübergang und Order gehen über
core_decision_journal/core_order_eventsmit gemeinsamerSignalId– dieselbe Forensik-Grundlage, die der Supervisor bereits nutzt.
1. Warum das nicht additiv geht: der Core ist heute aktienbasiert
| Stelle | Heutiger Stand | Konsequenz |
|---|---|---|
IbkrMapping.Stock() |
„der einzige Instrumententyp, den die Module handeln" | Kein Options-Kontrakt (Expiry/Strike/Right/Multiplier) baubar |
TradeSignal / OrderRequest |
nur Symbol + Side + Quantity |
Ein Signal kann keine Option benennen |
Position.Notional |
Quantity × AvgPrice |
Bei Optionen um Faktor 100 falsch → Risikolimits wirkungslos |
RiskService.EvaluateSell |
„Verkauf schließt Position", lehnt ohne Bestand ab | Sell-to-open wird grundsätzlich abgelehnt – die Kernoperation des Moduls |
IBrokerClient.PlaceOrderAsync |
Fill-oder-Fehlschlag innerhalb OrderTimeoutSeconds |
Limitorder am Mid liegt im Buch → gilt als Fehlschlag, ist aber aktiv (bekannte Grenze, IBKR-Integration.md) |
IBrokerClient |
kein reqPositions, keine Optionskette, keine Greeks |
Zuteilung/Verfall unsichtbar, Strike-Wahl unmöglich |
Das Modul setzt also auf einem Core-Options-Fundament auf, das zuerst gebaut wird. Der Aktienpfad
bleibt dabei unverändert (neue Felder sind optional, Kind = Stock ist der Default) – CongressTrading
darf nicht regressieren.
2. Core-Erweiterungen
2.1 Instrumententyp
public enum InstrumentKind { Stock, Option }
public enum OptionRight { Call, Put }
public sealed record OptionSpec(
string Underlying,
DateOnly Expiry,
decimal Strike,
OptionRight Right,
int Multiplier = 100);
TradeSignal und OrderRequest bekommen je ein optionales OptionSpec? Option. Ist es null,
verhält sich alles exakt wie heute.
2.2 Positionen mit Instrument-Identität
core_position erhält Kind, Expiry, Strike, Right, Multiplier; der fachliche Schlüssel wird
(Module, Symbol, Kind, Expiry, Strike, Right). Bestandszeilen sind Kind = Stock mit leeren
Optionsfeldern – Migration ohne Datenumzug. Notional rechnet ab jetzt mit dem Multiplikator.
IPortfolioService bekommt entsprechend überladene Abfragen; die bestehenden Aktien-Signaturen bleiben.
2.3 Optionskette + Greeks
Neuer Seam am IBrokerClient:
Task<OptionChain?> GetOptionChainAsync(string underlying, DateOnly from, DateOnly to, CancellationToken ct);
Task<OptionQuote?> GetOptionQuoteAsync(OptionSpec spec, CancellationToken ct); // + Delta, IV, OpenInterest
Task<IReadOnlyList<BrokerPosition>> GetPositionsAsync(CancellationToken ct);
Umsetzung in IbkrConnection:
- Kette über
reqSecDefOptParams– liefert Expiries und Strikes je Underlying ohne Marktdaten und ohne Abo. Das ist der einzige gangbare Einstieg: eine volle Kette hat hunderte Kontrakte, TWS erlaubt aber nur ~100 gleichzeitige Marktdatenzeilen. - Vorfilter, dann Quotes: Expiry-Fenster aus dem DTE-Ziel, Strike-Fenster um den Spot (± x %) –
erst für diese Handvoll Kontrakte
reqMktDatamit Greeks (tickOptionComputation). IbkrMapping.Option(spec)→SecType="OPT",Exchange="SMART",LastTradeDateOrContractMonthalsyyyyMMdd,Strike,Right="C"/"P",Multiplier="100", plusTradingClass(nötig, sobald ein Underlying mehrere Klassen führt, z. B. nach Splits oder bei Mini-Optionen). Rein, unit-getestet – wie das bestehendeIbkrMapping.
2.4 Asynchrone Order- und Fill-Verfolgung
Das ist der teuerste, aber unumgängliche Teil: eine Optionsorder wird limitiert am Mid platziert und füllt oft erst Minuten später oder gar nicht.
- Neue Tabelle
core_order_state: Order-ID,SignalId, Kontrakt, Menge, Limit, Status, gefüllte Menge, Zeitstempel – überlebt einen App-Neustart. IBrokerClient.SubmitOrderAsync(...)gibt die Order-ID ohne Warten zurück;PlaceOrderAsyncbleibt für den Aktienpfad erhalten (intern: submit + warten).- Dauerabo auf
orderStatus/openOrder/execDetailsstatt Slot-je-Order; einOrderTrackingService(IHostedService) trägt Endstatus nach, ruft dannRecordFillAsyncund schreibtcore_order_events. Nicht gefüllte Orders werden nach einer Frist neu bepreist oder storniert. - Nebennutzen: löst die in IBKR-Integration.md dokumentierte Grenze auch für CongressTrading.
2.5 Positionsabgleich (Zuteilung & Verfall)
ReconcilePositionsWorker (IHostedService, z. B. stündlich und nach Marktschluss) vergleicht
reqPositions mit core_position:
- Aktien tauchen auf / Short Put verschwindet → Zuteilung.
- Short Call verschwindet, Aktien weg → Abruf (called away).
- Option verschwindet am Verfallstag ohne Gegenbuchung → wertlos verfallen.
Jede Abweichung wird gebucht und ins Entscheidungsjournal geschrieben. Unerklärbare Differenzen
(manueller Eingriff in TWS) setzen den betroffenen Ticker auf
Halted.
2.6 Risiko: sell-to-open + Deckung
RiskContext bekommt FreeShares (nicht bereits durch andere Short Calls gebunden) und
AvailableCashForReservation. Neue Regeln im RiskService:
| Fall | Regel |
|---|---|
| Sell-to-open Call | FreeShares ≥ 100 × Kontrakte, sonst Ablehnung „ungedeckt" |
| Sell-to-open Put | AvailableCashForReservation ≥ Strike × 100 × Kontrakte, sonst Ablehnung |
| Buy-to-close | zulässig bis zur offenen Short-Menge |
| Limits | MaxTradePercent / MaxPositionPercentPerModule rechnen mit dem Multiplikator |
3. Modul IBKRTrader.Modules.OptionsWheel
IModule mit Name = "OptionsWheel", DbPrefix = "ow_", referenziert nur den Core, eigener DbContext,
eigenes Fenster, eigene Settings-Sektion – analog Accounting/CongressTrading.
3.1 Zustandsautomat je Ticker
Idle ──sell put──► ShortPut ──ITM/DTE──► Rolling ──► ShortPut
▲ │ │
│ │ Zuteilung └─ kein Netto-Kredit ─► (Zuteilung zulassen)
│ ▼
└── called away ── Stock ──sell call──► ShortCall ──ITM/DTE──► Rolling ──► ShortCall
▲ │
└─ verfallen ─────────┘
Zusätzlich PendingOrder (Order im Buch) und Halted (Sperre nach Fehler/Abweichung, nur manuell lösbar).
Der Automat ist rein und unit-getestet – er kennt weder Broker noch Datenbank.
3.2 Persistenz (ow_)
| Tabelle | Inhalt |
|---|---|
ow_underlyings |
Watchlist: Ticker, aktiv, Parameter-Überschreibungen, aktueller Zustand |
ow_cycles |
Ein Wheel-Durchlauf (Start, Ende, vereinnahmte Prämie brutto/netto, Ergebnis, Aktien-Einstand) |
ow_legs |
Jede verkaufte/geschlossene Option: Kontrakt, Prämie, Delta+IV bei Eröffnung, DTE, Status, Roll-Kette |
ow_candidates |
Bewertete Strike-Kandidaten je Scan (auch die verworfenen, mit Grund) – Nachvollziehbarkeit |
ow_events |
Zustandsübergänge mit Auslöser |
ow_candidates ist bewusst dabei: bei Vollautomatik ist die nicht getroffene Wahl die wichtigste
Information für die spätere Fehlersuche und für den Supervisor.
3.3 Reine Logik (Logic/, vollständig unit-getestet)
StrikeSelector– filtert die Kette: DTE-Fenster, Delta-Zielband, Mindestprämie (absolut und als annualisierte Rendite), maximaler Bid/Ask-Spread, Mindest-Open-Interest. Bewertet die Verbleibenden und begründet jede Verwerfung.RollDecider– rollen ja/nein: Trigger, Zielkontrakt, Netto-Kredit-Bedingung.CoverageCalculator– welche Aktien/welches Cash sind frei, welche durch offene Shorts gebunden.PremiumMath– annualisierte Rendite, Break-even, effektiver Einstand nach Prämien.WheelStateMachine– zulässige Übergänge, Ableitung des Zustands aus Positionen.
3.4 Worker
WheelScanWorker– im Handelszeitfenster: Zustand je Ticker prüfen, ggf. neues Leg eröffnen.WheelManageWorker– offene Legs überwachen: rollen, schließen, Orders nachbepreisen.
3.5 UI (ein Fenster, Tabs)
Übersicht (je Ticker: Zustand, offenes Leg, DTE, aktuelles Delta, Prämie vereinnahmt/annualisiert), Watchlist (Ticker + Parameter, Not-Aus je Ticker), Kandidaten (letzter Scan inkl. Verwerfungsgründe), Zyklen/Historie, Log. DB-Zugriff nur auf Interaktion (Smoke-UI-sicher).
4. Regelwerk (Defaults, je Ticker überschreibbar)
| Parameter | Default | Begründung |
|---|---|---|
| DTE beim Öffnen | 30–45 | Bestes Verhältnis Zeitwertverfall/Handelskosten |
| Ziel-Delta | 0,20 (Band 0,15–0,30) | ≈ 20 % Zuteilungswahrscheinlichkeit |
| Roll-Trigger | DTE ≤ 21 und (Delta > 0,50 oder ITM) | Gamma-Risiko steigt in der letzten Woche stark |
| Roll-Bedingung | nur bei Netto-Kredit | Ein Debit-Roll kauft nur Zeit und kostet Geld |
| Covered-Call-Strike | ≥ effektiver Einstand der Aktien | Verhindert, dass der Wheel systematisch Verluste realisiert |
| Max. Kontrakte je Ticker | 1 | Bewusst klein starten |
| Max. gebundenes Cash gesamt | Anteil des Kontowerts | Zweite Grenze über die Core-Limits hinaus |
| Vorzeitiges Schließen bei Gewinnziel | aus | Nicht gewählt – siehe Hinweis unten |
Hinweis zum Gewinnziel: Der übliche Begleiter der Roll-Politik ist, ein Leg bei ~50 % vereinnahmter Prämie zurückzukaufen; das nimmt Gamma-Risiko aus der letzten Woche und ist der Grund, warum viele Roll-Trigger nie greifen. Der Parameter ist vorgesehen (
ProfitTargetPercentexistiert bereits inTradingSettings), steht per Vorgabe auf „aus" und lässt sich ohne Codeänderung zuschalten.
Zuteilung ist nicht abwählbar. Auch bei konsequentem Rollen teilt IBKR zu – amerikanische Optionen können jederzeit ausgeübt werden, beim Call besonders vor dem Ex-Dividenden-Tag, und ein Roll ist nicht immer per Netto-Kredit möglich. Zuteilung ist deshalb ein regulärer Pfad des Automaten, kein Fehler. Genau dafür ist der Positionsabgleich (2.5) Pflicht.
5. Sicherungen
Zu den bestehenden zwei Schaltern (IBKR.UseTwsApi, Trading.TradingEnabled) kommen:
OptionsWheel.Enabled– Modulschalter.- Watchlist als Whitelist – kein Ticker außerhalb.
- Naked-Sperre im Core-
RiskService(2.6) – wirkt auch, wenn die Modullogik falsch liegt. Haltedje Ticker bei unerklärter Positionsabweichung; Neueröffnungen stoppen, bestehende Legs werden weiter verwaltet.- Kill-Switch „keine Neueröffnungen" – laufende Positionen bleiben handhabbar.
6. Phasen
| Phase | Inhalt | Abschlusskriterium |
|---|---|---|
| W-0 | Core: InstrumentKind/OptionSpec, IbkrMapping.Option, Positionen mit Multiplikator |
Build + Tests grün, Aktienpfad unverändert |
| W-1 | Core: Optionskette + Greeks (reqSecDefOptParams, tickOptionComputation) |
Kette eines Watchlist-Tickers gegen das Paper-Gateway abrufbar |
| W-2 | Core: asynchrone Order-/Fill-Verfolgung (core_order_state, OrderTrackingService) |
Limitorder überlebt Timeout und App-Neustart, Fill wird nachgebucht |
| W-3 | Core: Positionsabgleich + RiskService sell-to-open/Deckung |
Zuteilung im Paper erkannt und gebucht; ungedeckte Order wird abgelehnt |
| W-4 | Modul-Gerüst: IModule, ow_-DbContext + Migration, UI-Tabs, Watchlist |
App startet, --smoke-ui grün, kein Handel |
| W-5 | Reine Strategie-Logik + Tests (StrikeSelector, StateMachine, RollDecider, PremiumMath) | Hohe Testabdeckung ohne Broker |
| W-6 | Verdrahtung + vollautomatischer Paper-Betrieb, Beobachtung über mehrere Verfallszyklen | Mindestens ein vollständiger Wheel-Durchlauf im Paper |
| W-7 | Live-Freigabe | Eigene Entscheidung nach W-6 |
W-0 bis W-3 sind Core-Arbeit und nützen auch den anderen Modulen; erst ab W-4 entsteht das Modul selbst.
7. Bewusst offen / zu klären
Optionsberechtigung im Paper-Konto DUR371528 prüfen→ erledigt am 2026-08-04, vorhanden. Verifiziert gegen das laufende Gateway (Details siehe IBKR-Integration.md, Abschnitt „Optionen"):reqSecDefOptParamsfür AAPL liefert 24 Verfallstermine, 127 Strikes, Multiplier 100 über SMART; eine What-If-Order aufAAPL 20260812 C302.5wurde von IBKR angenommen (Init-Margin 589,52) statt mit einem Berechtigungsfehler abgelehnt. Damit ist die Grundvoraussetzung für dieses Modul gegeben.Greeks bei verzögerten Daten.→ erledigt am 2026-08-04, funktioniert. Gemessen anAAPL 20260821 C305: IV 0,2730 / Delta 0,5443 / Gamma 0,0220 / Vega 0,2626 / Theta −0,2304. Die Werte kommen über die verzögerten Tick-Felder 80–83; Feld 83 (Modell) ist die für die Strike-Wahl maßgebliche Variante. Die delta-basierte Wahl im Band 0,15–0,30 ist damit umsetzbar, die Ersatzlösung über prozentualen Abstand wird nicht gebraucht (derStrikeSelectorbehält sie trotzdem als Rückfalllinie). Details: KONZEPT-Datenlage-und-Strategien.md.- Marktdatenabo (OPRA) für Realtime-Optionskurse – Kosten/Notwendigkeit später entscheiden.
- Earnings-Sperre: keine neuen Legs über Quartalszahlen hinweg. Geprüft am 2026-08-04: über
die TWS API nicht lösbar –
CalendarReportund alle übrigen Fundamentaldaten sind auf dem Konto gesperrt (Fehler 10358, Refinitiv-Abo nötig). Das ist die einzige Stelle, an der uns eine externe Quelle ernsthaft fehlt. Behelf ohne Fremddaten: ein IV-Filter – keine neuen Legs, wenn die implizite Volatilität des Basiswerts deutlich über ihrem 30-Tage-Mittel liegt. Fängt den Earnings-Anstieg indirekt mit ab, unschärfer, aber ohne Abhängigkeit. - Accounting-Anschluss: Optionsprämien, Zuteilungen und Abrufe müssen im
AccountingClassifiereigene Buchungskategorien bekommen; derRealizedPnlEngine(FIFO) kennt weder Multiplikator noch die Einstandsverschiebung durch Zuteilung. Eigene Arbeit im Accounting-Modul. - Steuer bleibt wie im Accounting-Konzept unberührt und offen. Keine Steuerberatung.