from datetime import datetime import pytest from app.services import execution_quality as eq def test_side_adjust_no_cancellation(): rows = [ {"order_type": "BUY", "slippage": 0.1, "strategy_type": "daytrading"}, {"order_type": "SELL", "slippage": 0.1, "strategy_type": "daytrading"}, ] r = eq.aggregate_execution_quality_v1(rows)["overall"] assert r["mean_cost_bp"] == 0.0 assert r["mean_abs_bp"] == 10.0 assert eq.slippage_cost_bp_v3("BUY", 0.1) == pytest.approx(10.0) assert eq.slippage_cost_bp_v3("SELL", 0.1) == pytest.approx(-10.0) def test_matches_trade_executor_v2(): te = pytest.importorskip("app.services.trade_executor") for side in ("BUY", "SELL", "HOLD"): for v in (0.1, -0.3, None, "x"): assert eq.slippage_cost_bp_v3(side, v) == te.slippage_cost_bp_v2(side, v) def test_low_sample_null_and_groups(): rows = [ {"order_type": "BUY", "slippage": None, "strategy_type": "swing", "executed_quantity": 0}, {"order_type": "BUY", "slippage": 0.2, "strategy_type": "daytrading", "executed_quantity": 5, "executed_at": datetime(2026, 10, 7, 9, 5), "fill_verified": True}, ] r = eq.aggregate_execution_quality_v1(rows) assert r["overall"]["low_sample"] and r["overall"]["n_slippage"] == 1 assert r["by_strategy"]["swing"]["mean_cost_bp"] is None assert r["by_hour"][9]["fill_verified_ratio"] == 1.0 big = [{"order_type": "BUY", "slippage": 0.1}] * eq.LOW_SAMPLE_THRESHOLD assert not eq.aggregate_execution_quality_v1(big)["overall"]["low_sample"] def test_invalid_inputs(): for bad in (None, "x", float("nan"), float("inf")): assert eq.slippage_cost_bp_v3("BUY", bad) is None assert eq.slippage_cost_bp_v3("HOLD", 0.1) is None