Learning
VOL. VII · NO. 124 · OTC Derivatives · 19 JUL 2026

Securities Lending Sbl

OTC 衍生品 · 19 JUL 2026 · 6 min read · 1,350 words
· · ·

ODTS 74 — 证券借贷(SBL/转融通):被忽略的一类簿记

为什么需要这篇文档

整个 ODTS 系列写满了期权、远期、互换、收益凭证、雪球这些”主角”产品,但代码库里有一类独立、真实存在、却从未被文档提及的簿记业务:

SBL —— Securities Borrowing and Lending(证券借贷 / 转融通)。

eds-web-appsblbooking 模块里,系统维护着一整套证券借贷合约的停牌(suspension)与复牌(resumption)合约簿记,并配套了利率迁移(interest migration)的 EOD 批处理。这说明券商不仅做衍生品,也做”借股票/还股票”的融券业务,而且它有自己独立的生命周期、状态机和日终流程。

一个 PM/BA 如果不知道 SBL 的存在,在做”标的停牌了怎么办""融券利率怎么算”这类需求时,会完全摸错方向。


1. SBL 在代码里的位置

eds-web-app/src/com/cicc/sblbooking/
├── controller/
│   ├── InterestMigrationController.java   — 利率迁移接口
│   ├── SblInterestEodController.java      — SBL 利息日终
│   └── MigrationNotionalDetailsRequest.java
├── model/                                  — SBL 合约模型
└── service/
    ├── ContractGroupInterestServiceImpl.java
    ├── ContractGroupInterestMigrationService.java
    ├── ContractGroupAdjInterestMigration.java
    ├── ContractGroupAdjInterestProcessor.java
    ├── InterestBean.java
    ├── FixInterestProcessCallable.java     — 固定利率处理
    ├── FloatInterestProcessCallable.java   — 浮动利率处理
    └── BatchExecuteCallable.java

合约消息定义(protobuf,hedgingAs/contract):
  BeanSblResumptionContract   — 复牌合约
  BeanSblSuspensionContract   — 停牌合约

业务定位: SBL 和衍生品簿记共用一套底层框架(都是 eds-web-app 的 booking 引擎、protobuf 消息、EOD 调度),但是一个独立的业务域——它有自己专属的合约类型和日终逻辑。


2. 一份 SBL 停牌/复牌合约长什么样

BeanSblResumptionContract(复牌)的字段,把”一只股票暂停融券、又恢复融券”这件事完整地建模了:

字段含义说明
contractId / contractName合约 ID / 名称SBL 合约标识
stkId / exchId / fullTicker / tickerName标的证券借的是哪只股票、哪个交易所
trend方向借入 / 借出
initCount初始数量借了多少股
suspensionType停牌类型这次暂停属于什么性质
suspensionDate / suspensionOccurTime停牌时间精确到日期 + 时间戳
suspensionOccurDate停牌发生日
resumptionType复牌类型
resumptionDate / resumptionOccurTime复牌时间
resumptionSupensionid关联停牌 ID把”复牌”挂回”停牌”
requestid / contracteventid请求 / 事件 ID工作流追踪
contracteventStatus事件状态审批/执行状态机

业务含义: 一只证券的融券,可能因为监管停牌、券商自身风控、或客户申请而暂停;之后又可能恢复。系统用”停牌合约”和”复牌合约”两条记录来表达,且复牌通过 resumptionSupensionid 指回原始停牌——这是一个事件溯源(event sourcing)式的建模:不直接改一条状态,而是追加”发生了一次暂停/恢复”的事件。

这和 05 文档里讲的生命周期状态机是同一套思想,但 SBL 把它用在”券源可用性”这个维度上,而不是”交易状态”上。


3. SBL 的日终:利率是它真正的复杂性

SBL 表面是”借股票”,真正的业务复杂度在利息:借出的股票要按利率收息,利率可能是固定(FixInterestProcessCallable)或浮动(FloatInterestProcessCallable),而且历史上可能做过利率迁移(老合约按老利率、新合约按新利率)。

代码里的 service 层几乎全是利息相关:

  • ContractGroupInterestMigrationService / ContractGroupAdjInterestMigration — 合约组利率迁移(批量把一批合约的利率从旧规则切到新规则)
  • ContractGroupInterestServiceImpl — 利率计算
  • SblInterestEodControllerSBL 利息日终:每天跑批,按合约算当天利息
  • BatchExecuteCallable + Fix/FloatInterestProcessCallable — 并发处理固定/浮动利率批次

业务痛点: 利率迁移是 SBL 最容易出错的环节。一次全市场利率调整,可能要把成千上万个在途融券合约的计息规则切换到新利率——既要保证新合约用新利率,又要保证迁移时点之前已计提的利息不回滚。这本质上和 08 §5 “EOD 估值切换”是同一类”历史状态不可变、只在边界切”的工程难题。


4. 为什么 SBL 容易被忽略,但又不能忽略

  • 被忽略的原因: 它不像期权那样”性感”,文档作者(包括之前的我)天然会聚焦在衍生品主角身上。
  • 不能被忽略的原因:
    1. SBL 的”标的停牌/复牌”直接影响那个标的能不能做衍生品交易——和 09 标的生命周期、72 风控规则引擎里 underlyingControlType 是同一只”标的”的不同侧面。
    2. SBL 利息是券商的真实收入/成本,落在 P&L 里,和 54-MTM-PnL 同一条损益链。
    3. SBL 的日终批处理和衍生品 EOD 估值抢同一套调度资源——做 EOD 时序编排时(见 09)必须把它算进去。

5. 内行视角:SBL 是”共用框架、独立域”的典型

SBL 最值得 PM/BA 记住的一点,是它体现了这个系统的整体架构哲学:新产品/新业务不是另起炉灶,而是在 booking 框架上挂一个新的”合约类型 + 一组动作 + 一组日终任务”。

所以当你接到”我们要支持一个新的业务品种”的需求时,正确的类比不是”再写一个全新系统”,而是”像 SBL 那样,在 eds-web-app 里加一组 XxxContract + XxxService + XxxEodController”。这能大幅缩短你和技术对齐需求边界的时间。


自测

  • SBL 的”标的停牌”和”复牌”在代码里是用一条状态字段表达,还是用两条合约记录表达?为什么这么设计?
  • resumptionSupensionid 字段的作用是什么?
  • SBL 真正的业务复杂度在哪一层(簿记?还是利息)?代码里哪些类能证明?
  • 为什么做 EOD 调度时序编排时必须把 SBL 利息日终算进去?
  • 如果要新增一个业务品种,SBL 模块给你的架构启示是什么?

相关阅读:09-Product-and-Lifecycle-State-Machine.md(状态机)、72-Credit-and-Risk-Rules-Engine.md(标的控制)、54-MTM-and-PnL.md(损益链)