"""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}}, } )