"""Smoke-Tests für TradeMind (ohne Netzwerk & ohne echte Keys).""" import numpy as np import pandas as pd import pytest from trademind.config import Config, StrategyConfig, TradingConfig, TrainingConfig from trademind.strategy import Strategy from trademind.engine import Engine from trademind.trader import Trader from trademind.exchange import MockBroker, CcxtBroker from trademind.trainer import Trainer, eval_params, random_params @pytest.fixture def cfg() -> Config: return Config( trading=TradingConfig(), strategy=StrategyConfig(), training=TrainingConfig(generations=3, population=6), exchanges={}, ) @pytest.fixture def candles() -> pd.DataFrame: rng = np.random.default_rng(0) n = 300 close = 50_000 + np.cumsum(rng.standard_normal(n) * 500) open_ = np.roll(close, 1) open_[0] = 50_000 spread = np.abs(rng.standard_normal(n)) * 100 + 5 high = np.maximum(open_, close) + spread low = np.minimum(open_, close) - spread idx = pd.date_range(end=pd.Timestamp.utcnow().floor("h"), periods=n, freq="h") return pd.DataFrame( {"time": idx, "open": open_, "high": high, "low": low, "close": close, "volume": rng.uniform(10, 100, n)} ) def test_strategy_prepare_and_decide(cfg, candles): st = Strategy(cfg.strategy) prep = st.prepare(candles) assert all(k in prep for k in ("ema_fast", "ema_slow", "rsi", "atr")) sigs = st.decide(prep) assert len(sigs) == len(candles) assert sigs[-1].price > 0 def test_engine_run_produces_result(cfg, candles): st = Strategy(cfg.strategy) eng = Engine(cfg.trading, st) res = eng.run(candles) assert res.final_equity > 0 assert isinstance(res.summary().get("num_trades"), int) assert res.equity_curve[0] > 0 def test_paper_trader_roundtrip(cfg, candles): broker = MockBroker(seed=1) st = Strategy(cfg.strategy) tr = Trader(cfg, broker, st) res = tr.simulate() assert res.final_equity >= 0 assert res.num_trades >= 0 def test_trainer_improves_and_sets_weights(cfg, candles): base = Strategy(cfg.strategy) trainer = Trainer(cfg.training, base) p0 = random_params(__import__("random").Random(1)) before = eval_params(p0, candles, cfg.trading, base, cfg.training) best = trainer.train(candles, cfg.trading, base) # after: best should be >= before (elitism guarantees) after = eval_params(best, candles, cfg.trading, base, cfg.training) assert after >= before - 1e-6 def test_data_broker_falls_back_to_mock(cfg): """Ohne Netzwerk/Exchange muss der Fallback auf Mock-Daten greifen.""" from trademind.cli import _data_broker broker = _data_broker(cfg, data="auto", exchange="binance", seed=3) df = broker.fetch_ohlcv("BTC/USDT", "1h", 50) assert len(df) == 50 for col in ("open", "high", "low", "close"): assert (df[col] > 0).all() def test_mock_broker_deterministic(): b1 = MockBroker(seed=3).fetch_ohlcv("BTC/USDT", "1h", 100) b2 = MockBroker(seed=3).fetch_ohlcv("BTC/USDT", "1h", 100) assert b1.equals(b2) def test_strategy_set_parameter(cfg): st = Strategy(cfg.strategy) p = st.parameters() assert "fast_period" in p and "w_ema_cross" in p st.set_parameter("fast_period", 20) assert st.cfg.fast_period == 20 st.set_parameter("w_ema_cross", 1.5) assert st.weights["ema_cross"] == pytest.approx(1.5)