Nach Web-Recherche zum 2026er-Python-Standard umgesetzt, aber gefiltert: von
uv/Ruff/pyproject/CI passt hier nur, was zu einer Einzelmaschine mit
GUI-gebundenem MT5 und Live-Geld passt.
(1) requirements.txt (Laufzeit) + requirements-dev.txt (Werkzeuge/Messung),
Versionen gepinnt. Bis dahin gab es GAR KEINE Liste — nach einem
Maschinenausfall waere die Rekonstruktion Raten gewesen. Per AST ueber
core/, server.py, tools/ ermittelt statt geraten.
(2) tools/pre_commit.py faehrt vor jedem Commit check_nfalle + pytest (~5 s).
Einrichten: python tools/pre_commit.py --install. Notausgang
'git commit --no-verify' ist Absicht.
Bewusst OHNE das pre-commit-Framework: dessen Nutzen ist
Werkzeug-Versionierung ueber mehrere Maschinen. Hier gibt es eine, und es
wuerde eine ZWEITE ruff-Version in einer isolierten Umgebung installieren —
genau die Divergenz 'Pruefumgebung != Laufumgebung', die heute schon einmal
zugeschlagen hat.
(3) Ruff statt pyflakes (--select F821), ganzer Scan in 2,1 s. KEIN
ruff format — das wuerde 161 Dateien umformatieren, darunter alle
Backtests, und die Migrations-Regel verletzen.
⚠ VIERTER Fall der Klasse 'Erfolg melden, wo nichts geprueft wurde', und nur
durch den Test aufgefallen: --select F821,E999 laesst ruff 0.16 komplett
abbrechen (E999 wurde entfernt, Exit 2); die Meldung geht nach stderr, und weil
ich den Rueckgabecode nicht pruefte, meldete die Stufe 'keine undefinierten
Namen' — ohne irgendetwas geprueft zu haben. Ein absichtlich eingebauter
F821-Fehler kam glatt durch den Hook. Behoben: nur F821, und Exit 2 loest jetzt
den pyflakes-Rueckfall aus.
Beide Richtungen verifiziert: mit Fehler stoppt der Hook den Commit, ohne ist
er gruen. Der Test-Commit wurde zurueckgenommen (war nur lokal, ahead 1).
Nicht umgesetzt: Gitea Actions (Runner auf derselben Maschine wie der Live-Bot,
kein Mehrwert bei 5 s Pruefzeit), Container/Blue-Green (MT5 braucht eine
Desktop-Sitzung, EINE Broker-Verbindung), mypy/ty (kaum Annotationen).
Struktureller Fund: core/engine.py importiert backtest_breakout_squeeze — ein
Backtest ist Teil des LIVE-Abhaengigkeitsgraphen.
Endstand verifiziert: AutoAdminLogon=1, DefaultUserName=ah,
DefaultDomainName=HOMEBASE, Aufgabe OilAutoLogonLock Bereit und auf
autologon_lock.ps1 zeigend. Die Boot-Luecke ist damit konfiguratorisch
geschlossen.
⚠ Der SICHERE Weg hat nicht funktioniert: Sysinternals Autologon beendete sich
mit ExitCode 0, schrieb aber nichts — weder ueber den Dialog noch ueber die
Argument-Form. Ausgeschlossen: DevicePasswordLessBuildVersion (nicht gesetzt),
fehlende Elevation, haengender Prozess. Ursache ungeklaert. Aktiv ist deshalb
der Registry-Weg, und damit steht das Passwort im KLARTEXT unter
HKLM\...\Winlogon\DefaultPassword — lesbar fuer jeden lokalen Admin und jedes
Backup-Image. Entfernen-Kommando in CLAUDE.md.
⚠ Dritter Fall derselben Fehlerklasse in diesem Skript, jetzt behoben: die
Speicherart wurde aus einer stale Variable gelesen, die VOR dem
Registry-Schreiben gefuellt war. Die Ausgabe widersprach sich direkt — erst
korrekt 'steht jetzt im KLARTEXT', zwei Zeilen spaeter 'nicht im Klartext ✅'.
Der Zustand wird jetzt nach jedem Schreibvorgang frisch gelesen.
Lehre aus allen drei Faellen: eine Erfolgsmeldung muss den Zustand NACH der
Aktion pruefen, nicht den davor.
Offen: die Wirkung ist erst beim naechsten Reboot belegt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zwei Fehler in meinem Direkt-Zweig, beide behoben:
(a) '& $exe ...' WARTET bei GUI-Anwendungen NICHT — das Skript las die
Registry, bevor Autologon fertig war. Jetzt Start-Process -Wait -PassThru.
(b) '$null = ... 2>&1' hat die Rueckmeldung verschluckt — genau die
Information, die zur Diagnose noetig war, wurde weggeworfen. Jetzt werden
ExitCode und Ausgabe gezeigt.
Zusaetzlich diagnostiziert: Autologon64.exe startet nur elevated (direkter
Aufruf aus einer normalen Sitzung scheitert mit 'erfordert erhoehte Rechte').
Der Windows-11-Blocker DevicePasswordLessBuildVersion ist NICHT gesetzt, war
also nicht die Ursache.
Neu als letzter Ausweg: der Registry-Weg, aber nur nach ausdruecklicher
Zustimmung und mit klarer Warnung — dort landet das Passwort im KLARTEXT unter
HKLM\...\Winlogon\DefaultPassword. Er funktioniert dafuer immer. Die
Entscheidung gehoert dem Nutzer, nicht dem Skript; das Entfernen-Kommando wird
gleich mit ausgegeben.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Dialog-Weg ist zweimal ohne Ergebnis geblieben, weil er mit ENABLE
bestaetigt werden muss. Statt den Nutzer ein drittes Mal tippen zu lassen,
bietet das Skript nach einem abgebrochenen Dialog jetzt direkt an, es ohne
Dialog zu erledigen (j/n) — die Aktivierung steckt dafuer in einer Funktion,
die von beiden Wegen aufgerufen wird.
Ausserdem ehrlicher in der Fehlerursache: ein falsches Passwort meldet
Autologon nicht zurueck, das Ergebnis sieht dann genauso aus wie ein
abgebrochener Dialog. Beides wird jetzt genannt statt nur eines.
Mit dem echten 5.1-Parser geprueft, BOM gesetzt, Scan sauber.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der GUI-Weg fuehrte zweimal zu nichts. Diagnostiziert: der Dialog OEFFNET sich
(Fenstertitel 'Autologon - Sysinternals', Prozess verifiziert), muss aber mit
ENABLE bestaetigt werden — nur schliessen tut nichts.
Neu: -Direkt. Autologon 3.10 nimmt Benutzer/Domaene/Passwort als Argumente;
das Skript fragt es per Read-Host -AsSecureString ab (unsichtbar, nicht in der
History) und ruft ohne Dialog auf. Schlaegt es fehl, nennt das Skript jetzt den
wahrscheinlichen Grund je nach Weg (Dialog nicht bestaetigt vs. falsches
Passwort).
Abwaegung dokumentiert: bei -Direkt steht das Passwort fuer den Moment des
Aufrufs in der Kommandozeile des Kindprozesses (fuer Admins kurz sichtbar). Es
landet nicht in einer Datei, nicht in der Shell-History — und anschliessend als
verschluesseltes LSA-Secret statt im Klartext in der Registry.
Mit dem echten 5.1-Parser geprueft (0 Fehler), -Direkt als Parameter erkannt,
BOM gesetzt, n-Falle-Scan sauber.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der erste Lauf hat NICHTS eingerichtet — weder Auto-Logon noch die
Sperr-Aufgabe. Nachgeprueft: AutoAdminLogon, DefaultUserName und
OilAutoLogonLock allesamt nicht vorhanden.
(1) $ErrorActionPreference = 'Stop' PLUS schtasks /Delete auf eine noch nicht
existierende Aufgabe: native Programme schreiben nach stderr, PowerShell
macht daraus unter 'Stop' einen Abbruch. Das Skript endete, BEVOR /Create
lief. Jetzt wird vorher per /Query geprueft.
(2) Die Erfolgsmeldung log: ein fehlendes DefaultPassword wurde als
"LSA-Secret ✅" ausgegeben — dabei war gar nichts gesetzt, weil der
Autologon-Dialog ohne Enable geschlossen wurde. Abwesenheit eines
Klartext-Passworts beweist nicht, dass der sichere Weg genommen wurde; sie
ist auch mit "nichts passiert" vereinbar. Jetzt ist AutoAdminLogon = 1 die
Bedingung, und erst danach wird ueber die Speicherart geurteilt. Ohne
aktives Auto-Logon bricht das Skript mit Code 1 ab und ueberspringt
Schritt 2.
Dazu ein Design-Fehler, der erst beim Nachdenken auffiel: die Sperre haette bei
JEDER Anmeldung gefeuert — ein ONLOGON-Trigger unterscheidet nicht zwischen
Auto-Logon und manuellem Login. 30 s nach jedem normalen Anmelden waere der
Bildschirm zugefallen. Neu: tools/autologon_lock.ps1 prueft die Systemlaufzeit
und sperrt nur, wenn der Rechner < 3 min laeuft (= Auto-Logon nach Boot).
Trocken getestet: bei 1088 min Laufzeit -> sperrt nicht.
Beide .ps1 mit BOM geschrieben und mit dem echten 5.1-Parser gegengeprueft
(0 Fehler). check_nfalle.py Stufe C2 deckt alle drei Skripte ab.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Das Skript liess sich nicht ausfuehren — "Schliessende ) fehlt",
"Zeichenfolge hat kein Abschlusszeichen". Es war KEIN Syntaxfehler:
Windows PowerShell 5.1 liest .ps1 als CP1252, wenn kein BOM da ist. Aus dem
Gedankenstrich werden drei Zeichen, das darin enthaltene Anfuehrungszeichen
schliesst den String vorzeitig, und der Fehler kaskadiert bis zum Dateiende.
Der eigentliche Punkt ist, warum es beim Schreiben nicht auffiel: das hiesige
PowerShell-Werkzeug ist pwsh 7, und das liest UTF-8 ohne BOM klaglos. Die Datei
war in meiner Umgebung fehlerfrei und beim Nutzer kaputt — dieselbe
Divergenz-Klasse wie der Deployment-Drift, nur eine Ebene tiefer: die
Pruefumgebung war nicht die Laufumgebung.
Behoben (UTF-8 MIT BOM) und mit dem ECHTEN 5.1-Parser gegengeprueft
(Parser::ParseFile, 0 Fehler) — nicht mit pwsh 7, das den Fehler ja gerade
nicht zeigt.
Dabei ein zweiter Fall gefunden und mitbehoben: scripts/send_daily_report.ps1
(Umlaute, kein BOM). Der ist zwar dormant (Microsoft.Graph-Modul fehlt), haette
aber genauso gebrochen.
Dauerhaft abgesichert: tools/check_nfalle.py prueft es als Stufe C2 —
.ps1 mit Nicht-ASCII und ohne BOM ist ab jetzt ein Befund.
.bat ist nicht betroffen: cmd.exe verzeiht das in echo/Kommentaren
(restart_server.bat enthaelt Sonderzeichen, bricht aber nicht).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Schliesst die letzte Luecke der Boot-Pipeline: OilTradingServer und
HyperliquidDashboard haengen an einem Logon-Trigger, nach einem Update-Reboot
laeuft nichts bis zur Anmeldung (real 20.07.: Reboot 01:30, Server bis 07:42
tot, -95,48 EUR).
Ein Task "ohne angemeldete Sitzung" hilft NICHT: der Bot braucht das laufende
MT5-Terminal, und das ist eine GUI-Anwendung — es braucht eine echte
Desktop-Sitzung. Auto-Logon ist hier also das richtige Mittel, nicht nur das
bequeme.
BEWUSST NICHT der Registry-Weg: der legt das Passwort als DefaultPassword im
KLARTEXT unter HKLM\...\Winlogon ab, lesbar fuer jeden lokalen Admin und in
jedem Backup-Image. Stattdessen Sysinternals Autologon — verschluesseltes
LSA-Secret. Die EXE ist Microsoft-signiert (Signatur geprueft: Status Valid).
Das Skript verifiziert danach, dass DefaultPassword NICHT im Klartext steht.
Das eigentliche Restrisiko ist nicht das Passwort, sondern die offene Sitzung:
nach dem Reboot steht ein angemeldeter Desktop mit MT5 und Live-Broker-
Verbindung da. Deshalb legt das Skript zusaetzlich die Aufgabe
OilAutoLogonLock an — 30 s nach Anmeldung LockWorkStation. Die Sitzung laeuft
weiter (MT5 und beide Server arbeiten), der Bildschirm ist gesperrt.
NICHT ABGESCHLOSSEN: HKLM ist aus einer normalen Sitzung nicht schreibbar
(getestet: "Requested registry access is not allowed"). Der letzte Schritt
braucht ein Administrator-Fenster.
Das Passwort steht NICHT im Skript, nicht in der Doku und nicht im Repo — es
wird im Autologon-Dialog eingegeben. tools/autologon/ ist gitignored (Binaries,
gleiche Regel wie tools/piper/).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ersetzt das von Hand zusammengesetzte "killen, starten, warten, nachsehen" —
und macht die dokumentierte Schwachstelle der Pipeline pruefbar.
Fuenf Schritte, Rueckgabecode 0 nur wenn alle durchlaufen (verkettbar):
1. Prozess GEZIELT AM PORT beenden — nicht per *server.py*-Muster wie
restart_server.bat, das trifft auch das HL-Dashboard auf 8001 (real: es
wurde bei jedem MT5-Neustart still mit-erschlagen und riss die Luecken in
die Lead-Lag- und Order-Flow-Datensammlung).
2. starten und warten, bis /api/snapshot WIRKLICH antwortet.
3. genau EINE Instanz je Port.
4. --feld <name> pruefen.
5. Log AB DER STARTPOSITION auf ERROR/Traceback.
Schritt 4 ist der Kern: restart_server.bat hat zweimal still nicht neu
gestartet, und weil statische Dateien je Request frisch von der Platte gelesen
werden, belegt eine korrekt ausgelieferte app.js?v=N gar nichts ueber den
geladenen Python-Code. Ein neues Snapshot-Feld ist der einzige belastbare
Beweis — genau daran fiel der Fehler am 02.08. auf (hl_live.basis_stale). Ohne
--feld sagt das Skript ausdruecklich, dass der Beweis fehlt.
Beide Richtungen geprueft:
--feld rec_track -> "Python-Code ist neu", Exit 0
--feld dieses_feld_gibt_es_nicht -> "FEHLT - der alte Code laeuft weiter!",
Exit 1
Eine Pruefung, die nicht scheitern kann, waere wertlos.
Aufrufe:
python tools/deploy.py --feld <snapshot_feld>
python tools/deploy.py --nur-pruefen
python tools/deploy.py --hl
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Auf die Frage nach einem Lint-Modul: pyflakes installiert und als Stufe A2 in
tools/check_nfalle.py eingebunden. py_compile prueft nur die SYNTAX; ein
Tippfehler in einem NAMEN ist syntaktisch einwandfrei — und dieses Projekt hat
sehr viele breite except-Exception-Bloecke, in denen ein NameError unsichtbar
bleibt.
Beim ERSTEN Lauf zwei echte Fehler, beide in core/trader.py, beide nutzten
log. (den Namen gibt es dort nicht, nur log_trade/log_hist):
· _broker_offset_s(): der NameError lief in das except-pass UND nahm die
darunter stehende Zuweisung self._boff = int(off) mit -> ein echter
Broker-Zeitzonen-Wechsel waere nie uebernommen worden, dauerhaft und
lautlos. Ausgerechnet der Zweig, der als Deployment-Drift Fall 4 gebaut
wurde (falscher Offset -> Time-Stop-Alter negativ).
· modify_sltp(): steht NICHT in einem try -> der Fehler lief bis in
/api/sltp. Der Broker hatte SL/TP bereits geaendert, der User bekam trotzdem
eine Fehlermeldung, und set_sltp kam nie bis trail.deactivate() — das
Trailing blieb an und haette die Handeingabe zurueckgezogen. Seit dem
Initial-Commit drin.
Beide behoben (log_trade). Zusaetzlich die Annotation 'HistoryLogger | None'
ueber if TYPE_CHECKING sauber importiert (String-Annotation, kein
Laufzeit-Import, kein Zirkel). Projektweit jetzt 0 undefinierte Namen.
Schweregrad-Trennung ist Absicht: nur undefined name / syntax error werden
gemeldet, die ~105 kosmetischen Hinweise unterdrueckt. Auch
'redefinition of unused' bleibt draussen — es trifft das legitime Muster
hook = None + bedingtes def hook (in zwei Backtests geprueft, beide korrekt).
Eine Pruefung mit Dauer-Treffern wird ignoriert, und mit ihr die eine echte.
Backtest-Dateien nicht angefasst (Zahlen). Neustart verifiziert, Log sauber.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Auftrag "ueberpruefe alle dateien auf \n-Falle". Die Falle: ueber ein
Shell-Heredoc geschriebener Code macht aus einem gemeinten \n einen ECHTEN
Zeilenumbruch mitten im String-Literal. Heute zweimal passiert (Telegram-Text
in engine.py, Reminder-Eintrag in measurement_reminder.py).
Der Scan prueft in beide Richtungen:
A) kompiliert alle .py (161 Dateien) — sauber
B) JS: unabgeschlossene String-Literale — app.js sauber
C) UMGEKEHRT: literales \n als sichtbarer Text in HTML-title= und Markdown
— alle sauber
D) Signatur der beiden heutigen Faelle (Zeile endet offen, naechste besteht
nur aus einem Quote) — keine
⚠ Fehlalarm im Scanner selbst gefunden und behoben: Quotes zu ZAEHLEN meldet
'"' als offenes Literal (gueltiges JS mit einem Anfuehrungszeichen darin, real
in app.js). Der Scan verfolgt jetzt zeichenweise den AKTIVEN Quote-Typ.
Die betroffene app.js-Stelle trotzdem aufgeraeumt: schliessendes
Anfuehrungszeichen jetzt als U+201C statt ueber eine Konkatenation mit '"'.
Regel in CLAUDE.md ergaenzt: mehrzeilige Strings mit \n nicht per Heredoc
schreiben, sondern ueber den Edit-Weg.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
· Modul-Chips: neues `used`-Flag in _verdict.add(). used=False = dauerhaft
entmachtet (Elliott, Orderbuch — beide heute gemessen ohne Inhalt), das
Frontend filtert sie aus. ⚠ Sie bleiben im Snapshot und in verdict_votes:
log_verdict_votes speist daraus die Telemetrie und die 25.000-Verdict-Messung
braucht die Reihe weiter. Ausgeblendet wird die Anzeige, nicht die Messung.
Module mit weight=0 aus SITUATIVER Stille (Welle bei WARTEN, Squeeze ohne
Ausbruch) bleiben sichtbar.
· #vd-note (Muenzwurf-Hinweistext) entfernt, samt CSS. Die Aussage steht
weiter im Karten-Tooltip.
· Tooltips auf allen Dashboard-Anzeigen (59 title-Attribute): Karten,
Header-Boxen, Trade-Leiste, Anzeige-Elemente. Wo eine Messung existiert,
steht sie drin. Gesetzt ueber set_tooltips.py — idempotent, ergaenzt nur
fehlende title=.
Verifiziert: keine Anzeige mehr ohne Tooltip, keine doppelten IDs, Tag-Balance
ok, v=147 ausgeliefert, Elliott/Orderbuch used=False, eine Instanz auf 8000.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
EINSATZ-FELD (User-Wunsch): Laufzeitwert MANUAL_MARGIN in core/config.py
(set/get_manual_margin, Muster wie set_margin_buffer). 0 = automatisch wie bisher
(margin_buffer_pct % der freien Margin), > 0 = Position wird auf genau diesen
Margin-Einsatz gerechnet.
- calc_lots setzt es um und DECKELT auf freie Margin x Buffer; ein zu hoher
Wunschwert wird begrenzt und geloggt statt an den Broker durchgereicht. Reicht
der Betrag nicht fuers Mindestlot -> 0.0 + Warnung, Trade sauber abgelehnt.
- Vorrang vor dem Risiko-Modus in trader._send_locked: eine ausdrueckliche
Groessenvorgabe schlaegt die Rechenregel.
- Wirkt auf ALLE neuen Positionen, auch die autonomen.
- UI-Feld "Einsatz" in der ORDER-Leiste (nicht in der Trade-Leiste: die ist nur
bei offener Position sichtbar, der Einsatz muss vorher einstellbar sein),
bernstein umrandet solange gesetzt. Enter blurrt nur, change sendet einmal.
- POST /api/manualmargin, Snapshot manual_margin, neustart-fest ueber
runtime_state.json. Ende-zu-Ende getestet (250 -> Snapshot -> 0 -> persistiert).
- Lot-Logik isoliert geprueft: 200 EUR -> 0,58 Lots; 5000 EUR -> gedeckelt.
SPRACHAUSGABE: Piper lokal (tools/speak.py). Windows-TTS funktioniert zwar, aber
es ist KEINE deutsche Stimme installiert - weder SAPI5 noch OneCore (nur
David/Zira/Mark, en-US); deutscher Text kaeme mit englischer Aussprache.
Add-WindowsCapability scheitert ohne Adminrechte.
Piper gewaehlt: laeuft lokal (passt zum Rest - WireGuard-only, Secrets in der
ini, keine Cloud), kostet nichts, aus PowerShell/Python aufrufbar. Stimme
thorsten-medium (de_DE), Real-Time-Faktor 0,08 (4,3 s Audio in 0,36 s).
Das ZIP entpackt eine Ebene tiefer als erwartet (tools/piper/piper/piper.exe) -
speak.py SUCHT Binary und Modell statt Pfade fest zu verdrahten. Der erste
Entwurf scheiterte daran; der Fail-safe meldete die Pfade sauber statt stumm zu
bleiben. Drei Modi getestet (Argument, Pipe, --wav).
tools/piper/ ist gitignored (Binaries + 60-MB-Modell), speak.py versioniert.
v=136.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>