from __future__ import annotations from crypto_spot_bot.analytics import risk_guard_snapshot from crypto_spot_bot.data_quality import analyze_symbol_quality from crypto_spot_bot.models import Candle, Ticker, Trade, utc_now from crypto_spot_bot.storage import Storage def test_risk_guard_blocks_after_consecutive_losses(make_settings, tmp_path) -> None: settings = make_settings(tmp_path, risk_max_consecutive_losses=2) storage = Storage(settings.database_path) now = utc_now() for _ in range(2): storage.insert_trade( Trade( id=None, symbol="BTCUSDT", side="SELL", qty=1.0, entry_price=100.0, exit_price=99.0, net_pnl=-1.0, opened_at=now, closed_at=now, entry_diagnostics={"forecast": {"probability_up": 0.64, "model": "torch_gru"}}, ) ) guard = risk_guard_snapshot(settings, storage.closed_trades(), storage.latest_equity()) assert guard["block_new_entries"] is True assert "consecutive_losses" in guard["reasons"] assert guard["position_size_multiplier"] == 0.0 def test_data_quality_flags_missing_candle_gap() -> None: candles = [ Candle(1_000_000, 100, 101, 99, 100.5, 10), Candle(1_000_000 + 60 * 60 * 1000 * 3, 100.5, 102, 100, 101, 12), ] ticker = Ticker("BTCUSDT", 101, 100.99, 101.01, 1_000_000, 100, 0) row = analyze_symbol_quality(symbol="BTCUSDT", candles=candles, ticker=ticker, interval="60") assert row["status"] == "warn" assert any(issue["code"] == "missing_candles" for issue in row["issues"])