3. 坏账率定义与计算:坏账率公式、滚动坏账率、即时坏账率

坏账率是量化风控中最核心的损失指标之一。在高频行情场景下,由于交易频率高、持仓周期短、杠杆倍数大,传统月度/季度坏账率无法及时反映风险变化。本章从基础公式出发,逐步引入滚动坏账率与即时坏账率,帮助你在高频环境中建立实时风险哨兵。

3.1 坏账率基础公式

坏账率(Bad Debt Rate, BDR)定义为:在给定时间窗口内,确认无法收回的损失金额占该窗口内应回收总额的比例。

术语 符号 说明
坏账损失金额 L 逾期超过核销期限且经催收后确认无法回收的本金+利息
应回收总额 R 该窗口内所有到期应还的本金+利息+费用
坏账率 BDR BDR = L / R × 100%
# 基础坏账率计算示例
def basic_bad_debt_rate(loss_amount, total_receivable):
    """
    loss_amount: 坏账损失金额
    total_receivable: 应回收总额
    """
    if total_receivable == 0:
        return 0.0
    return round(loss_amount / total_receivable * 100, 4)

# 示例:某月坏账损失 50 万,应回收总额 5000 万
print(basic_bad_debt_rate(500000, 50000000))  # 输出: 1.0
关键点:基础坏账率是静态指标,只能反映历史已核销的损失,无法捕捉当前持仓的潜在风险。在高频行情中,等你确认坏账时,损失往往已经放大数倍。

3.2 滚动坏账率(Rolling Bad Debt Rate)

滚动坏账率通过固定时间窗口(如30天、7天)不断向前滑动计算,解决静态指标滞后性问题。每个计算周期只取最近N天的数据,窗口每过一天就向前滚动一次。

窗口类型 窗口长度 适用场景
月滚动 30天 常规信贷、低频交易
周滚动 7天 高频行情、日内交易
日滚动 1天 极端高频、做市商风控
# 滚动坏账率计算(7天窗口)
def rolling_bad_debt_rate(loss_series, receivable_series, window=7):
    """
    loss_series: 每日坏账损失列表
    receivable_series: 每日应回收总额列表
    window: 滚动窗口天数
    """
    rolling_rates = []
    for i in range(len(loss_series)):
        start = max(0, i - window + 1)
        window_loss = sum(loss_series[start:i+1])
        window_recv = sum(receivable_series[start:i+1])
        rate = window_loss / window_recv * 100 if window_recv > 0 else 0.0
        rolling_rates.append(round(rate, 4))
    return rolling_rates

# 示例:最近7天损失[2,3,1,4,2,3,5]万,应回收[200,210,190,220,205,215,230]万
losses = [2,3,1,4,2,3,5]
recvs  = [200,210,190,220,205,215,230]
rates = rolling_bad_debt_rate(losses, recvs, window=7)
print(rates[-1])  # 输出最后一个滚动值
实战建议:高频行情推荐使用7天滚动窗口。窗口太短(如1天)噪声大,太长(如30天)反应慢。7天兼顾敏感性与稳定性,适合日内交易和T+0结算场景。
滚动坏账率计算流程(7天窗口) D1 D2 D3 D4 D5 D6 D7 7天滚动窗口(当前) 滚动坏账率 = Σ损失 / Σ应回收 窗口内7天数据聚合 输出:滚动坏账率%

3.3 即时坏账率(Instant Bad Debt Rate)

即时坏账率是滚动坏账率的极端加速版本,专为高频行情设计。它使用当前持仓的未实现损失替代历史核销损失,实时反映如果立即平仓可能产生的坏账比例。

指标 滚动坏账率 即时坏账率
数据来源 历史已核销损失 当前持仓未实现损失
计算频率 每日/每周 实时/每笔交易
滞后性 有滞后(至少1天) 无滞后(即时)
适用场景 常规风控报告 高频行情哨兵预警
# 即时坏账率计算
def instant_bad_debt_rate(current_positions, market_prices, threshold_ratio=0.8):
    """
    current_positions: 当前持仓列表,每项为 { 'cost': 成本价, 'quantity': 数量 }
    market_prices: 当前市场价字典 { 'symbol': price }
    threshold_ratio: 坏账认定阈值(亏损超过成本价的80%视为坏账)
    """
    instant_loss = 0.0
    total_exposure = 0.0

    for pos in current_positions:
        symbol = pos['symbol']
        cost = pos['cost']
        qty = pos['quantity']
        price = market_prices.get(symbol, cost)

        exposure = cost * qty
        total_exposure += exposure

        # 未实现亏损比例
        loss_ratio = (cost - price) / cost
        if loss_ratio >= threshold_ratio:
            instant_loss += (cost - price) * qty

    if total_exposure == 0:
        return 0.0
    return round(instant_loss / total_exposure * 100, 4)

# 示例:持仓3个品种,当前市价大幅下跌
positions = [
    {'symbol': 'BTC', 'cost': 50000, 'quantity': 2},
    {'symbol': 'ETH', 'cost': 3000,  'quantity': 10},
    {'symbol': 'SOL', 'cost': 150,   'quantity': 100}
]
prices = {'BTC': 48000, 'ETH': 2500, 'SOL': 30}
print(instant_bad_debt_rate(positions, prices, threshold_ratio=0.8))
# SOL亏损80%,触发坏账认定
⚠️ 高频行情陷阱:即时坏账率对市场波动极度敏感。当行情剧烈波动时,该指标可能瞬间飙升。建议设置双重阈值:硬阈值(如5%)触发强制平仓,软阈值(如2%)触发人工复核,避免误杀正常持仓。
三种坏账率对比:基础 vs 滚动 vs 即时 基础坏账率 数据:历史核销损失 频率:月度/季度 滞后:高(30天+) 用途:监管报告 滚动坏账率 数据:窗口内损失 频率:每日/每周 滞后:中(1-7天) 用途:日常风控 即时坏账率 数据:未实现损失 频率:实时/每笔 滞后:无 用途:高频哨兵 从左到右:滞后性递减,实时性递增,高频场景优先选择即时坏账率

3.4 高频场景下的选择策略

  • 基础坏账率:用于月度/季度监管报告和财务核算,不参与实时风控决策。
  • 滚动坏账率:用于每日风控晨会、周报分析,适合T+1结算的常规高频交易。
  • 即时坏账率:用于实时哨兵预警、自动平仓触发,适合做市商、日内高频、杠杆交易。
实战口诀:基础看历史,滚动看趋势,即时看风险。高频行情中,三个指标同时监控:即时坏账率做第一道防线,滚动坏账率做第二道验证,基础坏账率做最终核算。