from __future__ import annotations from crypto_spot_bot.learning import TradeLearner from crypto_spot_bot.models import Trade, utc_now from crypto_spot_bot.storage import Storage def test_trade_learner_penalizes_losing_symbol_pattern(make_settings, tmp_path) -> None: settings = make_settings(tmp_path, learning_min_samples=2) storage = Storage(settings.database_path) for value in (-0.4, -0.2): storage.insert_trade( Trade( id=None, symbol="BTCUSDT", side="SELL", qty=1, entry_price=100, exit_price=99, net_pnl=value, reason="test", entry_pattern="пробой вниз", entry_confidence=0.7, opened_at=utc_now(), closed_at=utc_now(), ) ) learner = TradeLearner(settings, storage) learner.refresh() adjustment = learner.adjustment_for("BTCUSDT", "пробой вниз") assert adjustment.sample_size >= 4 assert adjustment.confidence_adjustment < 0 assert "убыточными" in adjustment.reason def test_trade_learner_builds_adaptive_rules_for_losing_ema_exit(make_settings, tmp_path) -> None: settings = make_settings(tmp_path, learning_min_samples=3) storage = Storage(settings.database_path) for value in (-0.05, -0.04, -0.03): storage.insert_trade( Trade( id=None, symbol="BTCUSDT", side="SELL", qty=1, entry_price=100, exit_price=99.9, net_pnl=value, reason="краткосрочный тренд ослаб ниже EMA50", entry_pattern="нейтрально", entry_confidence=0.7, opened_at=utc_now(), closed_at=utc_now(), ) ) learner = TradeLearner(settings, storage) state = learner.refresh() rules = learner.rules_for("BTCUSDT", "нейтрально") assert state.adaptive_rules["risk_mode"] == "defensive" assert rules["ema_exit_mode"] == "profit_only" assert rules["effective_entry_threshold_adjustment"] > 0 assert rules["min_hold_seconds"] > settings.min_hold_seconds def test_trade_learner_enters_capital_protection_and_validates_rules(make_settings, tmp_path) -> None: settings = make_settings(tmp_path, learning_min_samples=3, starting_balance_usdt=100, max_total_exposure_usdt=80) storage = Storage(settings.database_path) for value in (-0.12, -0.10, -0.08): storage.insert_trade( Trade( id=None, symbol="ETHUSDT", side="SELL", qty=1, entry_price=100, exit_price=99, net_pnl=value, reason="краткосрочный тренд ослаб ниже EMA50", entry_pattern="нейтрально", entry_confidence=0.7, opened_at=utc_now(), closed_at=utc_now(), ) ) learner = TradeLearner(settings, storage) state = learner.refresh() rules = state.adaptive_rules assert rules["trade_permission"] == "capital_protection" assert rules["reduce_exposure"] is True assert rules["bad_market_entry_block"] is True assert rules["target_total_exposure_usdt"] == 35.0 assert rules["validation"]["status"] == "accepted" assert rules["validation"]["avoided_loss_usdt"] > 0