- .vault-tools/trading-plattform-pruefung/LIESMICH.md
- .vault-tools/trading-plattform-pruefung/abendkontrolle.py
Erzeugt vom PostToolUse-Hook .vault-tools/auto-push/auto_push.py.
Co-Authored-By: Claude Opus 5 <[email protected]>
Trading Plattform: Prüfwerkzeuge des Koordinators fürs Dashboard
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.
vault-tools
trading-plattform
2026-09-17
2026-10-08
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)
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
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)
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
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
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
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 PaperSitzungen 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 seit --seit unter dem Thema der Maschine ankam (Vorgabe 12h; auch Berliner Ortszeit JJJJ-MM-TTTHH:MM) — Zeit in Berliner Zeit, Priorität, Titel und erste Zeile, darin jede Ziffernfolge als #. Schickt nichts und gibt das Thema nie aus, auch nicht in einer Fehlermeldung. Setzt TRADING_GEHEIMNISSE selbst, wenn die Variable fehlt. Exit 3 ohne Thema oder Geheimnisdatei, Exit 4 bei Weiterleitung oder Fehlerstatus (einer Weiterleitung folgt es nie, sonst ginge das Token mit). ntfy.sh hält Meldungen nur Stunden: Am 2026-10-08 um 14 Uhr war die Meldung von 22:36 am Vortag schon weg
aus dem Projektordner oder einem Arbeitsbaum in WSL: python -B ntfy_lesen.py --seit 12h
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
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
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
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
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
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 : 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
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.38.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
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
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).
Paket AB (2026-10-07): Abbau des Restbestands nach dem Netzschalter-Abriss
Am 2026-10-07 um 20:13 beendete ein Druck auf den Netzschalter beide Paper-Runner mitten im Handel, ohne Glattstellen. Pascal am selben Abend: am 2026-10-08 soweit es geht alles verkaufen, Testläufe bis Dienstag gestoppt. Die Zeitgeber trading-paper.timer und trading-paper-ibkr.timer sind seitdem aus, die Abendkontrolle ebenfalls; die Meldung dieses Werkzeugs ist in der Pause das einzige Netz. Plan im Projekt: docs/plans/2026-10-07-paket-ab-abbau-restbestand/.
Datei
Was sie tut
Aufruf
abbau_restbestand.py
Windows-Seite. Im Modus scharf nur zwischen 2026-10-08 15:40 und 2026-10-09 21:45: Runner-Units über systemctl show (nur LoadState=loaded mit inactive oder failed gilt als stehend), Marktuhr, beide Bestände; je Instanz mit Position oder offener Order genau ein Glattstellen über abbau_glattstellen.sh; nach 30 s beide Bestände neu; Ergebnis in data/paper/abbau/abbau.json und abbau.log im Projekt, mit "flach": true enden alle späteren Läufe still; bei Eingriff, Befund oder dem ersten "flach" eine Zeile in der Tagesnotiz und eine Meldung mit hoher Priorität. Fail-closed: laufender oder nicht geladener Runner, unlesbarer Zustand, unlesbare Marktuhr oder unlesbarer Bestand heißt nicht angefasst, mit Befund; Markt zu oder weniger als 10 min bis Schluss heißt nichts, ohne Meldung. wsl() setzt WSL_UTF8=1 und entfernt NUL; Befunde aus Ausnahmen nennen nur den Typ, der Traceback steht nur in abbau.log. --modus lesen fährt nur die lesenden Aufrufe, auch außerhalb des Fensters, und schreibt nichts; ohne --modus Exit 2
python abbau_restbestand.py --modus lesen; scharf nur über die Aufgabe
abbau_glattstellen.sh
WSL. Liest das Bestätigungswort aus config/killswitch.toml der Instanz, wählt den Broker ausdrücklich (--broker alpaca oder --broker ibkr) und ruft genau einmal scripts/killswitch.py glattstellen im Instanzordner mit deren Venv. Die Ausgabe geht durch einen Filter: das Wort wird [wort], dann ohne_kontonummer() (Kontonummern als [konto], dann maskiere()), dann jede Dezimalzahl [x]. Kennt keinen echten Ordner, der Aufrufer nennt ihn. --broker attrappe ersetzt die Wahl, nur für die Probe in einer Wegwerfkopie
bash abbau_glattstellen.sh <instanz> <instanzordner> [--broker attrappe] in WSL, Instanz alpaca oder ibkr
abbau_alpaca_lesen.py
WSL, Venv ~/venvs/trading: Marktuhr, Positionen (nur Symbol und Stück) und Zahl der offenen Orders des Alpaca-Kontos als eine JSON-Zeile; Fehlertexte durch ohne_kontonummer() und die Dezimalmaske
nur über abbau_restbestand.py; von Hand python abbau_alpaca_lesen.py --projekt <alpaca-ordner>
abbau_ibkr_lesen.sh
WSL: scripts/ibkr_pruefen.py lesen im IBKR-Ordner mit ~/venvs/trading-ibkr (Client-ID 12, lesend), nie orderweg
nur über abbau_restbestand.py
abbau_restbestand_angriffe.py
Angriffsfälle als Funktionen test_*, lauffähig als Skript und unter pytest (für mutanten_lauf.py). Abgedichtet: alle Pfade nach draußen zeigen ins Leere, wsl() ist durch eine zählende Attrappe ersetzt, im Fall zu wsl() selbst auch subprocess.run. Die Fälle test_wsl_* fahren den echten Wrapper und die Venvs gegen Wegwerf-Instanzordner mit falschem killswitch.py, erfundenem Wort, erfundener Kontonummer und erfundenen Beträgen; unter Windows übersprungen
unter Windows python -I -X utf8 abbau_restbestand_angriffe.py, in WSL ~/venvs/trading/bin/python -I abbau_restbestand_angriffe.py; Mutanten: mutanten.toml im Planordner
abbau_restbestand_einrichten.ps1
Aufgabe "Trading Plattform - Abbau Restbestand": Do 2026-10-08 15:45, 16:15, 17:00, 19:00, 21:00, Ersatz Fr 2026-10-09 15:45, 16:30, 19:00 und fünf Minuten nach jeder Anmeldung; nur angemeldet, Zeitlimit 45 min, keine zweite Instanz; druckt nach dem Registrieren die Einstellungen
Was es nicht tut: Es gibt keinen Killswitch frei. Jede angefasste Instanz steht danach auf gesperrt, Freigeben bleibt Pascal (scripts/killswitch.py freigeben). Es hat keinen eigenen Ordercode und keine Sperrdatei gegen einen zweiten Lauf von Hand; die Aufgabe selbst startet keine zweite Instanz. Während des Aufrufs steht das Wort in WSL in der Prozessliste von killswitch.py, dessen Schnittstelle es als Argument nimmt. Ob wsl.exe --exec eine Meldung mit Leerzeichen so weitergibt wie ein Skript mit Argumenten, war vor dem ersten scharfen Lauf nicht gemessen; was die Meldung ergab, steht in der Notizzeile unter "Meldung ans Telefon". Nach dem 2026-10-09 wird die Aufgabe mit -Aktion entfernen abgebaut.