Files
trade-kuns/docs/specs/2026-06-09-trade-kuns-design.md

172 lines
9.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# trade-kuns — Multi-Pair-Trendfolge-Bot (Design)
**Datum:** 2026-06-09
**Status:** Entwurf zur Review
**Entscheidungen:** Neuer Bot, neues Repo · TypeScript + Bun · Paper-only · komplett eigenständig von krypto-kuns
---
## 1. Was dieser Bot ist — und warum
**Ein Satz:** Der Bot kauft eines von vier Krypto-Assets (BTC, ETH, SOL, XRP), wenn dessen Preis auf dem 4-Stunden-Chart über das Hoch der letzten 20 Perioden ausbricht und der langfristige Trend aufwärts zeigt — und verkauft, wenn der Preis um 3×ATR vom Höchststand zurückfällt.
**Warum dieser Ansatz** (Lehren aus krypto-kuns v1, 8 Monate Live-Daten):
| v1-Problem | trade-kuns-Antwort |
|---|---|
| 20 bps Round-Trip-Fees fraßen den Mini-Edge der 115-min-Signale | 4h-Timeframe: Trades laufen TageWochen, Zielbewegung 520 % → Fees sind Rundungsfehler |
| Ein Pair (XRP) = ein Schicksal | 4 Pairs: irgendwo trendet es meistens; kein Trade, wenn nirgends |
| R:R 0.88 bei 31 % WinRate — mathematisch chancenlos | Trailing-Stop ohne TP-Deckel: Verlierer klein (1R), Gewinner offen (+2R bis +10R) |
| 5 Strategien, Aggregator, Gewichte, Veto, Confidence — nichts davon brachte messbaren Nutzen | Eine Regel, binär, in einem Satz erklärbar |
| Backtest in-sample optimiert → Overfitting → live rot | Walk-Forward-Validierung mit hartem Deploy-Gate (siehe §5) |
| `LongOnly`-Config griff live nie (Seed-Gap) | Config wird beim Start per Zod gegen Code-Defaults gemerged + effektive Config geloggt |
**Hinweis zu Fees:** Crypto.com berechnet 0.1 % pro Trade auf **alle** Pairs — XRP ist nicht günstiger als BTC. Entscheidend ist die Relation Fee : Zielbewegung, und die verbessert nur ein höherer Timeframe.
**Erwartungsprofil (wichtig, um live nicht nervös zu werden):** Trendfolge gewinnt nur 3545 % der Trades. Das ist kein Defekt — der Edge kommt daraus, dass Gewinner im Schnitt 24× größer sind als Verlierer. Wochen ohne Trade (Seitwärtsmarkt) sind Normalbetrieb, kein Bug.
## 2. Strategie-Regeln (vollständig)
Alle Berechnungen auf **4h-Candles** (aggregiert aus 15-min-Candles).
**Entry (long-only):**
1. 4h-Candle schließt über dem Hoch der letzten 20 4h-Candles (Donchian-20-Breakout), **und**
2. Schlusskurs > EMA-200 (4h) — Trendfilter gegen Kaufen im Bärenmarkt, **und**
3. für dieses Pair ist keine Position offen, **und**
4. die Positionsgröße nach §3 ist ≥ Mindestordergröße.
**Exit (eine Regel, kein Take-Profit):**
- **Chandelier-Trailing-Stop:** höchstes Hoch seit Entry 3×ATR(14, 4h). Der Stop wandert nur nach oben, nie nach unten. Geprüft auf **15-min-Granularität** (Low ≤ Stop → Exit zum Stop-Preis, pessimistisch).
- Initialer Stop bei Entry ≈ Entry 3×ATR → definiert das Trade-Risiko (1R).
**Parameter (alle konfigurierbar, Defaults):**
| Parameter | Default | Walk-Forward-Grid |
|---|---|---|
| `donchianPeriod` | 20 | 20 / 40 / 55 |
| `atrPeriod` | 14 | fix |
| `atrMultiplier` | 3.0 | 2.0 / 3.0 / 4.0 |
| `trendEmaPeriod` | 200 | 100 / 200 |
| `pairs` | BTC, ETH, SOL, XRP (USDT) | fix |
| `longOnly` | true | fix |
## 3. Risiko & Positionsgrößen
- **Paper-Startkapital:** 1000 USDT.
- **Risiko pro Trade: 1 % der aktuellen Equity** (= 10 USDT initial). Positionsgröße = Risikobetrag ÷ (Entry Initial-Stop). Beispiel: Entry 100, Stop 94 → 6 % Risiko-Distanz → Position 167 USDT.
- **Cap:** max. 30 % der Equity pro Position, max. 4 Positionen (eine pro Pair), kein Leverage, keine Shorts.
- **Fees:** 0.1 % pro Seite. **Slippage:** zusätzlich 5 bps pro Seite simuliert (konservativ).
- Kein Cooldown nötig — Re-Entry erfordert naturgemäß einen neuen Breakout.
## 4. Architektur
### 4.1 Stack
Bun 1.3 · Hono (HTTP) · Drizzle (Postgres) · Zod (Config/API-Validierung) · `bun test`. Eigene DB **`tradekuns`** in shared-postgres. Frontend: schlankes Vue 3 + Vite Dashboard.
### 4.2 Module
```
src/server/
market/ CryptoComClient (REST), CandleStore, Backfill (end_ts-Paginierung)
indicators/ ema, atr, donchian
strategy/ DonchianTrendStrategy (pure Funktion: Candles → Signal)
engine/ TradingEngine (5-min-Loop), PortfolioRisk, PaperTrader, DecisionLogger
backtest/ BacktestRunner, WalkForwardRunner, Metriken (PF, MaxDD, Sharpe, vs. Buy&Hold-BTC)
api/ Hono-Routen
db/ Drizzle-Schema + Migrations
config.ts Env (DATABASE_URL, ZITADEL_ISSUER) + Strategie-Defaults
src/frontend/ Vue 3 Dashboard
```
**Ein Code-Pfad:** Strategie und PaperTrader sind pure Funktionen über `(candles, state) → actions`. Live füttert sie der 5-min-Loop mit frischen Candles, der Backtest mit historischem Replay — identische Logik, per Konstruktion.
### 4.3 Datenfluss (Live)
```
alle 5 min: 15m-Candles je Pair von Crypto.com → CandleStore (Dedup)
→ Stop-Check offener Positionen (15m-Lows gegen Trailing-Stop)
→ bei neuer 4h-Candle: Aggregation → Entry-Evaluation je Pair
→ PortfolioRisk (Sizing, Caps) → PaperTrader → DecisionLog
```
### 4.4 Datenbank (Drizzle, snake_case)
- `candles` — pair, timestamp, OHLCV, **unique(pair, timestamp)**; 15-min-Basis, ~8 Monate × 4 Pairs ≈ 93k Zeilen nach Backfill
- `paper_trades` — pair, entry/exit (Zeit+Preis), Größe, Initial-Stop, Exit-Grund, PnL netto, R-Multiple
- `positions` — offene Positionen inkl. aktuellem Trailing-Stop (übersteht Neustarts)
- `decision_logs` — pro 4h-Bar je Pair: Indikatorwerte, Signal/Blockierungsgrund, Preis + `price_after_4h/24h/72h` (Outcome-Backfill für Edge-Messung)
- `bot_state` — Equity, Running-Flag, effektive Config
- `backtest_runs` / `backtest_trades` — inkl. Walk-Forward-Fenster-Metriken (JSON)
### 4.5 API
| Route | Zweck |
|---|---|
| `GET /health` | Healthcheck (ohne Auth) |
| `GET /api/portfolio` | Equity, offene Positionen mit aktuellem Stop, Cash |
| `GET /api/trades?limit` | abgeschlossene Trades inkl. R-Multiple |
| `GET /api/candles?pair&tf&limit` | Candles (15m / 4h) |
| `GET /api/decisions?pair&limit` | DecisionLog inkl. Outcomes |
| `GET /api/stats` | PF, WR, MaxDD, Equity-Kurve, vs. Buy&Hold-BTC |
| `POST /api/bot/toggle` · `POST /api/bot/reset` | an/aus, Paper-Reset |
| `GET/PUT /api/config` | Strategie-Parameter |
| `POST /api/backtest/run` · `POST /api/backtest/walkforward` · `GET /api/backtest/runs/:id` | Backtests |
| `POST /api/data/backfill` | historische Candles laden |
Auth: JWT gegen Zitadel (`auth.kuns.dev`), wie bei den anderen kuns.dev-Apps.
### 4.6 Dashboard (Vue)
Vier Ansichten: **Portfolio** (Positionen, Equity-Kurve, Stops), **Trades** (Historie mit R-Multiples), **Markt** (4h-Charts je Pair mit Donchian-Kanal/EMA/Stops via lightweight-charts), **Backtest** (Walk-Forward-Report: Fenster-Tabelle Train vs. OOS, Equity-Kurven). Polling 30 s — bei einem 4h-System reicht das locker.
## 5. Validierung — Deploy-Gate vor Live-Schaltung
1. **Backfill:** 15-min-Candles für alle 4 Pairs so weit zurück wie die Crypto.com-API liefert (Ziel ≥ 12 Monate; XRP-1m-Historie aus krypto-kuns kann ergänzend zu 15m aggregiert werden).
2. **Walk-Forward:** Train 120 Tage → Test 30 Tage, rollierend (Schritt 30 Tage). Grid-Search (§2-Grid, 18 Kombinationen) **nur auf Train**; beste Train-Kombination läuft ungesehen über das Test-Fenster.
3. **Gate (hart) — kombiniert über alle Test-Fenster:**
- OOS-ProfitFactor ≥ 1.2 nach Fees+Slippage
- ≥ 25 OOS-Trades
- MaxDrawdown ≤ 25 %
- kein Test-Fenster mit PF < 0.5 bei ≥ 5 Trades
- Train-PF ÷ OOS-PF < 2 (Overfitting-Indikator)
4. **Fällt das Gate durch**, ist das Ergebnis „diese Regeln haben keinen handelbaren Edge" — dann werden Regeln überarbeitet (z. B. Donchian-Periode, anderer Filter), nicht das Gate. Dieses Ergebnis ist ein legitimer, einkalkulierter Ausgang.
5. **Live-Monitoring:** `/api/stats` zeigt den rollierenden Edge (Outcome-Tracking aus decision_logs) — der Frühindikator, der bei v1 fehlte.
## 6. Fehlerbehandlung
- Crypto.com-Ausfall: Retry mit Backoff (3×), Zyklus überspringen, Lücken-Backfill im nächsten Zyklus; Status in `/api/portfolio` sichtbar.
- DB-Ausfall: Engine pausiert, Healthcheck rot → Coolify-Restart.
- Neustart mit offenen Positionen: `positions` wird geladen, Trailing-Stops laufen nahtlos weiter; verpasste 15m-Bars werden nachgeholt und Stops rückwirkend geprüft.
- Pair-spezifischer Datenfehler (z. B. SOL-Feed leer): Pair wird für den Zyklus übersprungen, andere Pairs laufen weiter.
## 7. Tests
- **Unit:** EMA/ATR/Donchian gegen Referenzwerte; Chandelier-Stop (wandert nie abwärts); Sizing-Mathematik inkl. Caps; Intra-Bar-Stop-Ausführung pessimistisch.
- **Integration:** Backtest-Determinismus; Walk-Forward ohne Train/Test-Leak (konstruierter Datensatz); Restart-Recovery offener Positionen.
- **API:** Smoke-Tests gegen Test-DB.
## 8. Deployment
- Repo `trade-kuns` → Gitea, Subdomain **`trade.kuns.dev`**, Port 8080, via `deploy`-Script.
- Dockerfile multi-stage: `oven/bun` (Frontend-Build + Server), Healthcheck `/health`.
- Env: `DATABASE_URL` (DB `tradekuns` in shared-postgres), `ZITADEL_ISSUER`.
- **krypto-kuns läuft unberührt weiter** — Vergleich der beiden Paper-Bots über Wochen, bevor irgendetwas abgeschaltet wird.
## 9. Reihenfolge der Umsetzung
1. **Fundament:** Repo-Skelett, Drizzle-Schema, CryptoComClient + Backfill, Indikatoren (+ Tests)
2. **Backtest zuerst:** Strategie, PaperTrader-Logik, BacktestRunner, WalkForwardRunner → **Gate-Entscheidung** auf echten Daten
3. **Live-Engine:** 5-min-Loop, Positions-Recovery, DecisionLogger + Outcome-Backfill, API
4. **Dashboard:** 4 Views
5. **Deploy:** Gitea + Coolify + DB anlegen, `trade.kuns.dev`
Schritt 2 ist der Pivot: erst wenn das Gate besteht, wird die Live-Engine gebaut.
## 10. Nicht-Ziele
- Kein Live-Trading (keine Order-Ausführung, keine Schreib-API-Keys)
- Keine Shorts, kein Leverage, kein Intraday-Scalping
- Kein Strategie-Aggregator, keine Confidence-Scores, kein ML
- Keine Übernahme von v1-Code oder v1-Tabellen — nur die XRP-Candle-Historie wird ggf. als Backtest-Daten importiert