- abendkontrolle.py: --quelle und --quelle-ibkr (Vorgabe wsl wie bisher, dockerhost liest das Ergebnis des Hosts ueber SSH), fahre_dockerhost - abendkontrolle_wsl.py: --ibkr-python fuer ibkr_pruefen.py im Container - abendkontrolle_einrichten.ps1: -Quelle und -QuelleIbkr, 23:15 sobald ein Teil vom Host kommt - neue Angriffstreiber abendkontrolle_dockerhost_angriffe.py und abendkontrolle_ibkr_python_angriffe.py - Abdichtung gegen echte WSL- und SSH-Wege in den Treibern, auch in abendkontrolle_angriffe.py und rueckweg_aapl_angriffe.py (nach dem ntfy-Vorfall eines Mutanten am 2026-09-26) - LIESMICH: Abschnitt Paket DH - .claude/workflows/plankritik.js: LF statt CRLF (das CR war die Ursache von "script contains control characters"), meta gekuerzt, Einzelheiten im Kommentar Co-Authored-By: Claude Opus 5.5 <[email protected]>
182 lines
46 KiB
Markdown
182 lines
46 KiB
Markdown
---
|
|
type: resource
|
|
status: active
|
|
title: "Trading Plattform: Prüfwerkzeuge des Koordinators fürs Dashboard"
|
|
summary: "Eigener Lauf mit echten Daten zum Dashboard der Trading Plattform — Vergleich der Endpunkte gegen Vollparse und pandas, zwei WebSocket-Verbindungen, Browser-Lauf und Wiederaufbau mit Playwright, gefahrlose Proben der zwei Skripte, Mutantenläufe. Entstanden 2026-09-17 (Teil 3b), erweitert 2026-09-18 (Teil 10: Anmeldung, Angriffsfälle, Beobachtung, Kerzenlatenz), bewusst nicht im Projekt-Repo."
|
|
tags: [vault-tools, trading-plattform]
|
|
created: 2026-09-17
|
|
updated: 2026-09-24
|
|
---
|
|
|
|
# Prüfwerkzeuge fürs Dashboard der Trading Plattform
|
|
|
|
Koordinator-Werkzeuge, nicht fürs Repo. Sie starten **nie** den echten Broker: Das Probe-Backend läuft mit `BrokerAttrappe` und einem Wegwerf-Register unter `/tmp`, liest aber die echten Protokolle und den echten Katalog. Python-Teile laufen in WSL aus dem Projektordner, die Browser-Teile mit dem Windows-Python und Playwright (Chromium).
|
|
|
|
| Datei | Was sie tut | Aufruf |
|
|
|---|---|---|
|
|
| `pruef_teil3b.py` | Liste und Einzelansicht der Läufe gegen einen eigenen Vollparse, Kerzen gegen eine eigene pandas-Rechnung; `--sabotage` verfälscht je einen Wert und muss mit Exit 2 enden (sieben Fälle) | `wsl -d Debian -- bash -s -- pruef_teil3b.py alles [--sabotage zahl] < lauf_pruef.sh` |
|
|
| `pruef_ws.py`, `lauf_ws_probe.sh`, `start_probe_backend.py`, `start_probe.sh` | zwei WebSocket-Verbindungen am Probe-Backend müssen dieselben `zeit`-Werte sehen | `wsl -d Debian -- bash -s < lauf_ws_probe.sh` |
|
|
| `browserlauf.py` | bei 375, 768, 1024 und 1440 px: Zeilen in „Läufe", zwei Einzelansichten, Minuten- und Tageschart gezeichnet, kein waagerechter Scroll, keine Konsolenmeldung; schreibt Screenshots — **ansehen** | Probe-Backend starten (`wsl -d Debian -- bash -s 8145 2.0 < start_probe.sh`, im Hintergrund), dann `python -X utf8 browserlauf.py http://localhost:8145 <ausgabeordner>` |
|
|
| `wiederaufbau.py` | Backend beenden und neu starten, die Kopfzeile muss „Backend getrennt" und wieder „Backend verbunden" zeigen, ohne Neuladen; `--ohne-neustart` muss rot enden | `python -X utf8 wiederaufbau.py` |
|
|
| `skripte_probe.sh`, `abkuerzung_probe.sh` | `--help`, Lauf ohne Schalter, unbekanntes Argument und Abkürzungen von `--ausfuehren` — **ausschließlich aus einem leeren Temp-Verzeichnis**; die Übung selbst wird nie gefahren | `wsl -d Debian -- bash -s < skripte_probe.sh` |
|
|
| `mutanten_py.py`, `mutanten_ts.py` | Mutanten zu Teil 3b auf einer Kopie mit angewendetem Plan, je mit Fehlerzeile | Pfad der Kopie als erstes Argument |
|
|
| `real_pytest.sh` | volle Suite im echten Baum, mit Zählung der „Task was destroyed"-Meldungen | `wsl -d Debian -- bash -s -- -q < real_pytest.sh` |
|
|
|
|
## Teil 10 (2026-09-18): Paper-Runner, Anmeldung, Härtung
|
|
|
|
| Datei | Was sie tut | Aufruf |
|
|
|---|---|---|
|
|
| `start_probe_zugang.py` | die echte App mit Attrappe, Wegwerf-Register und Wegwerf-Zugang (Benutzer `probe`, bekanntes Passwort, TOTP-Beispielgeheimnis der RFC-Literatur; beides in `zugang.json` der Ablage), auf Wunsch mit einer Paper-Statusdatei. **Seit 2026-09-21 bricht es ab, wenn im Arbeitsordner eine `config/secrets.toml` liegt** — `erzeuge_app` startete bis Paket S5 immer den echten Stille-Wächter, und eine Probe-Instanz im echten Projektordner hätte nach 180 s aufs Telefon geklingelt | aus einer **Kopie** des Projektordners (ohne Geheimnisdatei) in WSL: `PYTHONPATH=. python start_probe_zugang.py <port> <ablage> [mit-paperstatus]` |
|
|
| `angriffe.py` | 56 Fälle gegen Host-Positivliste, Origin, Sitzungszwang, Cookie-Attribute, Bremse, CSP und die anderen Header, WebSocket ohne Sitzung; Regressionsnachweis gegen das Backend vor Teil B: 45 rot | `python angriffe.py <basis-url> <ablage-mit-zugang.json>` |
|
|
| `browserlauf_zugang.py` | Anmeldeformular ohne Sitzung, falsche und richtige Anmeldung (frischer TOTP-Code), Name und „Abmelden" in der Kopfzeile, Strom, Karte „Paper-Betrieb", alle Ansichten unter der CSP, Abmelden und Neuladen, 375 px; protokolliert jede Antwort ab 400 mit Phase und Pfad (`antworten-ab-400.json`); `--sabotage` muss rot enden; Screenshots — **ansehen** (der Lauf fand so das `GET /api/paper` vor dem Tor und die unbeschrifteten Felder) | `python -X utf8 browserlauf_zugang.py http://localhost:<port> <ablage>/zugang.json <ausgabeordner> [--sabotage]` |
|
|
| `pruef_beobachtung_echt.py` | `baue_beobachtung` gegen `NautilusEnv._beobachtung` auf den echten IEX-Kerzen eines Tages, beide Seiten unabhängig gerechnet; Sabotage rot. Seit 2026-09-18 mit zweitem Teil: eine feste Aktionsfolge über alle fünf Stufen, Vergleich nach jedem Schritt bei gleichem Zustand (gemessen am 2026-09-17: 120 Beobachtungen bitgleich, davon 50 long, 50 short, Kontowert in allen ungleich dem Startkapital, Zähler in 60 größer null); `--mutant-vorzeichen` (Betrag statt Vorzeichen der Position) lässt genau die 50 Short-Beobachtungen rot fallen, während der erste Teil grün bleibt | `PYTHONPATH=. python pruef_beobachtung_echt.py JJJJ-MM-TT` aus dem Projektordner |
|
|
| `lies_paper_protokoll.py` | fasst ein Paper- oder Probe-Protokoll zusammen (Takte je Phase, Killswitch je Takt, frische Kerzen, erste Entscheidung, Orders, Schlussphase, Ende) | `python lies_paper_protokoll.py <jsonl>` |
|
|
| `handelstag_auswertung.py` | wertet einen Paper-Handelstag aus: Takte je Phase, frische Kerzen, Spanne Taktzeile gegen Minutenende (Obergrenze für „Kerze abrufbar"), Orders, Ende; mit `--broker` lesend die Orders des Paper-Kontos (Annahme bis Füllung aus `created_at`/`filled_at` gegen `order_timeout_s`, dazu die Teilspannen bis `submitted_at` und von dort bis zur Füllung — seit dem ersten Handelstag, an dem der Broker eine Order 8,7 s zwischen Annahme und Weitergabe liegen ließ und `submitted_at` allein das verschwiegen hätte; ein Hinweis ab der halben Grenze; Vorzeichen offener Positionen), mit `--kerzen` die Kosten je Order gegen den Schluss der letzten abgeschlossenen IEX-Kerze in Basispunkten. Am 2026-09-18 an den zwei Protokollen der Nacht erprobt (Probe: Spanne ausgelassen, weil die Kerzen gespielt sind) | aus dem Projektordner: `python handelstag_auswertung.py <protokoll.jsonl> [--broker] [--kerzen]` |
|
|
| `vorstart_pruefung.py` | liest vor dem Runner-Start: läuft schon ein Runner, Killswitch-Zustand im Register (nur Auskunft — der Start stellt nach der Neustartregel immer auf `angehalten`; ein Befund ist allein `gesperrt`), Paper-Konto glatt, Marktuhr des Brokers, eigene Uhr gegen den `Date`-Kopf des Brokers. Am 2026-09-18 fand der erste trockene Lauf einen Killswitch auf `aktiv` (Klick um 08:55 Uhr), den der Start überschreibt | aus dem Projektordner: `python vorstart_pruefung.py` |
|
|
| `runner_stand.py` | zeigt den Stand eines laufenden Paper-Runners aus seinem Protokoll: Zeilen je Art, Takte je Phase und Killswitch-Zustand, letzter Takt, Order- und Ende-Zeilen. Urteilt nicht und gibt keine Kontowerte aus. Am 2026-09-18 am Protokoll der Nacht erprobt (drei Zeilen: `kopf`, `ereignis`, `ende`); an einem Protokoll mit Takten noch nicht | in WSL: `python runner_stand.py [<protokoll.jsonl>]`, ohne Angabe das neueste `*-paper.jsonl` im Projektordner |
|
|
| `protokoll_vergleich.py` | vergleicht zwei JSONL-Protokolle der Messwerkzeuge Wert für Wert (Bitgleichheit nach einem Umbau); trennt `ABWEICHUNG`, `NUR NEU` (neuer Schlüssel, kein Befund ohne `--streng`) und `NUR ALT`. Erprobt am 2026-09-18: Selbstvergleich 5.190 Werte ohne Befund, `--sabotage` (ein ULP) rot, der Ein-Jahres-Lauf mit `OMP_NUM_THREADS=8` gegen den ohne 621 Abweichungen ab der dreizehnten Stelle | `python protokoll_vergleich.py <alt.jsonl> <neu.jsonl> [--ohne …] [--streng] [--sabotage]` |
|
|
| `probe_neu_einfrieren.py` | friert `tests/fixtures/tage_t0_t1_referenz.json` nur neu ein, wenn der Diff genau der vorhergesagte ist (neuer Schlüssel `fenster_ausgelassen_pool` in den Poolzeilen, geänderte Werte allein in der T1-Poolzeile und dort nur in den gelisteten Feldern); erprobt am 2026-09-18 an der Kopie mit angewendetem Plan B: 24 erlaubte Änderungen, 0 Befunde; `--sabotage` (ein ULP in einer T0-Zeile) rot, und `--schreiben` schrieb dann nichts | in WSL aus der Projektwurzel: `python probe_neu_einfrieren.py [--schreiben] [--sabotage]` |
|
|
| `ntfy_probe_server.py` | nimmt ntfy-Meldungen auf `127.0.0.1` entgegen und schreibt sie als JSONL mit (Titel, Priorität, Tags, Text; vom `Authorization`-Kopf nur Schema und Länge) — für den Lauf mit echten Daten zu Paket D ohne echtes Thema; `--status 403` lässt jede Zustellung scheitern | `python ntfy_probe_server.py <port> <mitschrift.jsonl> [--status 200] [--verzoegerung 0.0]` |
|
|
| `handabruf_kerzen.py` | Alter der jüngsten AAPL-Minutenkerze per REST (`feed` iex oder sip) mit Urteil FRISCH/ALT — die Messung vor dem ersten Paper-Tag; nachts nur ein Funktionsnachweis. Gemessen 2026-09-18 nachts: iex antwortet in 0,5 s, sip mit 403 „subscription does not permit querying recent SIP data" | aus dem Projektordner: `TZ=Europe/Berlin python handabruf_kerzen.py [iex|sip]` |
|
|
|
|
**Seit 2026-09-18 kennen `angriffe.py` und `browserlauf_zugang.py` https.** `angriffe.py` erwartet je nach Schema der Basis-URL `Secure` am Cookie und `Strict-Transport-Security` (https) oder beides nicht (http), dazu unter https keine Antwort 200 auf Klartext; `--ca <pem>` nennt das Zertifikat, dem vertraut wird (geprüft, nicht abgeschaltet). `browserlauf_zugang.py --selbstsigniert` schaltet die Zertifikatsprüfung des Browsers ab. Regressionsnachweis vom selben Tag: gegen ein TLS-Backend mit einem Mutanten von `sicherheit.py` (ohne `Secure`, ohne HSTS) fielen genau die vier https-Fälle rot, Exit 2; Grundlinie über http 59 Fälle, über https 60. Läuft das Backend auf einem anderen Rechner, fährt man `angriffe.py` dort in einem Wegwerf-Container mit `--network host` und legt die drei Dateien der Ablage (`zugang.json`, `status.json`, `anmeldungen.jsonl`) per Verknüpfung in einen Ordner — das Werkzeug braucht Dateizugriff auf die Ablage des Backends.
|
|
|
|
## Paket F (2026-09-20): Produktivbetrieb als Dienst
|
|
|
|
| Datei | Was sie tut | Aufruf |
|
|
|---|---|---|
|
|
| `pause_echtlauf.py` | Tagesverlust-Schutz in der Pause auf den echten IEX-Kerzen eines Tages: rechnet aus den Rohkerzen vor, in welchem Takt die Grenze reißen muss (long und short, Grenze bei der Hälfte des größten Tagesverlusts), und hält das gegen das Protokoll der echten `PaperSitzung` im Zustand `angehalten`; dazu die Gegenprobe ohne Position. Einziger Netzzugriff: die Kerzen, lesend; Meldungen gehen an einen mitschreibenden Transport. Gemessen am 2026-09-17: long Takt 6, short Takt 173, je erwartet gleich gemessen | aus dem Projektordner in WSL: `python pause_echtlauf.py JJJJ-MM-TT` |
|
|
| `dienste_stand.sh` | nur lesend: Unit-Dateien, `is-enabled`, Zustand, Startzeiten und letzter Exit-Code von Dashboard-Dienst und Runner, Zeitgeber, `/api/gesund`, Start von systemd, die letzten Journalzeilen beider Dienste, `status.json` und `tagesstart.json` ohne Kontowerte. Das Journal geht ohne `sudo`, wenn der Benutzer in `adm` oder `systemd-journal` ist (hier: ja); sonst nimmt das Skript `sudo -S` mit `WSL_PW` aus der Umgebung | aus PowerShell: `wsl -d Debian --exec bash /mnt/d/Claude/.vault-tools/trading-plattform-pruefung/dienste_stand.sh` |
|
|
| `hole_kerzen.py` | holt die echten IEX-Minutenkerzen eines Handelstags lesend und legt sie als JSON ab — die Eingabe für `neustart_echtlauf.py`. Gemessen am 2026-09-20 für den 2026-09-17: 390 Kerzen, byte-gleich mit dem Abruf des Abschlussprüfers | aus dem Projektordner in WSL: `python hole_kerzen.py JJJJ-MM-TT <ziel.json>` |
|
|
| `neustart_echtlauf.py` | der Tagesverlust nach einem Neustart mitten am Tag: rechnet aus den Rohkerzen vor, bei welcher Kerze die echte Grenze (0,2 Prozent) gegen den Tagesstart reißt und bei welcher gegen den Neustartkurs, und fährt dann zwei echte `PaperSitzung`en nacheinander mit gemeinsamer `tagesstart.json`, dazu die Gegenprobe ohne Datei. Kein Netz. Gemessen am 2026-09-20 auf den Kerzen des 2026-09-17 und 2026-09-18: mit Datei Riss bei der vorgerechneten Kerze (5, 150, 19), ohne erst bei 18, 173, 42 | aus dem Projektordner in WSL: `python neustart_echtlauf.py <kerzen.json>` |
|
|
| `ntfy_lesen.py` | liest über die Abfrage-Schnittstelle von ntfy zurück, was in der letzten Stunde unter dem Thema der Maschine ankam — Titel, Priorität, Zeit, erste Zeile. **Schickt nichts und gibt das Thema nie aus**, auch nicht in einer Fehlermeldung | aus dem Projektordner in WSL: `python ntfy_lesen.py` |
|
|
| `wiederanlauf_probe.ps1` | beendet die Distribution hart (`wsl --terminate`) und misst, wann geplante Aufgabe, Distribution und Dashboard von selbst zurück sind. **Ein laufender Runner stirbt mit — nur außerhalb der Handelszeit, nur mit `-Ausfuehren`** (ohne den Schalter Exit 2, nichts getan). Während der Messung kein anderer `wsl.exe`-Aufruf, jeder Klient weckt die Distribution selbst. Gemessen am 2026-09-20: Rückkehr am nächsten Fünf-Minuten-Rasterpunkt, Dashboard 13 s danach | `powershell -File wiederanlauf_probe.ps1 -Ausfuehren` |
|
|
|
|
## Paket H (2026-09-21): Kennzahlen nach Home Assistant
|
|
|
|
| Datei | Was sie tut | Aufruf |
|
|
|---|---|---|
|
|
| `ha_einrichten.py` | richtet in Home Assistant die Gegenstelle für den Hausmelder ein: acht Helfer mit dem Präfix `trading_` und eine Automation mit Webhook-Auslöser (`local_only`, nur POST). Die Webhook-ID entsteht im Skript (64 Hex-Zeichen), wird nie ausgegeben und landet nur in `[homeassistant]` der `config/secrets.toml` des Trading-Projekts, mit `aktiv = false`. `pruefen` und `lesen` lesen nur (`lesen` zeigt zusätzlich die Zustände der Helfer), `probe` schickt eine Beispiel-Nutzlast und liest zurück, `entfernen` baut Helfer und Automation wieder ab. **Läuft unter Windows mit dem Python des Home-Assistant-Projekts** — dort liegen der Klient `src/ha_verbindung.py`, die Adresse der Instanz und der Name der Token-Variable; das Token bleibt auf der Windows-Seite und kommt nie auf den Trading-Rechner. Gemessen am 2026-09-20/21: eingerichtet, `probe` rückgelesen wie gesendet, und ein POST des echten `Hausmelder` aus WSL kam in den Helfern an | `<ha-projekt>\.venv\Scripts\python.exe -X utf8 ha_einrichten.py <pruefen|lesen|einrichten|probe|entfernen> "<ha-projekt>" "<trading-projekt>"` |
|
|
|
|
## Nacht vom 2026-09-20 auf den 2026-09-21: Generalprobe, Hausmelder, YubiKey, Härtung
|
|
|
|
| Datei | Was sie tut | Aufruf |
|
|
|---|---|---|
|
|
| `generalprobe_echtlauf.py` | ruft die **echte** Funktion `_generalprobe` aus `scripts/paper.py` — dieselbe Verdrahtung wie im Betrieb — mit den echten IEX-Kerzen eines Tages (JSON aus `hole_kerzen.py`), einer Sicherungskopie des Registers (das echte wird nur lesend geöffnet), dem echten Registermodell, einem mitschreibenden „echten" Konto, das bei jedem schreibenden Aufruf wirft, einer Netzsperre auf `requests.Session.request` und einem Faden, der wie das Dashboard klickt (fortsetzen, anhalten, fortsetzen, glattstellen, freigeben). Urteilt über Exit-Code, Modus, Meldungsvorsatz, Netzversuche, Aufrufe am Konto, Position nach dem Glattstellen, Alter des Herzschlags, `tagesstart.json`. Gemessen am 2026-09-20/21 mit den Kerzen des 2026-09-18: bei 1 s je Marktminute 435 s, 389 Takte, drei Orders, 0 Befunde | in WSL: `python generalprobe_echtlauf.py <code-baum> <echter-projektordner> <kerzen.json> <wegwerf-ordner> [tempo]` |
|
|
| `hausmelder_echtlauf.py` | der echte `Hausmelder`-Faden gegen einen mitschreibenden HTTP-Server auf `127.0.0.1`: erste Nutzlast ohne Statusdatei, Änderung, Stille ohne Änderung, Lebenszeichen, Killswitch-Wechsel, HTTP 500 (Merker kippt nicht), 302 (nicht gefolgt), `veraltet`, Adresse in keinem Fehlschlag und keinem `repr`, `starte_hausmelder` über eine Geheimnisdatei. Mit `--echt <secrets.toml>` zusätzlich **ein** POST an die dort eingetragene Adresse; die Adresse wird nie ausgegeben. Zurücklesen mit `ha_einrichten.py lesen` | in WSL: `python hausmelder_echtlauf.py <code-baum> <wegwerf-ordner> [--echt <secrets.toml>]` |
|
|
| `ha_aktiv_setzen.py` | setzt `[homeassistant] aktiv` in einer Geheimnisdatei auf `true` oder `false` — genau eine Zeile, mit Probe vor dem Schreiben, dass sich nur dieser Wert ändert; gibt nur Abschnittsnamen und die Länge der Adresse aus | `python ha_aktiv_setzen.py <secrets.toml> <true|false>` |
|
|
| `start_probe_w.py` | Probe-Backend wie `start_probe_zugang.py`, dazu die Konfiguration für Sicherheitsschlüssel (RP-ID `localhost`, Origin `http://localhost:<port>`) und wahlweise ein nur gelesener Marktkatalog. **Bricht ab, wenn im Arbeitsordner eine `config/secrets.toml` liegt** — Probe-Instanzen starten nur aus einer Kopie oder einem Arbeitsbaum ohne Geheimnisse, sonst sprächen sie mit dem echten ntfy und dem echten Home Assistant | in WSL aus der Kopie: `python start_probe_w.py <port> <ablage> [<katalog>]` |
|
|
| `browser_w.py` | Browserlauf zum YubiKey-Weg: Playwright/Chromium mit einem **virtuellen Authenticator** über das DevTools-Protokoll (`WebAuthn.addVirtualAuthenticator`) gegen die Probe-Instanz unter `http://localhost:<port>` — Anmelden mit Code, Registrieren in „Zugang", Anmelden mit Passwort und Schlüssel (der Zähler des Authenticators muss steigen, sonst wurde er nie gefragt), falsches Passwort, Code-Weg danach, Entfernen, Gegenprobe unter `127.0.0.1` (409), Schlüsseldatei und Anmeldeprotokoll ohne Passwort, keine CSP- oder Permissions-Policy-Meldung. Gemessen am 2026-09-21: 17 von 17, auch gegen eine gehärtete Systemeinheit | unter Windows: `python -X utf8 browser_w.py <port> <ablage>` |
|
|
| `latenz_auswertung.py` | rechnet Reaktionszeiten aus dem, was ein Lauf ohnehin hinterlässt — nur lesend, Register mit `mode=ro`: Klick → Runner reagiert (Ereignis in `killswitch_ereignisse` mit Auslöser `pascal` gegen die erste Taktzeile mit dem neuen Zustand; obere Schranke, weil die Taktzeile am Ende des Takts entsteht), Kerze → Taktende (nur im Modus `paper`) und den Taktabstand als Rahmen. Für Tage, an denen der Runner seine Latenzen noch nicht selbst misst. Gibt nie einen Kontowert aus | in WSL aus dem Projektordner: `python latenz_auswertung.py <protokoll.jsonl> [<register.db>]` |
|
|
| `bremse_echtlauf.py` | Misst das Wachstum des Anmeldeprotokolls im gesperrten Zustand gegen eine laufende Probe-Instanz: fünf Fehlversuche, dann je 5 s Dauerfeuer auf `beginn`, `abschluss` und den Weg mit Code, gezählt in Zeilen und Bytes; zweiter Durchgang mit dem Abschluss als erster gesperrter Anfrage; dazu der 409 des Abschlusses unter `127.0.0.1`. Anlass: Der Prüfer maß am 2026-09-21 im Schlüsselweg 22 474 B/s, weil die Protokollbremse nur im Weg mit Code stand. Nach Task 229 gemessen: 2721 Anfragen in 5 s → eine Zeile | in WSL: `python bremse_echtlauf.py <port> <ablage> <beginn\|abschluss>` |
|
|
| `s5_echtlauf.py` | Gegenmessung der Dashboard-Härtung gegen eine laufende Probe-Instanz: 422 ohne die Eingabe, 512 MiB Rumpf mit und ohne `content-length` samt Spitzenspeicher des Servers aus `/proc`, Latenz von `POST /api/killswitch/anhalten` unter 40 parallelen teuren Kerzenabrufen, überlanger Grund, Sitzungswiderruf nach Passwortwechsel. Gemessen am 2026-09-21: 413 in 0,19 s ohne Speicherzuwachs (vorher 1,5 GiB), Killswitch höchstens 0,51 s (vorher 118 s) | in WSL: `python s5_echtlauf.py <port> <ablage> <code-baum>` |
|
|
| `s1_alpaca_lesen.py` | liest mit dem Alpaca-Klienten eines Code-Baums die echten Antworten des Paper-Kontos — **nur lesend, ohne einen Betrag auszugeben** (Feldnamen, Typen, Statusverteilung der Orderhistorie, Felder mit `None`). Für den Vergleich alter gegen neuer Parser | in WSL: `python s1_alpaca_lesen.py <code-baum> <echter-projektordner>` |
|
|
|
|
## Killswitch-Simulation (2026-09-21)
|
|
|
|
| Datei | Was sie tut | Aufruf |
|
|
|---|---|---|
|
|
| `killswitch_simulation.py` | der Killswitch im Zeitraffer, **ohne Netz, ohne das echte Konto und ohne das echte Register** — die echte Funktion `_generalprobe` mit den Kerzen eines Tages (JSON aus `hole_kerzen.py`), verdrahtet wie `generalprobe_echtlauf.py`. Drei Szenarien: `hand` (fortsetzen, anhalten, fortsetzen, glattstellen, freigeben — gehandelt wird nur im Zustand `aktiv`, beim Anhalten bleibt die Position stehen, nach dem Glattstellen ist sie null und der Runner gesperrt), `sturz` (alle Kerzen ab 11:00 Uhr New Yorker Zeit zehn Prozent tiefer — der Runner reißt die Tagesverlustgrenze selbst, stellt glatt, sperrt, meldet „Grenze verletzt", und sperrt nach einem „Freigeben" im selben Takt wieder, ohne neue Order) und `neustart` (das Dashboard startet mitten am Tag neu — Pause mit stehender Position, Pausenmeldung mit dem Auslöser `neustart`, und die Latenzanzeige zählt den Neustart nicht als Klick). Der Kopfkommentar nennt je Prüfung die Herkunft der Erwartung und die Grenzen: Gefüllt wird gespielt, der Klick geht nicht über HTTP, der Watchdog wird nicht gezielt ausgelöst. **Anlass:** Die Killswitch-Übung des Projekts stellt echte Orders und schreibt ins gemeinsame Register — sie darf nicht laufen, solange der Paper-Runner läuft. Gemessen am 2026-09-21 gegen den Betriebscode (0.20.0) mit den Kerzen des 2026-09-18 bei 1 s je Marktminute: je Szenario 431 s, Exit 0, 389 Takte, kein Befund und kein Hinweis; Reaktion des Runners auf einen Klick 0,85 bis 0,99 s (neun Messungen) | in WSL: `python killswitch_simulation.py <hand\|sturz\|neustart> <code-baum> <echter-projektordner> <kerzen.json> <wegwerf-ordner> [tempo]` |
|
|
| `killswitch_simulation_mutanten.py` | der Regressionsnachweis dazu: kopiert den Code-Baum, fährt zuerst die Grundlinie, macht die Kopie dann an sechs Stellen einzeln kaputt (Runner übergeht den Killswitch; Glattstellen schließt nicht; Tagesverlustgrenze greift nicht; jeder Auslöser zählt als Klick; keine Pausenmeldung beim Neustart; Tagesverlust hält nur an) und erwartet je Mutant Exit 2. Ein Muster, das nicht genau einmal trifft, ist ein Befund des Treibers. In zwei Teilen, je unter zehn Minuten. Gemessen am 2026-09-21 gegen den Betriebscode: Grundlinie und Gegenprobe in allen drei Szenarien ohne Befund, alle sechs Mutanten gesehen — drei davon an genau einer Prüfung (die Position nach dem Glattstellen, die Zahl der Klick-Messungen, die fehlende Pausenmeldung). **Der erste Lauf der Grundlinie fand dabei einen Fehler der Prüfung, nicht des Runners:** Im Schnelltempo fiel ein Klick mitten in einen Takt; dessen Taktzeile trug schon `gesperrt`, aber noch die Phase `handelt`, ohne Entscheidung und ohne Order. Seitdem ist alles ab dem zweiten Takt eines nicht aktiven Abschnitts verbindlich, der erste wird als Hinweis gedruckt | in WSL: `python killswitch_simulation_mutanten.py <code-baum> <echter-projektordner> <kerzen.json> <arbeitsordner> <1\|2>` |
|
|
|
|
## Red Button (2026-09-22, Paket R)
|
|
|
|
| Datei | Was sie tut | Aufruf |
|
|
|---|---|---|
|
|
| `browser_r.py` | Browserlauf zum Red Button mit virtuellem Sicherheitsschlüssel gegen eine Probe-Instanz (`start_probe_w.py` aus einer Kopie ohne Geheimnisdatei, mit gebautem `dashboard/dist`): anmelden mit Code, Schlüssel registrieren, unter `127.0.0.1` den Dialog öffnen (Hinweis „nur unter http://localhost:…", kein Wortfeld, gesperrter Knopf, kein POST), unter `localhost` den Red Button drücken, Grund eintragen, Stick (virtuell) berühren — beginn und Abschluss 200, Zähler des Authenticators steigt, genau ein Registerereignis `glattstellen` mit Auslöser `pascal`, Kopfzeile gesperrt; Screenshots. Importiert `totp`, `schritt` und `melde_mit_code_an` aus `browser_w.py`. **Reihenfolge ist Absicht:** erst `127.0.0.1`, solange der Killswitch noch bedienbar ist — nach dem Notaus ist er gesperrt. Gemessen am 2026-09-22: 15 von 16, der eine Befund war ein zu strenger Check des Skripts (berichtigt). Nicht gemessen: eine abgelehnte Signatur (der virtuelle Authenticator signiert immer gültig), das Wort ohne Schlüssel, die Protokollbremse — das deckt `tests/test_dashboard_red_button.py` | unter Windows: `python -X utf8 browser_r.py <port> <ablage-der-probe> <ordner-fuer-screenshots>` |
|
|
|
|
Das Einrichten selbst (`deploy/dienste-einrichten.sh` unter `sudo -S`, `deploy/windows/wsl-wachhalten.ps1 -Aktion einrichten`) und das Eintragen des ntfy-Themas liefen aus dem Scratchpad der Sitzung; die Befehle stehen in der Administrator-Anleitung des Projekts, Abschnitt „Produktivbetrieb als Dienst".
|
|
|
|
Die Compose-Probe (Bauen aus dem echten Baum mit verankerten Ausschlüssen, Start, Healthcheck, Angriffsfälle, Runner-Probe im Container, Aufräumen) lag als `compose_probe_echt.sh` im Scratchpad der Sitzung und braucht `sudo -S` mit dem WSL-Passwort aus `$WSL_PW`; sie ist deshalb nicht hier abgelegt. Muster: `tar --exclude=./data` — ohne Anker fällt auch `trading/data` weg.
|
|
|
|
Vor dem Browser-Lauf `npm run build` im Projekt, sonst dient das Backend eine alte Oberfläche aus. Die Datensatz- und Dateinamen in `browserlauf.py` und `pruef_teil3b.py` sind die des Bestands vom 2026-09-17; nach einem neuen Katalog oder neuen Protokollen nachziehen. Die Statustexte in `wiederaufbau.py` sind aus `Kopfzeile.tsx` abgeschrieben.
|
|
|
|
Die generischen Planwerkzeuge liegen unter `.vault-tools/plan-kopie/`.
|
|
|
|
## Geheimnisdatei seit Paket E2 (2026-09-23)
|
|
|
|
Die Werkzeuge nennen `config/secrets.toml` nicht mehr fest. Wer eine Projektklasse ruft, gibt `None` weiter (`from_secrets(None, …)`, `secrets_pfad=None`, `lies_ntfy_geheimnisse()`); wer die Datei selbst liest (`handabruf_kerzen.py`, `handelstag_auswertung.py`, `vorstart_pruefung.py`, `pruef_beobachtung_echt.py`), holt den Pfad mit `trading.geheimnisse.pfad()` und nennt im Fehlerfall `geheimnisse.beschreibung()`; `ha_einrichten.py` löst gegen den übergebenen Projektordner auf. Der Auflöser nimmt das Argument, dann `TRADING_GEHEIMNISSE`, dann `$CREDENTIALS_DIRECTORY/secrets.toml`, sonst `config/secrets.toml` relativ zum Arbeitsverzeichnis — **nach dem Umzug der Datei ins Linux-Dateisystem steht die Variable nur in einer Login-Shell** (`~/.profile`). Ein Werkzeug aus einer Skriptdatei über `wsl --exec bash` sieht sie nicht und meldet „fehlt": dann `export TRADING_GEHEIMNISSE=/home/claude/.config/trading-plattform/secrets.toml` im Skript setzen. `start_probe_w.py` und `start_probe_zugang.py` nehmen beide Variablen absichtlich aus ihrer Umgebung, damit eine Probe nie die echte Datei liest; `ha_aktiv_setzen.py` bekommt den Pfad als Argument.
|
|
|
|
## Paket M (2026-09-24): zehn Aktien in einem Runner
|
|
|
|
| Datei | Was sie tut | Aufruf |
|
|
|---|---|---|
|
|
| `handelstag_auswertung.py` | seit Paket M mit mehreren Instrumenten: Instrumente aus dem Protokollkopf; je Instrument Entscheidungen, Orders und die aus der Folge erwartete Zahl (Stufen, Versatz, Entscheidungen, Schlussbein, ohne geteilte Beine), erreichte Positionen und Takte mit frischer Kerze; groesste Zahl von Orders in einem Takt, Ereignisse je Art, Positionen je Instrument am Ende, BEFUND fuer jede nicht gefuellte Orderzeile; das Taktfeld orders gilt als Orders dieses Takts; `--broker` und `--kerzen` fragen alle Symbole des Kopfs, jede Order gegen die Kerze ihres Symbols | wie bisher: `python handelstag_auswertung.py <protokoll> [--broker] [--kerzen]` aus dem Projektordner |
|
|
| `m_probeaufruf.py` | lesender Probeaufruf vor dem Einspielen: `GET /v2/assets` roh (Schluessel und Typen) und ueber `AlpacaBroker.anlage`, `trades/latest` mit allen Symbolen roh und ueber `letzte_kurse`, Kerzen gebuendelt gegen einzeln, Seitenverhalten mit kleiner Seite; Exit 0 nur, wenn alles wie angenommen ist und keine Aktie die Startpruefung einer Folge mit Short verfehlt | aus einem Arbeitsbaum mit Paket M in WSL: `python m_probeaufruf.py <handelstag> <kennung> ...` |
|
|
|
|
## Betrieb ohne täglichen Klick (2026-09-24): Abendkontrolle und Rückweg
|
|
|
|
Pascal am 2026-09-24: eine dauerhafte Abendkontrolle, die Neustarts übersteht und keine Updates von Claude Code oder Desktop blockiert, und zehn Aktien bis Mittwoch 2026-09-30. Beides läuft als Windows-Aufgabe mit `pythonw.exe`, ohne Claude-Prozess.
|
|
|
|
| Datei | Was sie tut | Aufruf |
|
|
|---|---|---|
|
|
| `abendkontrolle_wsl.py` | liest einen Handelstag und urteilt im Code: Handelstag laut `GET /v2/calendar`, Protokoll des scharfen Runners, letzte Zeile „Ende: …, Exit n" im Journal (jeder Exit ungleich 0 ist ein Befund), BEFUND-Zeilen von `handelstag_auswertung.py --broker --kerzen`, offene Positionen beim Broker, mindestens ein Takt `aktiv`, Tagesbericht, Dashboard und Zeitgeber, Killswitch nicht `gesperrt`; bei Befund eine Meldung mit hoher Priorität über den Melder des Projekts. Gibt eine JSON-Zeile aus, nie Beträge | in WSL: `python abendkontrolle_wsl.py --tag JJJJ-MM-TT [--ohne-meldung]`; nur eine Meldung: `--meldung TITEL TEXT` |
|
|
| `abendkontrolle.py` | Windows-Seite: prüft jeden Werktag seit 2026-09-24 ohne Ergebnisdatei (höchstens sieben Tage zurück, heute erst ab 22:30), legt das Ergebnis unter `data/paper/abendkontrollen/<tag>.json` im Projekt ab und schreibt eine Zeile in `Inbox/<tag>.md` unter „Agentenprotokoll", bei Befund mit `#needs-review` | `python abendkontrolle.py [--tag JJJJ-MM-TT]` |
|
|
| `abendkontrolle_einrichten.ps1` | Aufgabe „Trading Plattform - Abendkontrolle": werktags 22:45 und fünf Minuten nach jeder Anmeldung, nur angemeldet, verpasste Läufe beim nächsten Start | `powershell -NoProfile -File abendkontrolle_einrichten.ps1 [-Aktion entfernen]` |
|
|
| `abendkontrolle_angriffe.py`, `abendkontrolle_ersatz_auswertung.py` | 44 Fälle in WSL (Kalender, Protokoll, Ende je Lauf samt mittags abgebrochenem und abendlichem Lauf, Journal, Auswertung, Broker, Maske, Bericht, Dienste, Killswitch, getrennte Fragen, Meldeweg gegen `ntfy_probe_server.py` und gegen einen toten Port, Bedienfehler; Reihenfolge an zwei Positionen) und 20 unter Windows (Notiz, Überschrift mit Zusatz, CRLF, kein UTF-8, Ergebnisform, Abbruch wird wiederholt, keine Nachbardatei, fällige Tage), ohne Netz. Am 2026-09-24 nach der unabhängigen Prüfung: 0 Abweichungen | `python abendkontrolle_angriffe.py` einmal in WSL (Venv), einmal unter Windows |
|
|
| `rueckweg_aapl.py`, `rueckweg_aapl_einrichten.ps1` | einmal: `config/paper-aapl-register.toml` wird `config/paper.toml`, lokal committet (nicht gepusht) — nur nach 2026-09-30 22:05, bei stehendem Runner, sauberem Projektordner mit `master`, wenn dort noch die Konfiguration mit `quelle = "folge"` liegt und beide Dateien ausser `[agent]`, den Instrumenten und dem Tagesverlust dieselben Schluessel und Werte tragen, in beide Richtungen verglichen (sonst schaltete der Tausch etwa ein abgeschaltetes `[auto_fortsetzen]` still wieder ein); ein halb erledigter Tausch wird zu Ende committet. Sonst Befund in der Notiz und eine Meldung. Aufgabe „Trading Plattform - Rueckweg AAPL" am 2026-09-30 22:50, zweiter Versuch 2026-10-01 22:10 | `python rueckweg_aapl.py`; Einrichten wie oben |
|
|
| `rueckweg_aapl_angriffe.py` | 22 Fälle auf einem Wegwerf-Git-Repo (dazu halb getauscht, Abschnitt nur in `paper.toml`, Automatik nur dort abgeschaltet, Abschnitt nur dort gelöscht, anderer Wert, anderer Zweig); am 2026-09-24 0 Abweichungen | `python rueckweg_aapl_angriffe.py` unter Windows |
|
|
| `abendkontrolle_mutanten.py` | baut je einen Fehler in eine Wegwerfkopie und verlangt, dass der Angriffstreiber rot wird: 16 Mutanten von `abendkontrolle_wsl.py` (in WSL), 9 von `abendkontrolle.py` und 12 von `rueckweg_aapl.py` (unter Windows). Am 2026-09-24: 37 von 37 gefangen | `python abendkontrolle_mutanten.py` einmal in WSL, einmal unter Windows |
|
|
|
|
## Einspielen (2026-09-24): Werkzeuge aus dem Scratchpad hierher
|
|
|
|
| Datei | Was sie tut | Aufruf |
|
|
|---|---|---|
|
|
| `dashboard_neustart.sh` | `sudo systemctl restart trading-dashboard.service` nur bei stehendem Runner, danach Tor 6b (Journal der letzten Minute ohne `PermissionError`/`Traceback`, sonst Exit 27), `/api/gesund` und die Oberfläche. Pascals dauerhafte Freigabe gilt für genau diesen Neustart außerhalb der Handelszeit | mit `WSL_PW` per WSLENV: `wsl -d Debian -u claude -- bash …/dashboard_neustart.sh` |
|
|
| `geheimnis_scan.py` | vor jedem Push: Werte ab 12 Zeichen aus Geheimnis- und Zugangsdatei gegen `git log -p <von>..<bis>`, nur Schlüsselnamen und Trefferzahlen; dazu, ob eine der drei Geheimnisdateien verfolgt wird. Regressionsnachweis mit `SCAN_PROBE=<bekannter Text>` (am 2026-09-24: 66 Treffer für einen bekannten Text, 0 für die echten Werte) | in WSL: `python geheimnis_scan.py <repo> <von> <bis> [<bis> …]` |
|
|
| `scan_push.sh` | Hülle um `geheimnis_scan.py` für den Projektordner: zählt die Commits im Bereich, fährt erst die Probe (`SCAN_PROBE_TEXT`, Vorgabe „Nachholtage melden“, ab 12 Zeichen) und dann den Scan. Nötig, weil aus der Git-Bash `$VAR` leer in WSL ankommt und der Scan dann „0 Zeichen Verlauf, 0 Treffer“ meldet (2026-09-25). Arbeitsbäume taugen nicht als `<repo>`: ihr `.git` zeigt auf einen Windows-Pfad | aus der PowerShell: `wsl -d Debian -- bash /mnt/d/Claude/.vault-tools/trading-plattform-pruefung/scan_push.sh <von> <bis>` |
|
|
|
|
## IBKR-Zugang (2026-09-24): Paper-Konto über das Gateway im Container
|
|
|
|
Pascal am 2026-09-24: Zugang zum IBKR-Paper-Konto vorbereiten, Gateway als Container in WSL, erster Test nach 22:00. Nichts davon handelt.
|
|
|
|
| Datei | Was sie tut | Aufruf |
|
|
|---|---|---|
|
|
| `ibkr_zugang_eintragen.sh` | Pascal trägt Paper-Benutzername, Passwort (ohne Anzeige, zweimal) und Kontonummer ein; Ablage `/home/claude/.config/trading-plattform/ibkr/` (0700/0600); ausgegeben werden nur Längen. Mit erfundenen Werten in einem Wegwerf-Ordner geprüft (`IBKR_ZIEL`) | `wsl -d Debian -u claude -- bash …/ibkr_zugang_eintragen.sh` |
|
|
| `ibkr_gateway_test.sh` | Gateway-Container `ghcr.io/gnzsnz/ib-gateway` (auf eine Prüfsumme festgelegt), Paper, `READ_ONLY_API=yes`, Port nur auf `127.0.0.1:4004`; Schritte `laden`, `pruefen`, `starten`, `log` (Benutzername maskiert), `probe`, `stoppen`; verweigert zwischen 15 und 22 Uhr Berlin | mit `WSL_PW` per WSLENV: `wsl -d Debian -u claude -- bash …/ibkr_gateway_test.sh <schritt>` |
|
|
| `ibkr_probe.py` | lesende Probe über `nautilus-ibapi` im eigenen Venv `~/venvs/ibkr-probe`: Verbindung, Konto (nur Anfang und Länge), Kontoart, Währung, Positionen (Zahl), verzögerter AAPL-Kurs (nur die Kursart), Fehlercodes; nie ein Betrag. Ohne Gateway geprüft: „keine Verbindung", Code 502, Exit 3 | `~/venvs/ibkr-probe/bin/python …/ibkr_probe.py [--port 4004]` |
|
|
|
|
## Paket AF (2026-09-24): Fortsetzen zum Tagesstart ohne Klick
|
|
|
|
| Datei | Was sie tut | Aufruf |
|
|
|---|---|---|
|
|
| `af_gegenfall.py` | faehrt die echte PaperSitzung eines Arbeitsbaums mit AF und der ausgelieferten `config/paper.toml` gegen einen ProbeBroker, Kerzen aus einer Datei von `hole_kerzen.py` fuer jede Aktie, Wegwerf-Register mit der Neustartregel, ohne Netz; der Fall `restposition` (10 Stueck in der letzten Aktie) und der Fall `mitten` (Start 60 Marktminuten nach der Oeffnung) muessen `nicht_fortgesetzt` mit dem Grund in Protokoll und Meldung zeigen, der Fall `flach` ist die Gegenprobe mit `fortgesetzt`, Ausloeser `automatik` und Orders; Exit 0 nur ohne BEFUND | aus dem Arbeitsbaum in WSL: `python af_gegenfall.py <kerzen.json> <fall>`, Fall `restposition`, `mitten` oder `flach`; die Kerzen vorher einmal lesend mit `hole_kerzen.py <tag> <kerzen.json>` |
|
|
| `af_registerprobe.py` | fragt die echte Funktion `pruefe_register` (Paket AF) gegen `data/registry.db`, nur lesend (`mode=ro`; die Klasse `Registry` fuehrte beim Oeffnen das Schema aus und schriebe); druckt Zustand, die vier juengsten Killswitch-Ereignisse (Stufe, Ausloeser, Zeit) und den Befund; Exit 0 erfuellt, 1 nicht erfuellt, 3 Register fehlt. Belegt am 2026-09-24 an drei gespielten Registern (bereit / Pascals Anhalten ohne Fortsetzen / aktiv) und an einer Kopie des echten; die mtime des echten blieb gleich. Braucht den Code mit AF im genannten Ordner | in WSL im Projektordner nach dem Dashboard-Neustart: `~/venvs/trading/bin/python af_registerprobe.py .` |
|
|
|
|
Was die uebrigen Werkzeuge mit AF sehen: `handelstag_auswertung.py` braucht keine Aenderung, es zaehlt das Ereignis `auto_fortsetzen` unter `ereignisse je art` und druckt seinen Text. `abendkontrolle_wsl.py` liest Zustand, Seit und Ausloeser des Killswitch und berichtet jede Zeile `auto_fortsetzen` als Hinweis (die ersten 200 Zeichen des Feldes text, das mit dem Ergebnis beginnt). `neustart_echtlauf.py` setzt `angehalten`/`neustart` ohne Ereignis, `pause_echtlauf.py` einen Ausloeser `echtlauf`: Die Sitzung setzt dort nicht fort, schreibt aber je Lauf eine Zeile `auto_fortsetzen` und in "Paper-Runner wartet" eine Zeile mehr. `generalprobe_echtlauf.py` und `killswitch_simulation.py` laden `config/paper.toml` und klicken nach Plan; gegen einen Baum mit AF setzt die Sitzung dort mit dem Schalter selbst fort, bevor der geplante Klick kommt. Wer diese vier fuer einen Vergleich mit Paket M faehrt, setzt vorher `auto_fortsetzen=False` in ihr `replace(lade_paper_config(...), ...)`; `neustart_echtlauf.py` und `pause_echtlauf.py` rufen `lade_paper_config` ohne `replace` auf — dort in der Konfiguration ihrer Kopie `[auto_fortsetzen] aktiv = false` setzen.
|
|
|
|
## Paket Z2 (2026-09-26): Totmann in Home Assistant
|
|
|
|
| Datei | Was sie tut | Aufruf |
|
|
|---|---|---|
|
|
| `ha_totmann.py` | richtet in Home Assistant eine Automation ein, die im Handelsfenster (aus dem Kalender von Alpaca, 400 Tage, als Epoch-Sekunden in der Bedingung) meldet, wenn `input_datetime.trading_gesendet` aelter als 15 Minuten ist, einmal je Stille und Handelstag, ueber einen App-Dienst aus `--app-dienst` und ueber `rest_command.trading_totmann_ntfy`; Adresse mit Thema und Zugriff stehen nur in `/config/secrets.yaml` von Home Assistant, der Block `rest_command:` mit `!secret` in `/config/configuration.yaml`, beide zwischen Marken und ueber die File-editor-API geschrieben. `pruefen` laesst Home Assistant die Bedingung mit acht gestellten Lagen per `render_template` rechnen, `trocken` rechnet dieselben Lagen lokal, ohne Netz | unter Windows mit dem Python des HA-Projekts: `ha_totmann.py pruefen <ha-projekt> <trading-projekt>`, dann `einrichten ... --app-dienst notify.<name>` (Exit 4: Home Assistant neu starten, dann noch einmal), `probe ... --app-dienst notify.<name>` (zwei echte Meldungen), Rueckweg `entfernen ...`; `ha_totmann.py trocken` ohne Ordner |
|
|
| `ha_totmann_wsl.py` | WSL-Teil von `ha_totmann.py`: liest in WSL aus der Geheimnisdatei der Plattform Thema, Token und die Alpaca-Schluessel, fragt den Kalender von Alpaca und gibt genau eine JSON-Zeile auf stdout; `ha_totmann.py einrichten` startet ihn ueber `wsl.exe --exec` und liest die Zeile nur als Pipe. Die Geheimnisdatei verlaesst WSL nicht | nur ueber `ha_totmann.py einrichten`; nie von Hand, sonst stuende das Thema auf der Konsole |
|
|
|
|
Was es nicht tut: Es aendert nichts an der Automation der Kennzahlen aus `ha_einrichten.py` und nichts an deren Helfern; es startet Home Assistant nie selbst neu. Der Kalender in der Bedingung laeuft nach 400 Tagen aus, danach schweigt der Totmann; der Alias der Automation nennt den letzten Tag, `pruefen` zeigt ihn, `einrichten` verlaengert.
|
|
|
|
## Paket IB2 (2026-09-25): Abendkontrolle der IBKR-Instanz
|
|
|
|
Seit Paket IB2 prüft die Abendkontrolle zwei Teile je Tag, nacheinander: den Alpaca-Runner wie bisher und die IBKR-Instanz im Betriebsordner `/mnt/d/Claude/.arbeitsbaeume/trading-ibkr-betrieb`. Der IBKR-Teil hat eine eigene Ergebnisdatei (`data/paper/abendkontrollen/<tag>-ibkr.json` im Projekt), eine eigene Zeile „Abendkontrolle IBKR (automatisch)“ in derselben Tagesnotiz, eigenes Nachholen ab `IBKR_ERSTER_TAG` in `abendkontrolle.py` und bei Befund eine eigene Meldung mit hoher Priorität, Titel „IBKR Abendkontrolle <tag>: n Befund(e)“. Ist der Zeitgeber `trading-paper-ibkr.timer` nicht `active` und gibt es kein Protokoll des Tages (No-Go-Tag), steht nur „IBKR-Instanz heute nicht gestartet (Zeitgeber aus).“ da, ohne Befund.
|
|
|
|
| Datei | Was sich ändert | Aufruf |
|
|
|---|---|---|
|
|
| `abendkontrolle_wsl.py` | `--teil ibkr`: Kalender wie beim Alpaca-Teil; Protokolle `<tag>T*-paper.jsonl` im Betriebsordner (Ende je Lauf, mindestens ein Takt `aktiv`, Schlussposition jedes Laufs aus seiner Zeile `ende` unabhängig vom Journal); die Instanzmarke `data/paper/broker.txt` muss `ibkr` sagen; Register der Instanz nur lesend (`mode=ro`), `gesperrt` ist ein Befund mit Stufe und Auslöser des jüngsten Ereignisses; Journal von `trading-paper-ibkr.service` (Ende, Exit, `Failed with result`, `Traceback`, „Nichts wird gebaut“); werktags außerhalb 09:00 bis 16:15 New Yorker Zeit und am Wochenende `scripts/ibkr_pruefen.py lesen` im Betriebsordner mit `~/venvs/trading-ibkr` (Client-ID 12, lesend) — Positionen und offene Orders müssen 0 sein; im Handelsfenster nur ein Hinweis. Aus der Ausgabe von `ibkr_pruefen.py` gehen nur die Zahlen und die Zeilen `BEFUND` und „Voraussetzung fehlt“ weiter, Kontonummern als `[konto]`, dann durch `maskiere()` | in WSL: `python abendkontrolle_wsl.py --teil ibkr --tag JJJJ-MM-TT [--ohne-meldung]`; für die Angriffsfälle dazu `--ibkr-ordner`, `--ibkr-konto` (JSON mit `exit` und `text`), `--jetzt` (ISO mit Versatz), `--kalender`, `--journal`, `--dienste` |
|
|
| `abendkontrolle.py` | fährt ohne `--teil` beide Teile nacheinander, erst `alpaca`, dann `ibkr`; `--teil alpaca` oder `--teil ibkr` nur einen; mit `--ohne-wsl` ohne `--teil` nur `alpaca`. Ein Ergebnis, dessen `teil` nicht zum angeforderten passt, gilt als gescheitert. Die Befund-Zeile beider Teile baut dieselbe Funktion `_zeile` | `python abendkontrolle.py [--tag JJJJ-MM-TT] [--teil ibkr]` |
|
|
| `abendkontrolle_angriffe.py` | dazu IBKR-Fälle in WSL (Grundlinie, Zeitgeber aus und an, von Hand gelaufen, Kalender, Marke, Register, Ende je Lauf, Handel, Restposition im Protokoll bei sauberem Journal, Journal, Konto am Gateway samt Maske der Kontonummer, Handelsfenster, Ordner fehlt, Bedienfehler, Meldeweg gegen `ntfy_probe_server.py` mit Titel „IBKR …“ und Priorität `high`) und unter Windows (eigene Zeile und Datei, Befund, No-Go-Tag, kein Handelstag, Abbruch, gescheitert, Ergebnis eines anderen Teils, `--ohne-wsl` nur Alpaca, beide Teile in einer Notiz, fällige Tage relativ zu `IBKR_ERSTER_TAG`), ohne Netz | wie oben |
|
|
| `abendkontrolle_mutanten.py` | dazu Mutanten der IBKR-Teile beider Dateien, auch für Schlussposition, Titelpräfix, Meldeweiche und die Prüfung des Teils; die Anker „keine Ergebnisdatei“ und „Wochenende mit“ folgen dem Code aus IB2 | wie oben |
|
|
|
|
Die Zahlen der Fälle und Mutanten im Abschnitt vom 2026-09-24 gelten für den Stand vor IB2; wie viele es jetzt sind, sagt die Zeile `ERGEBNIS` des Laufs. Was der IBKR-Teil nicht sieht: einen Tagesbericht (die Instanz hat keine Tagesauswertung), `handelstag_auswertung.py` und den Dienst `ibkr-gateway.service`. Holt die Kontrolle einen Tag während der New Yorker Handelszeit nach (Anmeldung am Nachmittag), liest sie das Konto nicht; der nächste Abendlauf liest es für seinen eigenen Tag. Den Zeitgeber liest sie zum Zeitpunkt der Kontrolle, nicht für den geprüften Tag: Beim Nachholen nach einem Umschalten kann sie einen Ausfall als „nicht gestartet“ werten oder einen No-Go-Tag als Befund.
|
|
|
|
## Paket DH (Trading Plattform 0.34.0): Abendkontrolle vom Docker-Host
|
|
|
|
Nach dem Umzug auf den Docker-Host (Hyper-V-VM) prüft der Host selbst: `deploy/docker-host/abendkontrolle-host.sh` aus dem Repo startet werktags 16:30 New Yorker Zeit `abendkontrolle_wsl.py` im Abbild der Plattform, mit `--journal` und `--dienste` statt `journalctl` und `systemctl` im Container — erst den Teil alpaca im Projekt `trading-alpaca`, dann den Teil ibkr im Projekt `trading-ibkr`, dort im Netz des Gateways und mit `--ibkr-python python`, weil es das Venv aus WSL im Abbild nicht gibt. Dafür liegen `abendkontrolle_wsl.py` und `handelstag_auswertung.py` als Kopie unter `/opt/trading-plattform/werkzeuge/` auf dem Host (Umzugs-Drehbuch, 4.4); wer eines davon hier ändert, kopiert es dort neu. Die Ergebnisse liegen je Tag unter `/var/lib/trading-abendkontrolle/<tag>.json` und `<tag>-ibkr.json`; scharf ist jeder Teil erst ab dem Datum in `erster-tag` beziehungsweise `erster-tag-ibkr` dort.
|
|
|
|
| Datei | Was sie tut | Aufruf |
|
|
|---|---|---|
|
|
| `abendkontrolle.py` | seit Paket DH mit `--quelle wsl` (Vorgabe, wie bisher) oder `--quelle dockerhost` für den Teil alpaca und `--quelle-ibkr` für den Teil ibkr (ohne Angabe wie `--quelle`). `dockerhost` liest das Ergebnis des Hosts über `ssh.exe` als Benutzer `kontrolle` mit dem Schlüssel `~/.ssh/trading-dh-kontrolle`, `BatchMode` und `StrictHostKeyChecking=yes` gegen `~/.ssh/known_hosts_trading_dh`, angefragt mit `JJJJ-MM-TT` oder `JJJJ-MM-TT-ibkr`. Auf dem Host darf der Schlüssel nur `abendkontrolle-lesen.sh`. Exit 3 dort heißt „noch kein Ergebnis“: Notiz mit `#needs-review`, der nächste Lauf versucht es erneut | `python abendkontrolle.py --quelle dockerhost [--quelle-ibkr wsl] [--tag JJJJ-MM-TT]` |
|
|
| `abendkontrolle_einrichten.ps1` | seit Paket DH mit `-Quelle` und `-QuelleIbkr` (je `wsl` oder `dockerhost`); kommt ein Teil vom Host, liegt der Abendlauf auf 23:15. Die letzte Zeile nennt beide Quellen | `powershell -NoProfile -File abendkontrolle_einrichten.ps1 -Quelle dockerhost -QuelleIbkr wsl` |
|
|
| `abendkontrolle_dockerhost_angriffe.py` | zwölf Fälle ohne Netz, abgedichtet: `wsl.exe` zeigt ins Leere, und `fahre_wsl` lehnt ohne eigene Attrappe des Falls ab, ein Aufruf des echten Wegs ist eine Abweichung (so auch der Windows-Teil von `abendkontrolle_angriffe.py`). Die Fälle: beide Ergebnisse landen in Ablage und Notiz, Argumente von ssh je Teil, Exit 3 als Befund, Müll als Befund, fällige Tage einzeln je Teil, ohne Schalter bleibt es WSL, `--quelle-ibkr wsl` hält die Instanz in WSL, ein Ergebnis des falschen Teils vom Host, unbekannte Quelle, Frist und Aufgabe passen zueinander. Fängt je Fall auch `SystemExit` | `python abendkontrolle_dockerhost_angriffe.py` unter Windows |
|
|
| `abendkontrolle_ibkr_python_angriffe.py` | seit der Prüfung vom 2026-09-26 mit zweiter Sperre: `IBKR_ORDNER` zeigt ins Leere; dazu dichtet `rueckweg_aapl_angriffe.py` seither `WSL` und `WSL_SKRIPT` im Modul `rueckweg_aapl` ab, und `abendkontrolle_angriffe.py` räumt seinen leeren Ordner im Temp wieder weg. Sonst: vier Fälle ohne Netz für `--ibkr-python` von `abendkontrolle_wsl.py`: Schalter, Vorgabe `IBKR_PY`, `ibkr_pruefen.py lesen` läuft mit dem genannten Interpreter (Ersatzskript im Wegwerf-Ordner), der Ablauf reicht den Schalter weiter | `python abendkontrolle_ibkr_python_angriffe.py` in WSL im Venv |
|
|
|
|
Was es nicht tut: Es prüft nicht, ob der Host die Kontrolle überhaupt fährt — bleibt sie dort aus, steht jeden Abend „noch kein Ergebnis“ in der Notiz, und das ist der Hinweis. Steht `-QuelleIbkr` falsch, fällt das nicht immer auf: Prüft die Aufgabe den Teil ibkr in WSL, obwohl die Instanz schon auf dem Host läuft, meldet sie ihn dort nur leise als „nicht gestartet“, weil der Zeitgeber in WSL aus ist. Ein Anmelde-Lauf zwischen 22:30 und dem Ende der Prüfung auf dem Host bekommt einmal „noch kein Ergebnis“, weil die Frist `FRUEHESTENS` für beide Quellen gilt (die Mutanten suchen genau diese Zeile).
|