4. 现金流建模:到期日阶梯、合同现金流与行为化调整

现金流建模,说白了就是回答一个问题:钱什么时候进来,什么时候出去

我在做流动性风险压力测试的头两年,踩过最大的坑就是——以为合同现金流就是实际现金流。后来被监管问询过一次,才真正明白:合同是合同,现实是现实。你想想看,客户会老老实实按合同还款吗?当然不会。

所以这一章,我们重点聊三件事:到期日阶梯怎么搭、合同现金流怎么算、行为化调整怎么做。

4.1 到期日阶梯:流动性分析的骨架

到期日阶梯,是流动性风险建模的起点。没有它,你连钱什么时候到期都搞不清楚。

我个人习惯把到期日阶梯分成三个维度:

  • 时间维度:隔夜、7天、14天、1个月、3个月、6个月、1年、3年、5年、5年以上
  • 产品维度:存款、贷款、同业存单、债券、衍生品、结构性产品
  • 币种维度:本币、外币(必要时分币种)

举个例子,一张简单的到期日阶梯表长这样:

时间区间 资产到期流入 负债到期流出 净头寸 累计净头寸
隔夜50亿80亿-30亿-30亿
7天120亿90亿+30亿0亿
14天80亿60亿+20亿+20亿
1个月200亿150亿+50亿+70亿
3个月300亿250亿+50亿+120亿

看到没?隔夜是负的30亿,说明明天就缺钱。这时候你就要问自己:流动性储备够不够补这个缺口?

核心要点:到期日阶梯不是静态的。每次压力测试,都要重新跑一遍。因为资产负债结构每天都在变。

4.2 合同现金流:按合同条款算出来的“理想状态”

合同现金流,就是假设所有交易对手都按合同办事。存款到期才取、贷款到期才还、债券到期才兑付。

听起来很简单对吧?但实际操作中,有四个细节特别容易出错:

  1. 本金和利息要分开算——利息的到期日往往和本金不同
  2. 浮动利率产品——未来现金流不确定,得用远期利率曲线估算
  3. 提前还款/提前支取条款——合同里写了可以提前,但合同现金流不考虑
  4. 展期条款——有些债券有展期权,合同现金流按原始到期日算

我在项目中遇到过一家银行,把一笔10亿的浮动利率贷款按固定利率算了现金流。结果压力测试时,利率上升导致实际利息支出比预期多了2000万。嗯,这个坑我记了很久。

下面是一段Python代码,用来计算一笔固定利率贷款的合同现金流:

import pandas as pd
import numpy as np
from datetime import datetime, timedelta

def calc_contract_cashflows(principal, rate, start_date, maturity_date, freq='M'):
    """
    计算固定利率贷款的合同现金流
    principal: 本金
    rate: 年化利率
    start_date: 起息日
    maturity_date: 到期日
    freq: 付息频率,'M'=月,'Q'=季,'Y'=年
    """
    # 生成付息日期序列
    dates = pd.date_range(start=start_date, end=maturity_date, freq=freq)
    
    # 计算每期利息
    if freq == 'M':
        period_rate = rate / 12
    elif freq == 'Q':
        period_rate = rate / 4
    else:
        period_rate = rate
    
    interest = principal * period_rate
    
    # 构建现金流表
    cf = pd.DataFrame({
        'date': dates,
        'interest': interest,
        'principal': 0
    })
    
    # 最后一期还本
    cf.iloc[-1, cf.columns.get_loc('principal')] = principal
    
    cf['total'] = cf['interest'] + cf['principal']
    
    return cf

# 示例:1亿贷款,年利率4.5%,1年期,按月付息
cf_table = calc_contract_cashflows(
    principal=100_000_000,
    rate=0.045,
    start_date='2024-01-01',
    maturity_date='2024-12-31',
    freq='M'
)

print(cf_table.head(3))
小提示:实际工作中,合同现金流通常从核心系统直接导出。但做压力测试时,我建议自己写一套计算逻辑,方便做敏感性分析。

4.3 行为化调整:从“合同”到“现实”的关键一步

合同现金流是理想状态。行为化调整,就是把理想拉回现实。

为什么要做行为化调整?因为客户的行为和合同写的不一样:

  • 活期存款——合同上没到期日,但实际有沉淀率。我见过一家银行,活期存款的沉淀率高达60%,也就是说只有40%会在短期内被取走
  • 定期存款——合同上写1年,但很多人会提前支取。压力情景下,提前支取率可能从5%飙升到30%
  • 贷款——合同上写3年,但客户可能提前还款。利率下行时,提前还款率会明显上升
  • 信用卡——合同上写的是循环额度,实际用款率只有30%-50%

行为化调整的核心,就是给每个产品定义一个行为化系数

# 行为化调整示例:定期存款提前支取模型
def behavioral_adjustment(contract_cf, product_type, scenario='baseline'):
    """
    对合同现金流进行行为化调整
    product_type: 'demand_deposit', 'time_deposit', 'loan', 'credit_card'
    scenario: 'baseline', 'adverse', 'severely_adverse'
    """
    # 定义不同情景下的行为系数
    behavior_params = {
        'demand_deposit': {
            'baseline': {'stable_rate': 0.65, 'runoff_rate': 0.35},
            'adverse': {'stable_rate': 0.50, 'runoff_rate': 0.50},
            'severely_adverse': {'stable_rate': 0.30, 'runoff_rate': 0.70}
        },
        'time_deposit': {
            'baseline': {'early_withdrawal': 0.05},
            'adverse': {'early_withdrawal': 0.15},
            'severely_adverse': {'early_withdrawal': 0.30}
        }
    }
    
    params = behavior_params[product_type][scenario]
    
    # 这里只是示意逻辑,实际需要更复杂的模型
    if product_type == 'demand_deposit':
        # 活期存款:稳定部分视为长期,流失部分视为短期
        stable = contract_cf * params['stable_rate']
        runoff = contract_cf * params['runoff_rate']
        return {'stable': stable, 'runoff': runoff}
    elif product_type == 'time_deposit':
        # 定期存款:提前支取部分提前到期
        early = contract_cf * params['early_withdrawal']
        normal = contract_cf * (1 - params['early_withdrawal'])
        return {'early': early, 'normal': normal}
    
    return contract_cf
⚠️ 曾经踩过的坑:我曾经把行为化系数设成固定值,结果压力测试结果怎么都对不上历史数据。后来才发现,行为化系数必须随压力情景动态调整。基线情景和严重压力情景下,客户的反应完全不同。

4.4 行为化调整的实战框架

做行为化调整,我建议按以下步骤来:

  1. 历史数据回测——至少取3年数据,分析每个产品的实际现金流与合同现金流的偏差
  2. 定义行为模式——沉淀率、提前支取率、提前还款率、用款率
  3. 情景映射——每个压力情景对应一套行为系数
  4. 压力测试执行——用行为化系数调整合同现金流,生成行为化现金流
  5. 结果验证——和历史压力事件对比,看模型是否合理

下面这张图,是我自己总结的现金流建模核心逻辑:

现金流建模核心逻辑 合同现金流 行为化系数 压力情景参数 行为化调整引擎 行为化现金流 合同现金流 × 行为化系数(情景) = 行为化现金流

你看,整个流程其实不复杂。但难点在于:行为化系数怎么定?

我个人经验是:

  • 先做历史均值,这是底线
  • 再做压力情景下的极端值,参考2008年、2020年等危机时期的数据
  • 最后做敏感性分析,看看系数变动10%对流动性缺口的影响有多大
一句话总结:合同现金流是起点,行为化调整是灵魂。没有行为化调整的压力测试,就是纸上谈兵。

嗯,这一章的内容就到这里。记住:做现金流建模,别只看合同,多想想客户会怎么动。你想想看,如果所有客户都按合同办事,那还要风险管理干嘛?


公众号:蓝海资料掘金营,微信deep3321