- main.py: detect rate_limit_exhausted from voter_a, switch to single(voter_b) and notify Discord once per session - discord.py: add notify_voter_fallback() with yellow warning embed - config.py: add voter_fallback to default notify_on list - dashboard/app.py: show warning banner when fallback mode active (last 2h) - CLAUDE.md: refresh architecture docs, fix stale google-genai migration note Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6.4 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Was das ist
Crypto-Trading-Bot, der alle 15 Minuten Marktdaten von Kraken Futures Demo holt, sie an zwei LLM-Voter im Ensemble schickt und nur bei Konsens (beide BUY/SELL ≥ 0.6 confidence) einen Trade ausführt. Alle Decisions/Trades landen in SQLite, ein Streamlit-Dashboard visualisiert PnL, ein Discord-Webhook benachrichtigt über Trades/Errors/Daily-Summary.
Zweck: Empirisch herausfinden, ob LLM-basiertes Trading profitabel wäre — ohne reales Risiko (Demo-Account).
Commands
# Tests + Lint
.venv/bin/pytest -q # Unit-Tests
.venv/bin/pytest tests/test_indicators.py # einzelner Test
.venv/bin/ruff check src/ # Linting
# Smoke-Tests (erfordern .env mit echten Keys)
.venv/bin/python scripts/smoke_kraken.py # Demo-API erreichbar?
.venv/bin/python scripts/smoke_ai.py # AI-Voter liefern JSON?
.venv/bin/python scripts/smoke_discord.py # Webhook erreichbar?
# Ausführen
.venv/bin/python -m aitrader.main --once # Ein vollständiger Tick
aitrader --once # alternativ via installiertem Entrypoint
# Dashboard (lokal)
.venv/bin/streamlit run src/aitrader/dashboard/app.py
Package-Manager: uv. Dependencies installieren mit uv pip install -e ".[dev]".
Architektur
src/aitrader/
├── main.py # run_tick(): vollständiger Tick-Flow von oben nach unten
├── config.py # YAML (config.yaml) + .env → Pydantic Settings (lru_cache)
├── exchange/
│ ├── kraken.py # ccxt-Wrapper, sandbox=True für Demo
│ └── market_data.py # OHLCV + Orderbook + Ticker → MarketSnapshot
├── features/
│ ├── indicators.py # RSI/MACD/EMA/ATR — pandas-only, kein pandas-ta
│ └── orderbook.py # Spread, Imbalance
├── news/sentiment.py # CryptoPanic + VADER (optional)
├── ai/
│ ├── registry.py # VoterConfig → konkreter Client (make_voter)
│ ├── prompt.py # System- + User-Prompt-Builder
│ ├── schema.py # TradeDecision Pydantic-Modell + JSON-Schema
│ ├── gemini.py # google-genai SDK, response_schema
│ ├── claude.py # anthropic SDK, Tool-Use für strukturierten Output
│ ├── openai_compat.py # OpenAI-kompatible Endpunkte (groq/deepseek/xai/openrouter/ollama)
│ └── ensemble.py # combine() / single() — HOLD bei Disagreement oder zu niedriger Confidence
├── trader/
│ ├── risk.py # evaluate(): Position-Cap, Daily-Loss-Limit, max offene Positionen
│ ├── executor.py # Market-Order auf Kraken Demo + DB-Eintrag
│ └── portfolio.py # SL/TP-Check, Equity-Snapshot, Trade-Close
├── notify/discord.py # Webhook-Notifier (Embeds)
├── storage/
│ ├── models.py # SQLModel-Tabellen: Decision, Trade, EquitySnapshot
│ └── db.py # SQLite-Engine + create_all
└── dashboard/app.py # Streamlit — absolute Imports wegen Script-Ausführung
Tick-Flow (main.py:run_tick): Marktdaten → Features/Indikatoren → Orderbook → News/Sentiment → Prompt-Builder → Voter A + B → Ensemble → DB → Discord → Risk-Check → Execute.
AI-Voter
Zwei generische Voter-Slots in config.yaml (ai.voter_a, ai.voter_b). Provider werden via ai/registry.py instanziiert. Default: voter_a=gemini, voter_b=groq. Wechsel braucht nur Config-Änderung + den passenden ENV-Key.
| provider | ENV-Key | Beispiel-Modell |
|---|---|---|
| gemini | GEMINI_API_KEY |
gemini-2.0-flash |
| claude | ANTHROPIC_API_KEY |
claude-haiku-4-5-20251001 |
| groq | GROQ_API_KEY |
llama-3.3-70b-versatile |
| deepseek | DEEPSEEK_API_KEY |
deepseek-chat |
| xai | XAI_API_KEY |
grok-4-fast |
| openrouter | OPENROUTER_API_KEY |
meta-llama/llama-3.3-70b-instruct:free |
| ollama | (kein Key) | llama3.3 |
ai.mode: single → nur voter_a, kein Konsens nötig.
Wichtige Regeln & Gotchas
- Niemals
exchange.sandbox: falseohne explizite User-Bestätigung. Das ist die einzige Schutzlinie zum Live-Geld. exchange.paper_only: trueblockt Trade-Execution zusätzlich, auch bei sandbox=true.- Indikatoren sind selbst implementiert (pandas-only) weil pandas-ta + numpy 2 inkompatibel war.
- Pair-Symbole: Kraken Futures nutzt teils
PI_XBTUSD-Format stattBTC/EUR— bei Symbol-Fehlernpairs:inconfig.yamlanpassen. - Ensemble-HOLD ist gewollt: Bei Disagreement oder zu niedriger Confidence wird absichtlich nicht getradet.
discord.notify_onenthältdecisionstandardmäßig nicht (192 Embeds/Tag wären spammig). Nurtrade_open,trade_close,erroretc.- Daily-Loss-Limit (5%) pausiert Trading automatisch — Reset um 00:00 UTC.
get_settings()istlru_cache— Änderungen an.env/config.yamlnach Start werden nicht übernommen ohne Neustart.
Wo läuft was
| Umgebung | Pfad | Aufruf |
|---|---|---|
| Lokal (Dev) | ~/code/aitrader |
.venv/bin/python -m aitrader.main --once |
| Server (Prod) | /opt/aitrader |
systemctl status aitrader |
| DB | data/aitrader.db |
sqlite3 data/aitrader.db ".tables" |
| Logs (Server) | journald | journalctl -u aitrader -f |
| Dashboard (Server) | http://<tailscale-host>:8501 |
nur via Tailscale |
Update-Workflow (lokal → Server)
git commit && git push- Auf Server:
cd /opt/aitrader && sudo -u aitrader git pull - Bei neuen Dependencies:
sudo -u aitrader /home/aitrader/.local/bin/uv pip install -e . sudo systemctl restart aitrader aitrader-dashboardsudo journalctl -u aitrader -f
Siehe DEPLOY.md für vollen Setup vom Frischserver inkl. Tailscale.
Ausstehende Erweiterungen (nicht implementiert)
- Backtest-Modus (historische Daten replay durch Decisions-Tabelle)
- Mehr Pairs / dynamisches Universe-Selection
- Position-Sizing per Kelly oder Vol-Targeting
- Prompt-Tuning A/B (zwei Prompts, vergleichen welcher besser performt)
Für Claude
- Kein Refactor "weil schöner" — der Code ist bewusst kompakt gehalten.
- Bei Trading-Logik:
ai/ensemble.pyundtrader/risk.pysind die zwei kritischen Dateien. - Bei Daten-Pipeline:
main.py:run_tickist der Flow von oben nach unten. - Niemals echtes Geld ohne explizite User-Bestätigung — das Projekt ist Demo-only.