3、坏账率定义:Tick级场景下的定义、计算口径与日频区别

在Tick级高频风控场景中,坏账率的定义与计算口径必须从“日频汇总”下沉到“瞬时快照”与“累积窗口”两个维度。传统日频坏账率以自然日为统计窗口,掩盖了日内极端波动与流动性枯竭的瞬时风险;而Tick级坏账率要求以每笔Tick数据为最小观测单元,实时刻画资产质量恶化过程。

3.1 核心定义:Tick级坏账率

Tick级坏账率是指在单个Tick时间戳下,当前持仓或敞口中被判定为“坏账”的资产价值占总敞口价值的比例。其核心特征包括:

  • 瞬时性:每个Tick独立计算,不依赖历史窗口平滑;
  • 事件驱动:仅当Tick数据到达时触发计算,无Tick则不更新;
  • 微观口径:坏账判定标准基于Tick级价格、成交量、买卖盘深度等微观指标。
关键原则: Tick级坏账率不是日频坏账率的“高频采样”,而是重新定义了坏账的触发条件——当Tick价格跌破特定阈值、或买卖价差超过流动性容忍度、或连续Tick无成交时,即可瞬时标记为坏账。

3.2 计算口径:瞬时坏账 vs 累积坏账

根据风控目标不同,Tick级坏账率分为两种计算口径:

口径类型 定义 计算公式 适用场景
瞬时坏账率 单个Tick时刻,当前持仓中已被标记为坏账的资产占比 InstantBadRate(t) = BadValue(t) / TotalExposure(t) 实时止损、闪电崩盘监测、流动性枯竭预警
累积坏账率 从当日开盘或指定起始Tick至当前Tick,累计坏账总价值与累计总敞口的比值 CumBadRate(t) = ΣBadValue(i) / ΣTotalExposure(i),i从起始Tick到当前Tick 日内风控考核、策略回测评估、坏账趋势分析
实践建议: 哨兵模型通常同时监控两种口径——瞬时坏账率用于触发熔断或人工干预,累积坏账率用于评估模型全天表现。两者结合可避免“瞬时误报”与“累积滞后”的单一缺陷。

3.3 与日频坏账率的区别

日频坏账率以“日”为最小时间粒度,Tick级坏账率以“Tick”为最小粒度。两者在统计窗口、计算逻辑、风险敏感度上存在本质差异:

对比维度 日频坏账率 Tick级瞬时坏账率 Tick级累积坏账率
时间粒度 1天(固定窗口) 单个Tick(事件驱动) 从起始Tick到当前Tick(滑动累积)
坏账判定依据 日终收盘价、日终持仓、日终财务指标 Tick价格、Tick成交量、Tick买卖盘深度 同瞬时,但累积历史判定结果
风险敏感度 低(日内波动被平滑) 极高(捕捉每个Tick的突变) 中高(累积效应放大趋势)
计算频率 每日1次 每Tick1次(可能数千次/日) 每Tick1次(需维护累积状态)
数据存储量 低(1条/日/资产) 高(每条Tick均需记录) 高(需存储累积中间变量)
典型应用 月度/季度风控报告、监管报送 实时熔断、闪电崩盘预警 日内策略归因、坏账趋势分析
常见误区: 不要将日频坏账率简单除以交易日Tick数来“模拟”Tick级坏账率。日频坏账率基于日终静态快照,而Tick级坏账率基于日内动态事件,两者统计口径完全不同。直接降频会导致风险严重低估。

3.4 计算口径对比流程图

下图展示了瞬时坏账率与累积坏账率在Tick时间轴上的计算逻辑差异:

Tick级坏账率计算口径对比 T1 T2 T3 T4 T5 T6 T7 瞬时坏账率:每个Tick独立计算 InstantBadRate(T3) = BadValue(T3) / TotalExposure(T3) InstantBadRate(T5) = BadValue(T5) / TotalExposure(T5) 累积坏账率:从起始Tick到当前Tick累积 CumBadRate(T3) = [Bad(T1)+Bad(T2)+Bad(T3)] / [Exp(T1)+Exp(T2)+Exp(T3)] CumBadRate(T5) = [Bad(T1)+...+Bad(T5)] / [Exp(T1)+...+Exp(T5)]

3.5 坏账判定逻辑架构

下图展示了Tick级坏账率从原始Tick数据到最终坏账率输出的完整判定链路:

Tick级坏账率判定逻辑架构 原始Tick数据流 坏账判定引擎 价格阈值 | 流动性阈值 | 连续无成交 瞬时坏账率计算 BadValue(t) / TotalExposure(t) 累积坏账率计算 ΣBadValue(i) / ΣTotalExposure(i) 实时熔断 / 预警 日内风控 / 策略归因

3.6 代码示例:Tick级坏账率计算核心逻辑

以下Python代码展示了瞬时坏账率与累积坏账率在Tick流处理中的核心计算逻辑:

class TickBadRateCalculator:
    """Tick级坏账率计算器(哨兵模型核心组件)"""

    def __init__(self, price_threshold: float, liquidity_threshold: float):
        self.price_threshold = price_threshold          # 价格坏账阈值
        self.liquidity_threshold = liquidity_threshold  # 流动性坏账阈值
        self.cum_bad_value = 0.0                        # 累积坏账价值
        self.cum_total_exposure = 0.0                   # 累积总敞口
        self.tick_count = 0

    def is_bad_tick(self, tick_price: float, bid_ask_spread: float,
                    volume: float) -> bool:
        """判断单个Tick是否为坏账Tick"""
        # 条件1:价格跌破阈值
        if tick_price < self.price_threshold:
            return True
        # 条件2:买卖价差超过流动性容忍度
        if bid_ask_spread > self.liquidity_threshold:
            return True
        # 条件3:成交量异常萎缩(连续低成交由外部状态机维护)
        if volume == 0:
            return True
        return False

    def process_tick(self, tick_price: float, bid_ask_spread: float,
                     volume: float, position_value: float) -> dict:
        """处理单个Tick,返回瞬时与累积坏账率"""
        self.tick_count += 1
        is_bad = self.is_bad_tick(tick_price, bid_ask_spread, volume)

        # 瞬时坏账率:当前Tick的坏账判定
        bad_value_tick = position_value if is_bad else 0.0
        instant_bad_rate = bad_value_tick / position_value if position_value > 0 else 0.0

        # 累积坏账率:更新累积状态
        self.cum_bad_value += bad_value_tick
        self.cum_total_exposure += position_value
        cum_bad_rate = (self.cum_bad_value / self.cum_total_exposure
                        if self.cum_total_exposure > 0 else 0.0)

        return {
            'tick_id': self.tick_count,
            'is_bad_tick': is_bad,
            'instant_bad_rate': round(instant_bad_rate, 6),
            'cum_bad_rate': round(cum_bad_rate, 6),
            'cum_bad_value': round(self.cum_bad_value, 2),
            'cum_total_exposure': round(self.cum_total_exposure, 2)
        }
工程注意: 实际生产环境中,Tick级坏账率计算需注意:
(1) 使用滑动窗口而非全量累积,避免数值溢出;
(2) 瞬时坏账率分母为0时(空仓),应返回0而非报错;
(3) 累积坏账率建议同时记录Tick时间戳,便于回放时对齐。