"""D48 forward candidate with hard-stop-consistent position sizing."""

import logging
from datetime import datetime

from risk_cap_math import risk_capped_stake
from v5_d48 import VolatilityBreakout

logger = logging.getLogger(__name__)


class VolatilityBreakoutRiskCap(VolatilityBreakout):
    """Change only stake sizing; signals, exits and protections remain D48."""

    def version(self) -> str:
        return "5.4.2-d48-riskcap-audit"

    def custom_stake_amount(
        self,
        pair: str,
        current_time: datetime,
        current_rate: float,
        proposed_stake: float,
        min_stake: float | None,
        max_stake: float,
        leverage: float,
        entry_tag: str | None,
        side: str,
        **kwargs,
    ) -> float:
        try:
            candle = self._last_candle(pair)
        except Exception as exc:
            logger.error("读取 %s 分析 K 线失败(%s)，fail-closed 跳过开仓", pair, exc)
            return 0
        if candle is None:
            logger.warning("%s 无可用分析 K 线，fail-closed 跳过开仓", pair)
            return 0

        atr = candle.get("atr")
        if atr is None or atr <= 0 or atr != atr or current_rate <= 0:
            logger.warning("%s ATR/价格无效，fail-closed 跳过开仓", pair)
            return 0

        try:
            wallet = float(self.wallets.get_total_stake_amount())
            stake = risk_capped_stake(
                wallet=wallet,
                risk_fraction=self.risk_per_trade,
                atr_loss_fraction=(float(atr) * self.atr_stop_multiple / current_rate)
                * leverage,
                hard_stop_fraction=abs(self.stoploss),
                wallet_cap_fraction=self.max_stake_wallet_fraction,
                max_stake=max_stake,
            )
        except Exception as exc:
            logger.error("计算 %s 风险封顶仓位失败(%s)，fail-closed 跳过开仓", pair, exc)
            return 0

        if min_stake is not None and stake < min_stake:
            return 0
        return stake
