Initial commit: TradeMind – Krypto-Trading-Bot mit Lernmodus

Per Podman deploybarer Bot, der Käufe und Verkäufe simuliert ausführt und sich
aus den Ergebnissen weiter antrainiert.

Aufbau
- Einheitliche Bar-Verarbeitung für paper, backtest und live; ausgetauscht werden
  nur Datenquelle und Broker.
- Börsenanbindung über ccxt: rund 100 Börsen allein über exchange.id erreichbar.
  Zugangsdaten kommen über ENV-Platzhalter, der Live-Modus ist doppelt abgesichert.
- Paper-Broker mit Gebühren, Slippage, Börsenpräzision und Volumengrenzen.
- Online trainierte logistische Regression bewertet jedes Einstiegssignal. Sie lernt
  aus realen Trade-Ergebnissen, aus Shadow-Labels aller Kandidaten – auch der
  abgelehnten – und aus Hintergrund-Stichproben; beim Kaltstart wird sie aus der
  Kurshistorie vorgelernt.
- Risikomanagement: Positions- und Exposure-Grenzen, ATR-Stops, Cooldown sowie
  Tagesverlust- und Drawdown-Notbremsen.
- SQLite-Persistenz, HTTP-Status mit Prometheus-Metriken und Dashboard, Webhooks.

Deployment
- Containerfile (zweistufig, non-root UID 10001), podman-compose, systemd-Quadlet.
- Modell und Datenbank liegen im Volume /data und überleben Neustarts.

128 Tests, ruff sauber. Verifiziert gegen echte Marktdaten sowie im gebauten
Container inklusive Healthcheck und Zustandswiederherstellung.
This commit is contained in:
Tobias Zimmermann
2026-08-22 08:53:04 +02:00
commit 65ed73977e
40 changed files with 7033 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
"""Gemeinsame Fixtures: synthetische Kursverläufe ohne Netzwerkzugriff."""
from __future__ import annotations
import numpy as np
import pytest
from trademind.config import Config, PaperConfig, RiskConfig, RuleConfig
from trademind.models import Candles
BAR_MS = 300_000 # 5 Minuten
def make_candles(
symbol: str = "BTC/USDT",
n: int = 600,
start_price: float = 30_000.0,
trend: float = 0.0002,
noise: float = 0.002,
cycle: float = 0.0,
cycle_period: int = 80,
seed: int = 7,
timeframe: str = "5m",
start_ts: int = 1_700_000_000_000,
) -> Candles:
"""Erzeugt eine plausible OHLCV-Serie (geometrischer Random Walk plus optionale Welle)."""
rng = np.random.default_rng(seed)
steps = rng.normal(loc=trend, scale=noise, size=n)
if cycle:
steps += cycle * np.sin(2 * np.pi * np.arange(n) / cycle_period)
close = start_price * np.exp(np.cumsum(steps))
open_ = np.concatenate([[start_price], close[:-1]])
spread = np.abs(rng.normal(0.0, noise * 0.8, size=n)) * close
high = np.maximum(open_, close) + spread
low = np.minimum(open_, close) - spread
low = np.maximum(low, close * 0.5)
volume = rng.lognormal(mean=3.0, sigma=0.4, size=n)
timestamp = start_ts + np.arange(n, dtype=np.int64) * BAR_MS
return Candles(
symbol=symbol,
timeframe=timeframe,
timestamp=timestamp,
open=open_,
high=high,
low=low,
close=close,
volume=volume,
)
@pytest.fixture
def candles() -> Candles:
return make_candles()
@pytest.fixture
def rules() -> RuleConfig:
return RuleConfig()
@pytest.fixture
def paper_config() -> PaperConfig:
return PaperConfig(starting_balance=10_000.0, fee_rate=0.001, slippage_bps=5.0)
@pytest.fixture
def risk_config() -> RiskConfig:
return RiskConfig(max_open_positions=2, max_position_pct=0.25, cooldown_bars_after_exit=0)
@pytest.fixture
def base_config(tmp_path) -> Config:
return Config.model_validate(
{
"mode": "backtest",
"market": {"symbols": ["BTC/USDT"], "timeframe": "5m", "history_bars": 300},
"paper": {"starting_balance": 10_000.0},
"storage": {"database_path": str(tmp_path / "test.sqlite3")},
"server": {"enabled": False},
"strategy": {"learner": {"model_path": str(tmp_path / "model.npz"), "warmup_samples": 20}},
}
)