"""IRR 精算计算模块 — Modified-Actuarial NPV IRR(二分法)。""" # HK IA 监管上限 HK_IA_CAP_HKD = 0.06 # HKD 6.0% HK_IA_CAP_OTHER = 0.065 # 非 HKD 6.5% def ia_irr_cap(currency: str = "HKD") -> float: """HK IA 监管上限。""" return HK_IA_CAP_HKD if currency.upper() == "HKD" else HK_IA_CAP_OTHER def compute_irr_ma( annual_prem: float, pay_yrs: int, sv: float, yr: int, cap: float = HK_IA_CAP_HKD, ) -> float | None: """Modified-Actuarial NPV IRR(二分法 200 次迭代)。 Args: annual_prem: 年缴保费 pay_yrs: 缴费年期 sv: 第 yr 年的退保价值 yr: 保单年度 cap: IRR 上限(HK IA 监管) Returns: IRR 值(0~cap 之间),无法计算返回 None """ if yr <= 0 or annual_prem <= 0 or sv <= 0: return None def npv(r): """计算净现值。""" if r <= -1: return float("inf") total = 0.0 for t in range(1, min(yr, pay_yrs) + 1): total += annual_prem / ((1 + r) ** t) # 退保价值折现到第 yr 年 total -= sv / ((1 + r) ** yr) return total # 二分法求解 low, high = 0.0, cap for _ in range(200): mid = (low + high) / 2 if npv(mid) > 0: low = mid else: high = mid return round((low + high) / 2, 6) def compute_irr_ma_withdraw( annual_prem: float, pay_yrs: int, start_yr: int, annual_wd: float, sv: float, yr: int, cap: float = HK_IA_CAP_HKD, ) -> float | None: """含退保场景的 Modified-Actuarial NPV IRR。 Args: annual_prem: 年缴保费 pay_yrs: 缴费年期 start_yr: 开始退保年度 annual_wd: 每年退保金额 sv: 第 yr 年的退保价值 yr: 保单年度 cap: IRR 上限 Returns: IRR 值,无法计算返回 None """ if yr <= 0 or annual_prem <= 0: return None def npv(r): if r <= -1: return float("inf") total = 0.0 for t in range(1, min(yr, pay_yrs) + 1): total += annual_prem / ((1 + r) ** t) # 退保收入折现 for t in range(start_yr, yr + 1): total -= annual_wd / ((1 + r) ** t) # 最终退保价值折现 total -= sv / ((1 + r) ** yr) return total low, high = -0.01, cap for _ in range(200): mid = (low + high) / 2 if npv(mid) > 0: low = mid else: high = mid return round((low + high) / 2, 6)