from alpaclaudia.config import RiskConfig from alpaclaudia.risk import ( AccountSnapshot, check_covered_call, check_csp, check_trailing_stop, ) RISK = RiskConfig( max_position_pct=0.25, min_cash_buffer_pct=0.05, trailing_stop_enabled=True, trailing_stop_pct=0.08, ) ACCT = AccountSnapshot(equity=100_000, cash=50_000, buying_power=50_000) def test_csp_ok(): r = check_csp( underlying="TSLA", strike=200.0, qty=1, account=ACCT, existing_short_puts=0, max_short_puts_per_symbol=1, risk_cfg=RISK, ) assert r.ok, r.reason def test_csp_blocked_by_cash_buffer(): r = check_csp( underlying="TSLA", strike=600.0, # 60k collateral, only 50k cash qty=1, account=ACCT, existing_short_puts=0, max_short_puts_per_symbol=1, risk_cfg=RISK, ) assert not r.ok def test_csp_blocked_by_position_cap(): # 25% of 100k equity = 25k; strike 300 * 100 = 30k collateral r = check_csp( underlying="TSLA", strike=300.0, qty=1, account=ACCT, existing_short_puts=0, max_short_puts_per_symbol=1, risk_cfg=RISK, ) assert not r.ok assert "cap" in r.reason or "exceeds" in r.reason def test_csp_blocked_by_concurrency(): r = check_csp( underlying="TSLA", strike=200.0, qty=1, account=ACCT, existing_short_puts=1, max_short_puts_per_symbol=1, risk_cfg=RISK, ) assert not r.ok def test_covered_call_blocks_below_cost_basis(): positions = [ {"symbol": "TSLA", "qty": 200, "avg_entry_price": 250.0, "is_option": False} ] r = check_covered_call( underlying="TSLA", strike=240.0, qty=1, positions=positions, ) assert not r.ok def test_covered_call_requires_shares(): r = check_covered_call( underlying="TSLA", strike=300.0, qty=1, positions=[], ) assert not r.ok def test_covered_call_ok(): positions = [ {"symbol": "TSLA", "qty": 200, "avg_entry_price": 250.0, "is_option": False} ] r = check_covered_call( underlying="TSLA", strike=275.0, qty=2, positions=positions, ) assert r.ok def test_trailing_stop_needs_long_position(): r = check_trailing_stop(symbol="TSLA", qty=100, positions=[]) assert not r.ok