Training über das Dashboard anstoßen

Neuer Abschnitt "Training" im Dashboard mit zwei Bedienelementen und den
zugehörigen Endpunkten /control/train/history, /control/train/live und
/control/training.

Historisches Nachtraining
- Kerzenanzahl je Symbol wählbar (500 bis 50 000), Fortschritt und Ergebnis
  werden im Dashboard angezeigt.
- Läuft mit derselben Logik wie ein Backtest, aber ohne zu handeln, und
  speichert das Modell anschließend.
- Handelsdurchlauf und Nachtraining teilen sich einen Mutex, damit sie nicht
  gleichzeitig auf Modell und Portfolio zugreifen. Die rechenintensive Schleife
  läuft in einem Worker-Thread, damit der Status-Server antwortbereit bleibt.
- Ein zweiter Start wird abgelehnt, solange einer eingereiht ist oder läuft.

Kontinuierliches Lernen
- Schalter für das Online-Lernen im laufenden Betrieb. Ausgeschaltet handelt der
  Bot weiter, verändert das Modell aber nicht mehr.

Label-Trennung
- Vorgemerkte Labels tragen jetzt ein Tag. Ein Nachtraining darf die offenen
  Labels des Live-Betriebs weder auflösen noch verwerfen; ohne die Trennung
  würden sie gegen historische Kurse ausgewertet und das Modell mit falschen
  Ergebnissen gefüttert.
- score() liest die Gewichte unter dem Lock, damit ein parallel laufendes
  Training keinen halb aktualisierten Vektor sichtbar macht.

Absicherung
- server.control_token (TRADEMIND_CONTROL_TOKEN) schützt alle Steuerbefehle über
  den Header X-TradeMind-Token; lesende Endpunkte bleiben offen. Ohne Token warnt
  der Bot beim Start, wenn der Port nicht nur lokal erreichbar ist.
- server.enable_control: false entfernt die Routen vollständig.

153 Tests (25 neue), ruff sauber. Im gebauten Container geprüft: 202/409 beim
Anstoßen, 401 ohne und mit falschem Token, +1099 Beobachtungen in 4,3 s bei
weiterlaufendem Handels-Loop ohne Fehler.
This commit is contained in:
Tobias Zimmermann
2026-08-23 12:15:28 +02:00
parent 35d5c64e5b
commit 3cd12b67aa
11 changed files with 933 additions and 69 deletions
+54 -4
View File
@@ -64,9 +64,11 @@ podman-compose down # stoppen
Port 8080 wird auf allen Interfaces veröffentlicht — das Dashboard ist damit standardmäßig
von anderen Rechnern erreichbar.
> **Sicherheit.** Alle Endpunkte sind lesend (`GET`, keine Steuerbefehle), aber **nicht
> authentifiziert**. Wer den Port erreicht, sieht Kontostand, offene Positionen und die
> gesamte Trade-Historie. In offenen Netzen deshalb entweder einen Reverse Proxy mit
> **Sicherheit.** Die lesenden Endpunkte sind **nicht authentifiziert** — wer den Port
> erreicht, sieht Kontostand, offene Positionen und die gesamte Trade-Historie. Dazu kommen
> die Steuerbefehle unter `/control/…` (Training anstoßen, Lernen umschalten), die sich mit
> `server.control_token` schützen lassen und das auch sollten. Gehandelt oder konfiguriert
> werden kann über HTTP in keinem Fall. In offenen Netzen deshalb einen Reverse Proxy mit
> Authentifizierung davorsetzen, den Zugriff per Firewall auf bekannte Quell-IPs begrenzen
> oder auf rein lokalen Zugriff zurückstellen:
>
@@ -220,6 +222,9 @@ Modell ist untrainiert lerne aus bis zu 3000 historischen Kerzen vor …
Vorlernen abgeschlossen: 662 neue Beobachtungen (gesamt 662), Modell einsatzbereit
```
Nachtrainieren lässt sich jederzeit — per Knopf im Dashboard oder über
`trademind backtest --save-model`, siehe [Training aus dem Dashboard anstoßen](#training-aus-dem-dashboard-anstoßen).
Solange das Modell nicht warm ist (`warmup_samples`), entscheidet allein das Regelwerk.
Die Qualität lässt sich im Status unter `strategy.learner.online_accuracy` verfolgen — das ist
eine *prequentielle* Messung: erst vorhersagen, dann lernen, also keine Selbstbewertung auf
@@ -326,7 +331,7 @@ Timeframes und Parameter gehören ausprobiert, bevor auch nur ein Paper-Euro fli
| Endpunkt | Inhalt |
|--------------|-------------------------------------------------------------|
| `/` | Dashboard: Equity, Positionen, Trades, Modellzustand |
| `/` | Dashboard: Equity, Positionen, Trades, Modellzustand, Training |
| `/health` | Liveness — nutzt der Container-Healthcheck |
| `/ready` | Readiness (503, solange der Bot nicht sauber läuft) |
| `/status` | vollständiger Zustand als JSON |
@@ -344,6 +349,51 @@ Slack als auch Discord.
---
## Training aus dem Dashboard anstoßen
Im Abschnitt **Training** des Dashboards stehen zwei Bedienelemente:
**Historisch nachtrainieren.** Anzahl Kerzen wählen (500 50 000 je Symbol), Knopf drücken.
Der Bot lädt die Historie, läuft sie mit derselben Logik wie ein Backtest durch — **ohne zu
handeln** — und speichert das Modell danach. Der Fortschritt erscheint direkt darunter:
```
Fertig in 4.3s: +1099 Beobachtungen (gesamt 1753), Modell einsatzbereit, gespeichert
```
Ein zweiter Start wird abgelehnt, solange einer läuft. Handelsdurchlauf und Nachtraining
schließen sich gegenseitig aus, der Live-Betrieb pausiert also für die paar Sekunden.
Die Labels des laufenden Betriebs bleiben davon unberührt.
**Kontinuierliches Lernen.** Schaltet das Online-Lernen im laufenden Betrieb an und aus.
Ausgeschaltet handelt der Bot weiter, verändert das Modell aber nicht mehr — praktisch, um
einen erreichten Stand einzufrieren, ohne den Bot anzuhalten.
Dieselben Aktionen per HTTP:
```bash
curl -X POST localhost:8080/control/train/history -H 'Content-Type: application/json' -H "X-TradeMind-Token: $TOKEN" -d '{"bars": 5000}'
```
| Endpunkt | Methode | Wirkung |
|--------------------------------|---------|--------------------------------------------|
| `/control/training` | GET | Zustand des letzten/laufenden Trainings |
| `/control/train/history` | POST | `{"bars": 5000}` — Nachtraining anstoßen |
| `/control/train/live` | POST | `{"enabled": false}` — Lernen ein/aus |
> **Absicherung.** Anders als die lesenden Endpunkte verändern diese den Zustand des Bots.
> Setze deshalb `server.control_token` (bzw. `TRADEMIND_CONTROL_TOKEN`), sobald der Port
> nicht nur lokal erreichbar ist — die Steuerbefehle verlangen ihn dann im Header
> `X-TradeMind-Token`, während `/status` und Co. offen bleiben. Ohne Token warnt der Bot
> beim Start. Komplett abschalten lässt sich die Steuerung mit `server.enable_control: false`;
> die Routen sind dann nicht vorhanden (404).
>
> ```bash
> openssl rand -hex 24
> ```
---
## Aufbau
```