Automatischer Push: 2 Datei(en) geändert

- .vault-tools/trading-plattform-pruefung/LIESMICH.md
- .vault-tools/trading-plattform-pruefung/ntfy_lesen.py

Erzeugt vom PostToolUse-Hook .vault-tools/auto-push/auto_push.py.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Pascal MichelandClaude Opus 5 committed 2026-10-09 04:00:01 +02:00
1 parent 3784322a76
commit fca08de1c5
2 files changed
+67 -12

No files matched your search

@@ -49,7 +49,7 @@ Koordinator-Werkzeuge, nicht fürs Repo. Sie starten **nie** den echten Broker:
| `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` | | `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>` | | `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>` | | `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` | | `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 | `powershell -File wiederanlauf_probe.ps1 -Ausfuehren` | | `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 ## Paket H (2026-09-21): Kennzahlen nach Home Assistant
@@ -1,36 +1,90 @@
"""Liest nur zurueck, was in der letzten Stunde bei ntfy unter dem Thema der Maschine ankam. """Liest zurueck, was bei ntfy unter dem Thema der Maschine ankam, mit maskierten Ziffern.
Koordinator-Skript, nicht Teil des Repos. Schickt nichts. Das Thema wird nie ausgegeben -- weder Koordinator-Skript, nicht Teil des Repos. Schickt nichts. Das Thema wird nie ausgegeben -- weder
hier noch in einer Fehlermeldung. Aufruf aus dem Projektordner (WSL): python ntfy_lesen.py hier noch in einer Fehlermeldung. Aufruf aus dem Projektordner (WSL):
python -B ntfy_lesen.py [--seit 12h | --seit 2026-10-07T20:00]
Exit 0 gelesen, 1 Netzfehler, 3 kein Thema, 4 Weiterleitung oder Fehlerstatus.
""" """
import argparse
import json import json
import os
import re
import sys import sys
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from zoneinfo import ZoneInfo
sys.path.insert(0, str(Path.cwd())) sys.path.insert(0, str(Path.cwd()))
# Ohne Login-Shell fehlt die Variable (LIESMICH, Abschnitt zu den Geheimnissen); der Pfad selbst
# ist kein Geheimnis, sein Inhalt schon.
os.environ.setdefault("TRADING_GEHEIMNISSE", "/home/claude/.config/trading-plattform/secrets.toml")
import requests import requests
from trading import geheimnisse
from trading.paper.melder import lade_melder_config from trading.paper.melder import lade_melder_config
from trading.paper.melder import lies_ntfy_geheimnisse from trading.paper.melder import lies_ntfy_geheimnisse
BERLIN = ZoneInfo("Europe/Berlin")
# ntfy nimmt fuer since eine Dauer (12h, 30m) oder einen Unix-Zeitstempel (docs.ntfy.sh/subscribe/api).
DAUER = re.compile(r"^\d+[smhd]$")
def main() -> int:
config = lade_melder_config("config/paper.toml", secrets_pfad=None) def seit_parameter(wert: str) -> str:
thema, token = lies_ntfy_geheimnisse() """Eine Dauer bleibt, wie sie ist; eine Ortszeit ohne Zone gilt als Berliner Zeit."""
if DAUER.match(wert):
return wert
zeit = datetime.fromisoformat(wert)
if zeit.tzinfo is None:
zeit = zeit.replace(tzinfo=BERLIN)
return str(int(zeit.timestamp()))
def maskiert(text: object) -> str:
"""Jede Ziffernfolge als #, weil eine Meldung einen Betrag tragen kann."""
return re.sub(r"\d+", "#", str(text))
def main(argv: list[str] | None = None) -> int:
teiler = argparse.ArgumentParser(description="ntfy zuruecklesen, ohne das Thema zu zeigen.")
teiler.add_argument(
"--seit", default="12h",
help="Dauer wie 12h oder Berliner Ortszeit JJJJ-MM-TTTHH:MM; ntfy.sh haelt Meldungen nur Stunden.",
)
args = teiler.parse_args(argv)
try:
seit = seit_parameter(args.seit)
except ValueError:
print(f"--seit nicht lesbar: {args.seit}")
return 2
try:
# Beide lesen die Geheimnisdatei; fehlt sie, wirft schon die Konfiguration.
config = lade_melder_config("config/paper.toml", secrets_pfad=None)
thema, token = lies_ntfy_geheimnisse()
except OSError as ausnahme:
print(f"Geheimnisdatei nicht lesbar ({type(ausnahme).__name__}): {geheimnisse.beschreibung()}")
return 3
if not thema:
# Mit leerem Thema hiesse die Adresse .../json; genau das endete am 2026-10-07 mit HTTP 307.
print(f"Kein Thema in der Geheimnisdatei: {geheimnisse.beschreibung()}")
return 3
kopf = {"Authorization": f"Bearer {token}"} if token else {} kopf = {"Authorization": f"Bearer {token}"} if token else {}
try: try:
antwort = requests.get( antwort = requests.get(
f"{config.ntfy_url}/{thema}/json", params={"poll": "1", "since": "1h"}, f"{config.ntfy_url}/{thema}/json", params={"poll": "1", "since": seit},
headers=kopf, timeout=10, allow_redirects=False, headers=kopf, timeout=10, allow_redirects=False,
) )
except Exception as ausnahme: except Exception as ausnahme:
# Nur der Typ: Die Ausnahme von requests traegt die Adresse und damit das Thema. # Nur der Typ: Die Ausnahme von requests traegt die Adresse und damit das Thema.
print(f"Ruecklesen gescheitert: {type(ausnahme).__name__}") print(f"Ruecklesen gescheitert: {type(ausnahme).__name__}")
return 1 return 1
print(f"Ruecklesen: HTTP {antwort.status_code}") print(f"Ruecklesen seit {args.seit}: HTTP {antwort.status_code}")
if antwort.status_code >= 300:
# Einer Weiterleitung folgen hiesse, das Token an ein anderes Ziel zu schicken.
print("Kein Ergebnis: Weiterleitung oder Fehlerstatus, nicht gefolgt.")
return 4
anzahl = 0 anzahl = 0
for zeile in antwort.text.splitlines(): for zeile in antwort.text.splitlines():
try: try:
@@ -40,11 +94,12 @@ def main() -> int:
if eintrag.get("event") != "message": if eintrag.get("event") != "message":
continue continue
anzahl += 1 anzahl += 1
zeit = datetime.fromtimestamp(eintrag.get("time", 0), BERLIN).strftime("%Y-%m-%d %H:%M:%S")
erste = (str(eintrag.get("message", "")).splitlines() or [""])[0]
# Ohne Angabe fuehrt ntfy die Prioritaet 3 (default) und laesst das Feld weg. # Ohne Angabe fuehrt ntfy die Prioritaet 3 (default) und laesst das Feld weg.
print(f" bei ntfy: Titel '{eintrag.get('title')}', Prioritaet {eintrag.get('priority', 3)}, " print(f" {zeit} Prioritaet {eintrag.get('priority', 3)} Titel '{maskiert(eintrag.get('title'))}' "
f"Zeit {datetime.fromtimestamp(eintrag.get('time', 0)).isoformat()}, " f"erste Zeile '{maskiert(erste)[:70]}'")
f"erste Zeile '{str(eintrag.get('message', '')).splitlines()[0][:70]}'") print(f"{anzahl} Meldung(en).")
print(f"{anzahl} Meldung(en) in der letzten Stunde.")
return 0 return 0