Skip to main content

Phase 2.3 清算与结算(Clearing & Settlement)

目标:理解交易成交后的资金和证券流转过程,这是金融后台系统的核心。


一、为什么清算和结算是两件事​

很多人把这两个概念混用,但它们是不同的阶段:

阶段英文发生时间做什么
交易(Trade)Trade ExecutionT 日买卖双方撮合成交,确定价格和数量
清算(Clearing)ClearingT 到 T+N计算买卖双方各自应收/应付多少钱和证券
结算(Settlement)SettlementT+N 日真正的钱和证券完成划转

类比:

  • 交易 = 你在超市选好商品,去收银台结账
  • 清算 = 收银员算出你该付多少钱,打印小票
  • 结算 = 你真正掏钱,店员把商品给你

二、清算流程详解​

逐笔清算 vs 净额清算​

逐笔清算(Gross Settlement):每笔交易单独结算。

A 买入 AAPL 100 股 @ 150  →  A 付 15000 元,收 100 股
B 买入 AAPL 200 股 @ 150 → B 付 30000 元,收 200 股
  • 优点:简单直观,风险隔离
  • 缺点:资金占用大,效率低

净额清算(Net Settlement / Netting):同一日所有交易轧差后,只结算净额。

A 买入 AAPL 100 股 @ 150(应付 15000 元)
A 卖出 AAPL 60 股 @ 152(应收 9120 元)

净额清算:A 净买入 40 股,净付款 15000 - 9120 = 5880 元

净额清算大幅降低资金和证券的流转量,是现代清算所的标准做法。

多边净额清算(Multilateral Netting)​

中央对手方(CCP)介入后,所有参与方只和 CCP 结算净额:

原始交易关系:
A ──卖50股──► B
B ──卖80股──► C
C ──卖30股──► A

经过 CCP 多边轧差:
A 净买入 20 股(30-50= -20,即卖出 20 股) ← 此处以实际净头寸为准
B 净卖出 30 股
C 净买入 50 股

实际只需三笔结算,而不是原来的三笔,且金额更小

清算的后端实现思路​

// 日终净额清算计算
public Map<String, NetPosition> calculateNetPositions(
List<Trade> todayTrades,
String settlementDate) {

// Key: accountId + ":" + symbol
Map<String, BigDecimal> netQtyMap = new HashMap<>();
Map<String, BigDecimal> netAmountMap = new HashMap<>();

for (Trade trade : todayTrades) {
String key = trade.getAccountId() + ":" + trade.getSymbol();

// 买入:证券+,资金-
if (trade.getSide() == Side.BUY) {
netQtyMap.merge(key, trade.getQty(), BigDecimal::add);
netAmountMap.merge(key,
trade.getQty().multiply(trade.getPrice()).negate(),
BigDecimal::add);
} else {
// 卖出:证券-,资金+
netQtyMap.merge(key, trade.getQty().negate(), BigDecimal::add);
netAmountMap.merge(key,
trade.getQty().multiply(trade.getPrice()),
BigDecimal::add);
}
}

// 构建净头寸结果
Map<String, NetPosition> result = new HashMap<>();
netQtyMap.forEach((key, qty) -> {
result.put(key, new NetPosition(key, qty, netAmountMap.get(key), settlementDate));
});
return result;
}

三、结算流程详解​

T+N 规则​

不同市场的结算周期不同:

市场规则说明
A 股(中国)T+1股票 T+1 结算,资金 T+0 可用
美股T+1(2024年起)2024年5月前是 T+2
欧洲股票T+2欧盟标准
外汇(即期)T+2大多数货币对
外汇(美加元)T+1因地理相近
国债(中国)T+0当日结算

T+N 对后端系统的影响:

  • 成交后资金/证券并非立即可用
  • 系统需要区分"可用余额"和"结算中余额"
  • 需要维护 Settlement Calendar(排除非工作日)
// 计算结算日(需考虑节假日)
public LocalDate calculateSettlementDate(LocalDate tradeDate, String market) {
int settlementDays = getSettlementDays(market); // T+1=1, T+2=2
LocalDate settlementDate = tradeDate;

int daysAdded = 0;
while (daysAdded < settlementDays) {
settlementDate = settlementDate.plusDays(1);
if (isBusinessDay(settlementDate, market)) {
daysAdded++;
}
}
return settlementDate;
}

DVP(货银对付,Delivery vs Payment)​

DVP 是结算安全的核心机制:证券交付和资金支付同步发生,消除其中一方违约的风险。

没有 DVP 的风险:
A 先把股票给 B → B 拿到股票后,可以不付钱(赖账)

DVP 机制:
托管行同时操作:
A 账户: 证券 -100 股,资金 +15000 元
B 账户: 证券 +100 股,资金 -15000 元
两步要么同时成功,要么都不执行(原子操作)

结算失败(Settlement Fail)​

当一方无法履约时,结算失败:

  • 证券交付失败(Fail to Deliver):卖方没有足够的证券
  • 资金支付失败(Fail to Receive):买方没有足够的资金

处理机制:

  • 推迟结算(Roll over to next day)
  • 强制买入(Buy-in):托管行代为购入证券,费用由违约方承担
  • 罚款机制(某些市场对结算失败收取罚金)

四、中央对手方(CCP)​

CCP 的作用​

CCP 介入原始买卖双方的交易,成为"每个买方的卖方,每个卖方的买方",这个过程叫合约替代(Novation):

原始交易:
A ←──── 交易 ────► B

CCP 介入后:
A ←── 新合约 ──► CCP ◄── 新合约 ──► B

好处:

  • A 和 B 不再需要了解对方的信用状况
  • 即使 B 违约,A 仍能从 CCP 处完成结算
  • 风险集中管理,效率更高

保证金制度(Margin)​

CCP 要求所有参与方缴纳保证金,分两类:

初始保证金(Initial Margin):

  • 开仓时缴纳,覆盖潜在市场风险
  • 基于持仓规模和市场波动率计算
  • 通常覆盖 1-2 天的极端价格变动

变动保证金(Variation Margin):

  • 每日盯市(Mark to Market)后,根据浮动盈亏调整
  • 亏损方每日补缴,盈利方每日收到
示例:
周一:A 买入期货,初始保证金 10 万元
周一收盘:期货涨,A 浮盈 1 万元 → A 收到变动保证金 1 万元
周二收盘:期货跌,A 浮亏 3 万元 → A 需补缴变动保证金 3 万元
(否则 CCP 强制平仓)

保证金追缴(Margin Call)​

当变动保证金不足时,CCP 发出保证金追缴通知:

// 每日盯市和保证金计算
public void dailyMarkToMarket(String accountId, LocalDate date) {
List<Position> positions = positionRepository.getPositions(accountId);
BigDecimal totalVariationMargin = BigDecimal.ZERO;

for (Position pos : positions) {
BigDecimal currentPrice = marketDataService.getClosingPrice(pos.getSymbol(), date);
BigDecimal previousPrice = marketDataService.getClosingPrice(pos.getSymbol(), date.minusDays(1));

BigDecimal priceDiff = currentPrice.subtract(previousPrice);
BigDecimal variationMargin = priceDiff.multiply(pos.getNetQty());
totalVariationMargin = totalVariationMargin.add(variationMargin);

// 更新持仓成本价(盯市后重置)
pos.setAverageCost(currentPrice);
}

// 结算变动保证金
if (totalVariationMargin.compareTo(ZERO) > 0) {
// 盈利,CCP 支付给账户
creditMarginAccount(accountId, totalVariationMargin);
} else {
// 亏损,账户需支付给 CCP
BigDecimal required = totalVariationMargin.negate();
if (getMarginBalance(accountId).compareTo(required) < 0) {
issueMarginCall(accountId, required); // 发出追缴通知
} else {
debitMarginAccount(accountId, required);
}
}
}

五、托管(Custody)​

托管的职责​

托管行(Custodian Bank)负责:

  • 安全保管客户的证券和资金
  • 维护持仓记录(Securities Holding)
  • 处理企业行为(Corporate Actions)
  • 提供结算服务

企业行为(Corporate Actions)处理​

这是托管系统中最复杂的部分之一。

现金分红(Cash Dividend):

股权登记日(Record Date):登记持有股东名单
除息日(Ex-Dividend Date):当日买入不再享有本次分红
派息日(Payment Date):实际发放现金

后端处理:
1. 从交易所接收分红通告(Dividend Announcement)
2. 以股权登记日的持仓为基准,计算每位持有人应得金额
3. 派息日将现金划入各账户
4. 记录企业行为历史,供对账和税务使用

股票拆分(Stock Split):

2:1 拆分(1 股拆为 2 股):
- 持仓数量 × 2
- 持仓成本价 ÷ 2
- 所有挂单价格和数量需相应调整

后端处理:
1. 接收交易所的拆分通告
2. 批量更新所有持仓记录
3. 更新历史成本记录(影响税务计算)
4. 通知 OMS 调整未成交挂单

配股(Rights Issue):

公司给现有股东以优惠价认购新股的权利

后端处理:
1. 确认股东是否行使认购权(有时限)
2. 收取认购资金
3. 分配新股
4. 未行使的权利可能需要出售(取决于条款)

六、对账(Reconciliation)​

清结算系统的核心质量保证机制。

对账的层次​

内部对账(Internal Reconciliation)
├── OMS 持仓 vs 风控系统持仓(应实时一致)
├── 交易台持仓 vs 托管持仓(应每日一致)
└── 资金系统 vs 会计系统(应每日一致)

外部对账(External Reconciliation)
├── 我方持仓记录 vs 托管行报告
├── 我方成交记录 vs 交易所成交记录
└── 我方资金 vs 银行账单

对账差异处理​

public List<ReconciliationBreak> reconcile(
List<Position> internalPositions,
List<Position> custodianPositions) {

List<ReconciliationBreak> breaks = new ArrayList<>();

Map<String, Position> custodianMap = custodianPositions.stream()
.collect(toMap(p -> p.getSymbol(), p -> p));

for (Position internal : internalPositions) {
Position custodian = custodianMap.get(internal.getSymbol());

if (custodian == null) {
breaks.add(new ReconciliationBreak(
internal.getSymbol(),
BreakType.MISSING_IN_CUSTODIAN,
internal.getNetQty(),
BigDecimal.ZERO
));
} else if (internal.getNetQty().compareTo(custodian.getNetQty()) != 0) {
breaks.add(new ReconciliationBreak(
internal.getSymbol(),
BreakType.QUANTITY_MISMATCH,
internal.getNetQty(),
custodian.getNetQty()
));
}
}

return breaks;
}

对账差异的常见原因:

  • 成交回报延迟(消息还在路上)
  • 企业行为处理时间差
  • 结算失败未及时处理
  • 系统 bug 导致的记录不一致

七、资金账户模型​

金融系统中资金账户远比银行账户复杂:

账户余额的构成:
┌─────────────────────────────────────┐
│ 总资产(Total Assets) │
│ ├── 现金余额(Cash Balance) │
│ │ ├── 可用余额(Available) │ ← 可以立即使用
│ │ ├── 冻结余额(Frozen) │ ← 已下单但未成交,冻结中
│ │ └── 结算中(Pending Settlement)│ ← 已成交但未到结算日
│ │
│ └── 证券持仓市值(Securities Value)
│
└─────────────────────────────────────┘
// 下单时冻结资金
public void freezeFundsForOrder(String accountId, BigDecimal amount) {
Account account = accountRepository.findById(accountId);

if (account.getAvailableBalance().compareTo(amount) < 0) {
throw new InsufficientFundsException("Available: " + account.getAvailableBalance());
}

// 原子操作:可用余额减少,冻结余额增加
account.setAvailableBalance(account.getAvailableBalance().subtract(amount));
account.setFrozenBalance(account.getFrozenBalance().add(amount));
accountRepository.save(account);
}

// 成交后:解冻 → 转入结算中
public void handleFill(String accountId, BigDecimal filledAmount) {
Account account = accountRepository.findById(accountId);

account.setFrozenBalance(account.getFrozenBalance().subtract(filledAmount));
account.setPendingSettlement(account.getPendingSettlement().add(filledAmount));
accountRepository.save(account);
}

// 结算日:结算中 → 完成
public void completeSe ttlement(String accountId, BigDecimal amount) {
Account account = accountRepository.findById(accountId);
account.setPendingSettlement(account.getPendingSettlement().subtract(amount));
// 已从托管行收到实际资金,余额在托管行报告中更新
accountRepository.save(account);
}

本节小结​

概念核心要点
清算 vs 结算清算=算账,结算=真正的钱券划转
净额清算轧差后只结算净额,大幅降低资金占用
T+N 规则A 股 T+1,美股 T+1,外汇 T+2
DVP货银对付,证券与资金同步交割,消除违约风险
CCP中央对手方,介入所有交易,隔离信用风险
保证金初始保证金+变动保证金,每日盯市
托管保管证券,处理企业行为(分红/拆股/配股)
对账内部对账+外部对账,差异必须有原因

下一节:Phase 2.4 合规与监管