3. Python 精算模型基础:寿险准备金计算模型

本章将使用 Python 构建一个简化的寿险准备金计算模型,重点在于理解精算模型的输入/输出规范、计算逻辑与 Serving 接口的对应关系。准备金是保险公司对保单未来赔付义务的当前估计,其计算是精算模型的核心场景之一。

3.1 准备金计算的基本原理

寿险准备金通常采用 未来法 计算:准备金 = 未来赔付支出现值 - 未来保费收入现值。对于一份 n 年期定期寿险,在保单第 t 年末的准备金可表示为:

V_t = A_{x+t : n-t|} - P * ä_{x+t : n-t|}

其中:

  • A:死亡赔付的精算现值
  • P:年缴净保费
  • ä:期初付生存年金的精算现值
  • x:投保年龄,n:保险期限,t:已过保单年度
关键假设:本模型使用静态死亡率表(如 CL1 生命表)和固定折现率(如 3.5%),不考虑退保、费用和分红,以聚焦核心计算流程。

3.2 模型输入规范

模型输入采用结构化字典格式,便于后续 API 序列化。输入参数分为保单特征、假设参数和计算控制三类:

参数类别 参数名 类型 说明
保单特征 age int 投保年龄(18-65)
保单特征 term int 保险期限(年)
保单特征 sum_assured float 保额(元)
假设参数 interest_rate float 折现率(如 0.035)
假设参数 mortality_table list[float] 各年龄死亡率 qx 数组
计算控制 valuation_year int 评估年度(保单年度 t)
输入规范要点:所有数值参数使用 float 类型,年龄和期限使用 int,死亡率表使用 list[float]。这种规范直接映射到 JSON API 的请求体结构。

3.3 模型核心实现

以下 Python 代码实现了准备金计算的核心逻辑,包含精算现值计算和准备金聚合:

import numpy as np

def calculate_reserve(inputs: dict) -> dict:
    """
    寿险准备金计算模型
    :param inputs: 包含 age, term, sum_assured, interest_rate,
                   mortality_table, valuation_year 的字典
    :return: 包含各项精算现值和准备金的字典
    """
    age = inputs['age']
    term = inputs['term']
    SA = inputs['sum_assured']
    i = inputs['interest_rate']
    qx = inputs['mortality_table']
    t = inputs['valuation_year']

    v = 1 / (1 + i)  # 折现因子
    remaining = term - t  # 剩余保险期限

    # 提取剩余期限的死亡率(从 age+t 开始)
    q = qx[age+t : age+t+remaining]
    p = [1 - qk for qk in q]

    # 计算死亡赔付精算现值 A
    A = 0.0
    for k in range(remaining):
        prob_survive = np.prod(p[:k]) if k > 0 else 1.0
        A += prob_survive * q[k] * (v ** (k + 0.5))

    # 计算期初付生存年金精算现值 ä
    a_ddot = 0.0
    for k in range(remaining):
        prob_survive = np.prod(p[:k]) if k > 0 else 1.0
        a_ddot += prob_survive * (v ** k)

    # 计算年缴净保费(均衡保费)
    P_net = SA * A / a_ddot if a_ddot > 0 else 0.0

    # 计算第 t 年末准备金
    reserve = SA * A - P_net * a_ddot

    return {
        'A_x': round(A, 6),
        'a_ddot_x': round(a_ddot, 6),
        'P_net': round(P_net, 2),
        'reserve': round(reserve, 2),
        'valuation_year': t
    }

3.4 模型输出规范

输出同样采用结构化字典,包含中间精算变量和最终准备金结果:

输出字段 类型 说明
A_x float 死亡赔付精算现值(每元保额)
a_ddot_x float 期初付生存年金精算现值
P_net float 年缴净保费(元)
reserve float 第 t 年末准备金(元)
valuation_year int 评估年度(回显)
精度注意:精算现值保留 6 位小数,准备金和保费保留 2 位小数。API 返回时应统一使用 float 类型,避免 Decimal 序列化问题。

3.5 模型调用示例

以下示例演示如何使用模型计算一份 30 岁男性、保额 100 万、20 年期的定期寿险在第 5 年末的准备金:

# 构造输入
sample_input = {
    'age': 30,
    'term': 20,
    'sum_assured': 1_000_000,
    'interest_rate': 0.035,
    'mortality_table': cl1_male_qx,  # CL1 生命表男性死亡率数组
    'valuation_year': 5
}

# 调用模型
result = calculate_reserve(sample_input)

print(f"评估年度: {result['valuation_year']}")
print(f"死亡精算现值(A): {result['A_x']}")
print(f"年金精算现值(ä): {result['a_ddot_x']}")
print(f"年缴净保费: {result['P_net']} 元")
print(f"第5年末准备金: {result['reserve']} 元")

输出结果示例:

评估年度: 5
死亡精算现值(A): 0.023456
年金精算现值(ä): 12.345678
年缴净保费: 1899.50 元
第5年末准备金: 45678.90 元

3.6 模型计算流程与 Serving 映射

下图展示了准备金模型的计算流程及其与 API Serving 层的对应关系:

准备金模型计算流程与 Serving 映射 API 请求输入 参数解析与校验 精算现值计算 准备金聚合计算 API 响应输出 Serving 层职责 • JSON 反序列化 • 参数类型校验 • 死亡率表注入 • 结果序列化 模型层职责 • 精算现值计算 • 净保费计算 • 准备金聚合

3.7 模型与 API 的接口契约

准备金模型与 API Serving 层之间遵循明确的接口契约,确保模型可被独立部署和调用:

契约维度 规范要求 示例
输入格式 JSON 对象,键名 snake_case {"age": 30, "term": 20}
输出格式 JSON 对象,包含中间变量 {"reserve": 45678.90}
错误处理 返回错误码 + 描述信息 {"error": "INVALID_AGE"}
幂等性 相同输入必须返回相同输出 纯函数无状态
性能要求 单次计算 < 100ms 批量计算可优化
模型 Serving 最佳实践:将精算模型封装为纯函数,不依赖全局状态。输入输出使用标准 Python 字典,便于直接序列化为 JSON。死亡率表等静态数据通过参数注入,而非硬编码在模型内部。

3.8 模型验证与测试

为确保模型正确性,需要针对边界条件和已知结果进行验证:

  • 零时刻验证:t=0 时,准备金应等于未来法计算的初始值
  • 满期验证:t=n 时,准备金应为 0
  • 折现率验证:折现率为 0 时,精算现值退化为概率和
  • 死亡率验证:死亡率为 0 时,准备金应为 0(无赔付风险)
def test_reserve_boundary():
    """边界条件测试"""
    # 满期时准备金应为 0
    result = calculate_reserve({
        'age': 30, 'term': 10, 'sum_assured': 100000,
        'interest_rate': 0.035,
        'mortality_table': cl1_male_qx,
        'valuation_year': 10
    })
    assert abs(result['reserve']) < 0.01, "满期准备金应为 0"

    # 死亡率为 0 时准备金应为 0
    zero_mort = [0.0] * 100
    result = calculate_reserve({
        'age': 30, 'term': 10, 'sum_assured': 100000,
        'interest_rate': 0.035,
        'mortality_table': zero_mort,
        'valuation_year': 0
    })
    assert abs(result['reserve']) < 0.01, "无死亡风险时准备金应为 0"

    print("所有边界测试通过")

通过以上步骤,我们构建了一个符合精算原理、输入输出规范、可被 API 直接调用的寿险准备金计算模型。下一阶段将基于此模型实现 RESTful API 服务。