0feeeba815185cc50fa840921a3f1d4cce432012
7
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0feeeba815 |
Optionskette und Bewertungsgroessen im Core
Der Core kennt jetzt die handelbaren Verfallstage und Strikes eines Basiswerts
(reqSecDefOptParams) und die Bewertungsgroessen eines Kontrakts
(tickOptionComputation). Damit steht der letzte Baustein, den eine
Wheel-Strategie braucht, um ueberhaupt einen Kontrakt auswaehlen zu koennen.
OptionChain ist bewusst nur eine Liste und trifft keine Marktentscheidung. Die
Auswahlhilfen daran sind reine Rechnung - "der Verfall bei etwa 35 Tagen" ist
eine Kalenderfrage, "welches Delta will ich" nicht. Letzteres gehoert ins Modul.
Zwei Eigenheiten der TWS-API sind beim Messen aufgefallen und haben je einen
Fehler gekostet:
1. Greeks kommen NICHT im Snapshot. reqMktData mit snapshot=true liefert Geld-,
Brief- und letzten Kurs, aber keine tickOptionComputation. Es braucht ein Abo,
das beim ersten Modell-Tick wieder abbestellt wird.
2. TWS meldet je Basiswert MEHRERE Serien. Fuer AAPL kamen "AAPL" und "2AAPL" -
letztere eine Sonderserie mit eigenen Ausuebungspreisen. Der erstbeste Satz
war die falsche: Strike 320 in "2AAPL" gibt es nicht, TWS antwortete mit 200
("No security definition has been found"). Die Auswahl nimmt jetzt SMART vor
allen anderen Boersen und darin die Handelsklasse, die dem Symbol entspricht.
Massgeblich ist ausserdem allein das Modell-Feld (13 bzw. 83 bei verzoegerten
Daten). Die Varianten zu Geld-, Brief- und letztem Kurs fehlen bei illiquiden
Serien und lieferten sonst ein Delta aus einem Kurs, den niemand stellt. Fehlende
Werte meldet TWS als double.MaxValue oder -1; sie werden zu null, nicht zu 0 -
ein Delta von 0 hiesse "reagiert nicht auf den Basiswert".
Gemessen gegen das Paper-Gateway:
AAPL (USD, SMART/AAPL, x100): 22 Verfallstage, 123 Strikes
Auswahl wie beim Wheel: AAPL|20261009|P|320 (Kurs 320.01, 34 Tage Laufzeit)
Deckungsbedarf je Kontrakt: 32.000,00 USD
IV 24.5 %, Delta -0.471, Gamma 0.0169, Vega 0.392, Theta -0.123 (verzoegert)
Der Schalter --option-chain SYMBOL [--currency X] faehrt genau diesen Ablauf und
bleibt als Pruefwerkzeug. 414 Tests gruen.
Behebt #299.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
40f7bb0d6e |
Bestandsabgleich gegen den Broker: Zuteilung, Verfall, Fremdbestand
Zuteilung und Verfall aendern Positionen ohne eine Order von uns - es gibt kein Ereignis, an das sich ein Abgleich haengen koennte. Nach einem Verfallstag fuehren wir Kontrakte, die es nicht mehr gibt; nach einer Zuteilung liegen Aktien im Konto, die in keinem Buch stehen. Beides verschiebt still die Deckungslage: Ein Covered Call, dessen Aktien in Wahrheit abgerufen wurden, ist ab dann ein nackter Call. PositionReconciler ist reine Rechnung und deutet die Differenz, statt nur Mengen anzugleichen. Verschwindet ein geschriebener Put und tauchen zugleich Aktien des Basiswerts auf, gehoeren diese Aktien dem Buch, das den Put geschrieben hat - landeten sie in UNASSIGNED, verloere ein Wheel-Modul genau den Bestand, aus dem es den naechsten Call schreiben muss. Der Einstand ist dabei der Strike, denn zu genau dem Preis wurde geliefert. Passt die Aktienbewegung nicht zur Groesse der Option, gilt sie NICHT als Zuteilung. Verfall wird nur angenommen, wenn der Verfallstag erreicht ist. Ein Kontrakt, der vorher verschwindet, ist eine Abweichung und wird als solche gemeldet - von Hand geschlossen ist kein Verfall. Die gefaehrlichste Stelle ist die leere Antwort: Die Leseschnittstelle liefert bei gestoerter Verbindung eine leere Liste, die von einem leeren Konto nicht zu unterscheiden ist. Solange wir selbst Positionen fuehren, gilt sie deshalb als Stoerung. Ohne diese Sperre setzte ein Verbindungsabbruch jede Position auf null. Gehandelt wird nie. Der Abgleich bucht ausschliesslich nach. BrokerPosition traegt jetzt das Instrument (IbkrMapping.ToInstrument); ein Kontrakt, den unser Modell nicht kennt - Future, Devise, Fonds -, liefert null und wird uebersprungen statt als Aktie gedeutet. Gemessen auf dem Testserver gegen das Paper-Konto: vier Altlasten erkannt (GOOG, MIGA:EUR, die SAP-ADR aus dem Fehllauf und zwei ungebuchte SAP:EUR), alle an UNASSIGNED gebucht, das Buch DIAG unangetastet. Gegenprobe danach: "Bestand stimmt ueberein (5 Positionen)". 402 Tests gruen. Erledigt den offenen Teil von #300, Kern von #306. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
9e0d3b229a |
Kursabfrage nimmt das Instrument statt nur das Symbol
Ohne Waehrung wird jeder Kontrakt als USD gesucht: ein Wert, der nur in EUR notiert, ist dann "nicht aufloesbar", und die Ursache steht nirgends. Beim Order-Nachweis gegen MIGA:EUR genau so aufgetreten - die Kontraktaufloesung fuer die ORDER war bereits waehrungsfaehig, die fuer den KURS nicht, und damit brach die Kette eine Stufe vorher ab. Dieselbe Aenderung ist die Voraussetzung fuer Optionskurse (#299): ohne Kontraktangaben laesst sich eine Option ueberhaupt nicht abfragen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
2a73172e27 |
Instrumente sind waehrungsfaehig
Die Waehrung gehoert zur Identitaet eines Instruments und nicht zu
seiner Beschreibung: derselbe Ticker kann an mehreren Plaetzen in
verschiedenen Waehrungen notieren, und ein Kauf darf nur aus Bargeld
derselben Waehrung finanziert werden (Kapitalmodell §4 Schicht C). Zwei
Notierungen als eine Position zu fuehren, wuerde Bestand und Deckung
vermischen.
USD bleibt im Instrumentenschluessel IMPLIZIT ("AAPL", nicht
"AAPL:USD"). Andernfalls waere jede Bestandszeile ab sofort ein anderes
Instrument als vorher und aus einer Position wuerden zwei. Trennzeichen
ist der Doppelpunkt und nicht der Punkt - Ticker enthalten Punkte
(BRK.B).
Neu: Currencies (kanonische Schreibweise an allen vier Stellen, die sie
gleich haben muessen), Currency an OptionSpec, InstrumentRef,
TradeSignal, OrderRequest und core_position. CapitalService nimmt die
Waehrung ab jetzt aus dem Instrument statt vom Aufrufer - wer sie
uebergeben koennte, koennte die Deckungspruefung gegen den falschen Topf
laufen lassen. --verify-order kennt --currency.
Anlass: das Paper-Konto haelt EUR 91.832 und USD -3.751. Ein
USD-Nachweis waere ein USD-Kredit gewesen und wurde von Schicht C
zu Recht abgelehnt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
084cd7ef77 |
Options-Fundament und Kapitalmodell im Core; Modul OptionsWheel
Das OptionsWheel setzt auf Dingen auf, die es im Core nicht gab. Diese Sitzung baut sie. #298 Optionen als Instrument. InstrumentKind/OptionSpec und ein druckbarer Instrumentenschluessel ("AAPL|20260918|C|150"); TradeSignal und OrderRequest tragen ein optionales OptionSpec, ohne das sich der Aktienpfad unveraendert verhaelt. Position.Notional rechnet ab jetzt mit der Kontraktgroesse - vorher war jede Option um Faktor 100 zu klein bewertet und damit jedes Risikolimit wirkungslos, lautlos und in die gefaehrliche Richtung. Daneben neu BoundCapital: ein Short Put bindet Strike x Kontraktgroesse, nicht die vereinnahmte Praemie. #300 sell-to-open. Jeder Auftrag zerfaellt in einen schliessenden und einen eroeffnenden Teil; der schliessende wird von keinem Limit verhindert - auch nicht vom Kaufstopp, denn ein Rueckkauf baut eine Verpflichtung ab. Deckungspruefung im Core, nicht im Modul: Short Call nur mit freien Aktien, Short Put nur mit reservierbarem Bargeld. #302-#305 Kapital- und Buchmodell. Buecher mit reservierten Namen und Eigentumsregeln, Pool mit Caps und Headroom, Margin-Sperre in vier Schichten, core_reservation mit Lebenszyklus, Frist, Idempotenz ueber (SignalId, ContractKey) und Quarantaene beim Start. #309/#310 Modul OptionsWheel: ow_-Schema mit fuenf Tabellen, Zustandsautomat, StrikeSelector, RollDecider, PremiumMath - vollstaendig ohne Broker testbar. Der Handelsbetrieb bleibt gesperrt, solange #299 und #294 fehlen; das Modul sagt das ueber GetActivationBlocker, statt still nichts zu tun. #293 --verify-order am Daemon: eine Order durch die vollstaendige Kette (Buch, Risiko, Bindung, Order, Fill, Buchung, Abschluss). Ohne --confirm ein Trockenlauf; Abbruch ausserhalb von Paper-Modus UND Paper-Port. Drei Widersprueche in den Konzepten sind dabei entschieden worden: Schicht B heisst ab jetzt "kein UNGEDECKTER Short" (der Grund der Regel war der Kredit, nicht der Short), die Hausreserve wird einmal abgezogen statt zweimal, und der Positionsschluessel ist eine Spalte statt eines Sechser-Verbunds (MySQL verlangt NOT NULL fuer Schluesselspalten). Begruendungen stehen in docs/ROADMAP.md. Enthaelt ausserdem die noch nicht committete Arbeit aus der vorigen Sitzung: die Fehlerbehebungen aus Epic X (WorkerBase-Intervall, BackupWorker, --check gegen die Datenbank, CapitolTrades-429, SIGTERM) samt DatabaseEndpoint, MysqlDumpTool und der Roadmap-Umstellung. Sie lag im Arbeitsbaum und liess sich nicht abtrennen, weil beide Staende dieselben Dateien beruehren. 213 -> 369 Tests, Build ohne Warnung. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
0a72ea7e28 |
Deploymentcenter-Integration (Schritte 0-8 des Konzepts)
Bindet Lizenz, Watchdog, Fehler-Stream, UpdateService und Erstinstallation an
das Deploymentcenter 2.5.1 an. Einbauort ist IBKRTrader.Hosting - den Host
teilen sich Shell und Daemon.
Projekt-Befunde aus dem Konzept vorab bereinigt:
P1 Echte DB-Zugangsdaten als Vorgabewerte in AppSettings -> Platzhalter.
Das alte Passwort steht weiterhin in der Git-Historie und ist als
kompromittiert zu behandeln (Rotation ist Nutzer-Aktion).
P2 AppPaths fiel unter Windows auf /etc/ibkrtrader zurueck, was .NET zu
C:\etc\ibkrtrader aufloest. Jetzt %ProgramData%\IBKRTrader.
P3 Globale Ausnahmebehandler (AppDomain / TaskScheduler) - vorher gab es
keinen Logeintrag, wenn der Prozess unbehandelt wegbrach.
P4 Version einmal zentral in Directory.Build.props statt zweimal hartkodiert.
Bewusste Abweichungen vom DC-Leitfaden, beide fuer ein handelndes System:
- Lizenz-Urteil fuehrt zum Sperrbetrieb (TradingEnabled=false) statt zu
Environment.Exit(1). Keine neuen Einstiege, aber Risiko-, Exit- und
Buchhaltungslogik laufen weiter.
- exitCurrentApp bleibt immer false; der Aufrufer beendet geordnet.
Das SDK haengt als Cross-Repo-ProjectReference am Schwester-Repo
Deploymentcenter (Interim, siehe Konzept 2.2). Damit ist P5 offen: die
Gitea-CI checkt das Schwester-Repo nicht aus und wird rot, bis der Bezug auf
ein NuGet-Paket umgestellt ist.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
9c7e19149c |
L2: Kopfloser Linux-Dienst - der Trading-Kern laeuft ohne Oberflaeche
Meilenstein: Trading, Worker, Accounting, Supervisor, REST und MCP laufen
als systemd-Dienst auf Linux. Nur noch IBKRTrader.App ist Windows-gebunden.
Neu IBKRTrader.Hosting: die komplette Host-Zusammenstellung, aus der
WinForms-Program.cs herausgezogen. Bewusst ein eigenes Projekt - laege sie
weiter in der Shell, muesste sie fuer den Daemon dupliziert werden, und
beide wuerden auseinanderlaufen. Ein Modul, das nur in einer Variante
registriert ist, faellt sonst erst im Betrieb auf. RunStartupChecks buendelt
die Startschritte in fester Reihenfolge (Zeitzone vor dem ersten Logeintrag,
Master-Key vor jeder Entschluesselung).
Neu IBKRTrader.Daemon: kopfloser Einstiegspunkt mit SIGTERM-Behandlung,
--check (Trockenlauf: Host bauen, Startpruefungen, keine Boersenverbindung -
fuer Deployment und CI) und --db-version.
AppPaths: Logs, Backups, settings.json und master.key lagen neben der
Binaerdatei. Unter /opt hat der Dienstbenutzer dort keinen Schreibzugriff -
der Dienst waere beim ersten Logeintrag gescheitert. Aufloesung jetzt:
Umgebungsvariable, sonst Binaerverzeichnis WENN beschreibbar (haelt Windows
und die Entwicklung unveraendert), sonst FHS. Der Schreibtest ist ein echter
Schreibversuch - Attributpruefung traegt nicht, weil unter Linux
Besitzer/Gruppe/Modus und unter Windows die ACL entscheiden.
Rechtepruefung fuer master.key/openrouter.key auf Unix: Windows-ACLs
uebertragen sich beim Kopieren auf einen Linux-Host nicht, eine key-Datei mit
644 waere dort fuer jeden lokalen Nutzer lesbar. Nur eine Warnung.
InvariantGlobalization ausdruecklich auf false. Der naheliegende Griff zum
schlanken Image waere hier ein Eigentor gewesen und haette genau die zwei
Punkte aus L1b lautlos rueckgaengig gemacht: ohne ICU faellt die Aufloesung
von Windows-Zeitzonen-IDs aus (Rueckfall auf UTC im Container) und
CultureInfo.GetCultureInfo("de-DE") liefert die invariante Kultur, womit die
PDF-Betraege wieder das Format wechseln.
systemd: Unit mit Type=notify plus UseSystemd() im Host - ohne sd_notify
haette systemctl start bis zum Timeout gehangen. Unit mit Absicherung
(ProtectSystem=strict, ReadWritePaths), deploy/README.md mit Voraussetzungen,
Verzeichnissen, Zeitzonen-Festlegung und dem, was der Daemon NICHT loest
(IB Gateway headless bleibt eine eigene Baustelle).
Verifiziert: 193 Tests gruen (+5), Build 0 Fehler/0 Warnungen, --smoke-ui
konstruiert alle 7 Fenster, --check laeuft durch, und publish -r linux-x64
liefert 11 MB mit ELF-Launcher, ohne eine einzige Windows-Abhaengigkeit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|