"""Slippage stress test for any ORB strategy.

Runs the same backtest at increasing slippage levels to find the break-even
slippage point. Useful for validating that a strategy's edge survives realistic
transaction costs.

Usage:
    python -m apps.intraday_bt.scripts.run_slippage_ladder \\
        --config configs/intraday/strategies/orb_pullback_v1.yaml \\
        --days 200 \\
        --bps 5,10,15,25
"""
from __future__ import annotations

import argparse
import asyncio
from pathlib import Path

from apps.intraday_bt.composite import _build_sleeve_config
from apps.intraday_bt.run import load_config, run as run_sleeve


async def _main(args: argparse.Namespace) -> None:
    bps_values = [float(x.strip()) for x in args.bps.split(",")]
    base_config = load_config(args.config)
    days = args.days
    capital = args.capital
    name = Path(args.config).stem

    print(f"\nSlippage ladder: {name}  ({days}d, ${capital:,.0f})")
    print(f"{'BPS':>6}  {'Return':>9}  {'Sharpe':>7}  {'MaxDD':>8}  {'WR':>7}  {'Trades':>7}")
    print("-" * 52)

    baseline_return = None
    for bps in bps_values:
        sleeve = _build_sleeve_config(base_config, capital, days)
        # Override slippage_bps
        params = sleeve.orb_strategy
        if params is not None:
            params_dict = params.model_dump()
            params_dict["slippage_bps"] = bps
            from libs.intraday.domain import ORBStrategyParams
            sleeve_config_dict = sleeve.model_dump()
            sleeve_config_dict["orb_strategy"] = params_dict
            from libs.intraday.domain import IntradayConfig
            sleeve = IntradayConfig(**sleeve_config_dict)

        _, metrics, _, _ = await run_sleeve(sleeve)
        ret = (metrics.total_return_pct or 0) * 100
        sharpe = metrics.sharpe_ratio or 0.0
        dd = (metrics.max_drawdown_pct or 0) * 100
        wr = (metrics.win_rate or 0) * 100
        trades = metrics.total_trades or 0

        if baseline_return is None:
            baseline_return = ret

        degradation = ret - baseline_return
        deg_str = f"({degradation:+.1f}pp)" if bps != bps_values[0] else "        "

        print(f"{bps:>6.0f}  {ret:>+8.2f}%  {sharpe:>7.3f}  {dd:>+7.2f}%  {wr:>6.1f}%  {trades:>7}  {deg_str}")

    # Find break-even (last bps where return > 0)
    print()
    print(f"  Run with --bps ladder to find break-even slippage.")


def main() -> None:
    parser = argparse.ArgumentParser(description="Slippage ladder stress test")
    parser.add_argument("--config", required=True)
    parser.add_argument("--days", type=int, default=200)
    parser.add_argument("--capital", type=float, default=10_000.0)
    parser.add_argument("--bps", default="5,10,15,25",
                        help="Comma-separated slippage bps values (default: 5,10,15,25)")
    args = parser.parse_args()
    asyncio.run(_main(args))


if __name__ == "__main__":
    main()
