HiHuo
首页
博客
手册
工具
关于
首页
博客
手册
工具
关于
  • 交易所技术完整体系

    • 交易所技术完整体系
    • 交易所技术架构总览
    • 交易基础概念
    • 撮合引擎原理
    • 撮合引擎实现-内存撮合
    • 撮合引擎优化 - 延迟与吞吐
    • 撮合引擎高可用
    • 清算系统设计
    • 风控系统设计
    • 资金管理系统
    • 行情系统设计
    • 去中心化交易所(DEX)设计
    • 合约交易系统
    • 数据库设计与优化
    • 缓存与消息队列
    • 用户系统与KYC
    • 交易所API设计
    • 监控与告警系统
    • 安全防护与攻防
    • 高可用架构设计
    • 压力测试与性能优化
    • 项目实战-完整交易所实现

清算系统设计

交易所的清算系统在极端行情下面临严峻挑战。当市场价格剧烈波动(如暴跌50%),会触发大量爆仓。如果清算系统处理不及时,可能导致用户穿仓(亏损超过保证金),平台承担巨额损失。

参考BitMEX、OKEx、Binance等头部交易所的清算机制,本章讲解如何设计一套能在极端行情下稳健运行的清算系统。

1. 清算基础概念

1.1 什么是清算

清算(Liquidation):当用户的保证金不足以维持其仓位时,系统强制平仓的过程。

假设用户用100 USDT做保证金,10倍杠杆做多BTC:

  • 开仓价格:10,000 USDT
  • 保证金:100 USDT
  • 杠杆:10倍
  • 仓位价值:1,000 USDT
  • 持有BTC数量:0.1 BTC

当BTC价格跌到9,000 USDT时:

  • 仓位价值:900 USDT
  • 亏损:100 USDT
  • 保证金余额:100 - 100 = 0 USDT

此时触发清算,系统会强制卖出0.1 BTC,平掉该仓位。

1.2 关键指标

package liquidation

import "math"

// 仓位信息
type Position struct {
	UserID        string
	Symbol        string  // 交易对,如 "BTC/USDT"
	Side          string  // "long" 或 "short"
	EntryPrice    float64 // 开仓价格
	Quantity      float64 // 持仓数量
	Leverage      float64 // 杠杆倍数
	Margin        float64 // 保证金
	MaintenanceMarginRate float64 // 维持保证金率,如0.5%表示需要保持0.5%的保证金
}

// 1. 未实现盈亏 (Unrealized PnL)
func (p *Position) UnrealizedPnL(currentPrice float64) float64 {
	if p.Side == "long" {
		return (currentPrice - p.EntryPrice) * p.Quantity
	} else {
		return (p.EntryPrice - currentPrice) * p.Quantity
	}
}

// 2. 账户权益 (Equity)
func (p *Position) Equity(currentPrice float64) float64 {
	return p.Margin + p.UnrealizedPnL(currentPrice)
}

// 3. 维持保证金 (Maintenance Margin)
func (p *Position) MaintenanceMargin(currentPrice float64) float64 {
	positionValue := currentPrice * p.Quantity
	return positionValue * p.MaintenanceMarginRate
}

// 4. 保证金率 (Margin Ratio)
func (p *Position) MarginRatio(currentPrice float64) float64 {
	equity := p.Equity(currentPrice)
	positionValue := currentPrice * p.Quantity
	return equity / positionValue
}

// 5. 爆仓价格 (Liquidation Price)
func (p *Position) LiquidationPrice() float64 {
	// 爆仓价格的推导:
	// Equity = Margin + UnrealizedPnL = MaintenanceMargin
	// 对于多仓:Margin + (LiqPrice - EntryPrice) * Quantity = LiqPrice * Quantity * MMR
	// 解得:LiqPrice = (Margin + EntryPrice * Quantity) / (Quantity * (1 + MMR))

	if p.Side == "long" {
		numerator := p.Margin + p.EntryPrice*p.Quantity
		denominator := p.Quantity * (1 + p.MaintenanceMarginRate)
		return numerator / denominator
	} else {
		// 对于空仓:LiqPrice = (EntryPrice * Quantity - Margin) / (Quantity * (1 - MMR))
		numerator := p.EntryPrice*p.Quantity - p.Margin
		denominator := p.Quantity * (1 - p.MaintenanceMarginRate)
		return numerator / denominator
	}
}

// 6. 是否触发清算
func (p *Position) ShouldLiquidate(currentPrice float64) bool {
	marginRatio := p.MarginRatio(currentPrice)
	return marginRatio <= p.MaintenanceMarginRate
}

// 示例计算
func Example() {
	position := &Position{
		UserID:                "user123",
		Symbol:                "BTC/USDT",
		Side:                  "long",
		EntryPrice:            10000,
		Quantity:              0.1,
		Leverage:              10,
		Margin:                100,
		MaintenanceMarginRate: 0.005, // 0.5%
	}

	// 当前价格9500
	currentPrice := 9500.0

	// 未实现盈亏 = (9500 - 10000) * 0.1 = -50 USDT
	pnl := position.UnrealizedPnL(currentPrice)
	// 账户权益 = 100 + (-50) = 50 USDT
	equity := position.Equity(currentPrice)
	// 维持保证金 = 9500 * 0.1 * 0.005 = 4.75 USDT
	mm := position.MaintenanceMargin(currentPrice)
	// 保证金率 = 50 / (9500 * 0.1) = 5.26%
	mr := position.MarginRatio(currentPrice)
	// 爆仓价格 = (100 + 10000*0.1) / (0.1 * 1.005) ≈ 10945 USDT
	liqPrice := position.LiquidationPrice()

	// 是否清算? 5.26% > 0.5%,暂不清算
	shouldLiq := position.ShouldLiquidate(currentPrice)

	// 当价格跌到9900时
	// 保证金率 = [100 + (9900-10000)*0.1] / (9900*0.1) = 0.404%
	// 0.404% < 0.5%,触发清算!
}

2. 清算流程设计

2.1 完整流程

1. 监控触发 → 2. 风险评估 → 3. 清算排队 → 4. 执行清算 → 5. 清算完成 → 6. 通知用户

2.2 实现代码

package liquidation

import (
	"container/heap"
	"context"
	"sync"
	"time"
)

// 清算引擎
type LiquidationEngine struct {
	// 仓位管理
	positions map[string]*Position // userID -> Position
	posMu     sync.RWMutex

	// 清算队列(优先级队列)
	liquidationQueue *LiquidationQueue
	queueMu          sync.Mutex

	// 价格源
	priceFeed *PriceFeed

	// 撮合引擎接口
	matchEngine MatchEngineInterface

	// 保险基金
	insuranceFund float64
	fundMu        sync.Mutex

	// 监控
	metrics *LiquidationMetrics
}

func NewLiquidationEngine(matchEngine MatchEngineInterface) *LiquidationEngine {
	return &LiquidationEngine{
		positions:        make(map[string]*Position),
		liquidationQueue: NewLiquidationQueue(),
		priceFeed:        NewPriceFeed(),
		matchEngine:      matchEngine,
		insuranceFund:    0,
		metrics:          NewLiquidationMetrics(),
	}
}

// Step 1: 监控所有仓位
func (e *LiquidationEngine) MonitorPositions(ctx context.Context) {
	ticker := time.NewTicker(100 * time.Millisecond) // 每100ms检查一次
	defer ticker.Stop()

	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
			e.checkAllPositions()
		}
	}
}

func (e *LiquidationEngine) checkAllPositions() {
	e.posMu.RLock()
	positions := make([]*Position, 0, len(e.positions))
	for _, pos := range e.positions {
		positions = append(positions, pos)
	}
	e.posMu.RUnlock()

	// 并发检查所有仓位
	var wg sync.WaitGroup
	for _, pos := range positions {
		wg.Add(1)
		go func(p *Position) {
			defer wg.Done()
			e.checkPosition(p)
		}(pos)
	}
	wg.Wait()
}

func (e *LiquidationEngine) checkPosition(pos *Position) {
	// 获取当前价格
	currentPrice := e.priceFeed.GetPrice(pos.Symbol)

	// 判断是否触发清算
	if pos.ShouldLiquidate(currentPrice) {
		// 计算清算优先级(保证金率越低,优先级越高)
		marginRatio := pos.MarginRatio(currentPrice)
		priority := 1.0 / (marginRatio + 0.0001) // 避免除零

		// 加入清算队列
		e.enqueueLiquidation(&LiquidationTask{
			Position: pos,
			Price:    currentPrice,
			Priority: priority,
			EnqueueTime: time.Now(),
		})
	}
}

// Step 2 & 3: 清算排队
type LiquidationTask struct {
	Position    *Position
	Price       float64
	Priority    float64   // 优先级,越大越紧急
	EnqueueTime time.Time
	index       int       // heap接口需要
}

type LiquidationQueue []*LiquidationTask

func NewLiquidationQueue() *LiquidationQueue {
	lq := &LiquidationQueue{}
	heap.Init(lq)
	return lq
}

// 实现heap.Interface
func (lq LiquidationQueue) Len() int { return len(lq) }

func (lq LiquidationQueue) Less(i, j int) bool {
	// 优先级高的排在前面
	return lq[i].Priority > lq[j].Priority
}

func (lq LiquidationQueue) Swap(i, j int) {
	lq[i], lq[j] = lq[j], lq[i]
	lq[i].index = i
	lq[j].index = j
}

func (lq *LiquidationQueue) Push(x interface{}) {
	n := len(*lq)
	task := x.(*LiquidationTask)
	task.index = n
	*lq = append(*lq, task)
}

func (lq *LiquidationQueue) Pop() interface{} {
	old := *lq
	n := len(old)
	task := old[n-1]
	old[n-1] = nil
	task.index = -1
	*lq = old[0 : n-1]
	return task
}

func (e *LiquidationEngine) enqueueLiquidation(task *LiquidationTask) {
	e.queueMu.Lock()
	defer e.queueMu.Unlock()

	heap.Push(e.liquidationQueue, task)
	e.metrics.QueueLength.Add(1)
}

// Step 4: 执行清算
func (e *LiquidationEngine) ProcessLiquidations(ctx context.Context) {
	// 启动多个worker并发处理
	numWorkers := 10
	for i := 0; i < numWorkers; i++ {
		go e.liquidationWorker(ctx)
	}
}

func (e *LiquidationEngine) liquidationWorker(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			return
		default:
			task := e.dequeueLiquidation()
			if task == nil {
				time.Sleep(10 * time.Millisecond)
				continue
			}

			e.executeLiquidation(task)
		}
	}
}

func (e *LiquidationEngine) dequeueLiquidation() *LiquidationTask {
	e.queueMu.Lock()
	defer e.queueMu.Unlock()

	if e.liquidationQueue.Len() == 0 {
		return nil
	}

	task := heap.Pop(e.liquidationQueue).(*LiquidationTask)
	e.metrics.QueueLength.Add(-1)
	return task
}

func (e *LiquidationEngine) executeLiquidation(task *LiquidationTask) {
	startTime := time.Now()
	defer func() {
		e.metrics.LiquidationLatency.Observe(time.Since(startTime).Seconds())
	}()

	pos := task.Position

	// 1. 再次确认需要清算(价格可能已经恢复)
	currentPrice := e.priceFeed.GetPrice(pos.Symbol)
	if !pos.ShouldLiquidate(currentPrice) {
		e.metrics.CancelledLiquidations.Add(1)
		return
	}

	// 2. 计算清算订单
	liquidationOrder := e.createLiquidationOrder(pos, currentPrice)

	// 3. 提交到撮合引擎
	trades, err := e.matchEngine.SubmitOrder(liquidationOrder)
	if err != nil {
		e.metrics.FailedLiquidations.Add(1)
		// 重新入队
		e.enqueueLiquidation(task)
		return
	}

	// 4. 计算清算盈亏
	totalFilled := 0.0
	avgFillPrice := 0.0
	for _, trade := range trades {
		totalFilled += trade.Quantity
		avgFillPrice += trade.Price * trade.Quantity
	}
	if totalFilled > 0 {
		avgFillPrice /= totalFilled
	}

	// 5. 更新仓位
	e.posMu.Lock()
	delete(e.positions, pos.UserID)
	e.posMu.Unlock()

	// 6. 处理清算盈亏
	pnl := e.calculateLiquidationPnL(pos, avgFillPrice)
	if pnl < 0 {
		// 穿仓,使用保险基金
		e.useInsuranceFund(-pnl)
	} else {
		// 盈余,增加保险基金
		e.addInsuranceFund(pnl)
	}

	// 7. 记录清算
	e.recordLiquidation(&LiquidationRecord{
		UserID:       pos.UserID,
		Symbol:       pos.Symbol,
		Side:         pos.Side,
		Quantity:     pos.Quantity,
		EntryPrice:   pos.EntryPrice,
		LiquidationPrice: avgFillPrice,
		PnL:          pnl,
		Timestamp:    time.Now(),
	})

	// 8. 通知用户
	e.notifyUser(pos.UserID, &LiquidationNotification{
		Symbol:     pos.Symbol,
		Quantity:   pos.Quantity,
		Price:      avgFillPrice,
		PnL:        pnl,
		Timestamp:  time.Now(),
	})

	e.metrics.SuccessfulLiquidations.Add(1)
}

// 创建清算订单
func (e *LiquidationEngine) createLiquidationOrder(pos *Position, currentPrice float64) *Order {
	// 清算订单的特点:
	// 1. 市价单,保证成交
	// 2. 方向与持仓相反
	// 3. 数量等于持仓数量
	// 4. 标记为清算订单(享有特殊优先级)

	var side string
	if pos.Side == "long" {
		side = "sell" // 平多仓
	} else {
		side = "buy" // 平空仓
	}

	return &Order{
		OrderID:       generateOrderID(),
		UserID:        "LIQUIDATION_ENGINE", // 特殊用户
		Symbol:        pos.Symbol,
		Side:          side,
		Type:          "market",
		Quantity:      pos.Quantity,
		IsLiquidation: true, // 标记为清算订单
		Timestamp:     time.Now(),
	}
}

// 计算清算盈亏
func (e *LiquidationEngine) calculateLiquidationPnL(pos *Position, fillPrice float64) float64 {
	// 清算盈亏 = 平仓盈亏 - 手续费
	var closePnL float64
	if pos.Side == "long" {
		closePnL = (fillPrice - pos.EntryPrice) * pos.Quantity
	} else {
		closePnL = (pos.EntryPrice - fillPrice) * pos.Quantity
	}

	fee := fillPrice * pos.Quantity * 0.0005 // 假设手续费0.05%

	totalPnL := pos.Margin + closePnL - fee

	return totalPnL
}

// 保险基金管理
func (e *LiquidationEngine) useInsuranceFund(amount float64) {
	e.fundMu.Lock()
	defer e.fundMu.Unlock()

	if e.insuranceFund >= amount {
		e.insuranceFund -= amount
	} else {
		// 保险基金不足,触发社会化分摊(Auto-Deleveraging)
		deficit := amount - e.insuranceFund
		e.insuranceFund = 0
		e.triggerAutoDeleveraging(deficit)
	}
}

func (e *LiquidationEngine) addInsuranceFund(amount float64) {
	e.fundMu.Lock()
	defer e.fundMu.Unlock()

	e.insuranceFund += amount
}

3. 自动减仓机制 (Auto-Deleveraging, ADL)

当保险基金不足以覆盖穿仓损失时,需要对盈利最多的反向仓位进行强制平仓。

3.1 ADL排名算法

// ADL排名:根据盈利和杠杆计算
type ADLRanking struct {
	Position *Position
	PnL      float64
	Score    float64 // 排名分数,越高越先被减仓
}

func (e *LiquidationEngine) calculateADLScore(pos *Position, currentPrice float64) float64 {
	// ADL Score = PnL% × Leverage
	// 盈利越多、杠杆越高,分数越高

	pnl := pos.UnrealizedPnL(currentPrice)
	pnlPercent := pnl / pos.Margin

	score := pnlPercent * pos.Leverage

	return score
}

func (e *LiquidationEngine) getADLRanking(symbol string, side string) []*ADLRanking {
	e.posMu.RLock()
	defer e.posMu.RUnlock()

	rankings := make([]*ADLRanking, 0)
	currentPrice := e.priceFeed.GetPrice(symbol)

	for _, pos := range e.positions {
		if pos.Symbol == symbol && pos.Side == side {
			pnl := pos.UnrealizedPnL(currentPrice)
			if pnl > 0 { // 只对盈利仓位进行ADL
				score := e.calculateADLScore(pos, currentPrice)
				rankings = append(rankings, &ADLRanking{
					Position: pos,
					PnL:      pnl,
					Score:    score,
				})
			}
		}
	}

	// 按分数降序排序
	sort.Slice(rankings, func(i, j int) bool {
		return rankings[i].Score > rankings[j].Score
	})

	return rankings
}

3.2 执行ADL

func (e *LiquidationEngine) triggerAutoDeleveraging(deficit float64) {
	// 记录ADL事件
	e.metrics.ADLEvents.Add(1)

	// 示例:需要清算BTC/USDT的多仓(因为空仓穿仓)
	// 实际应根据穿仓的仓位类型决定
	symbol := "BTC/USDT"
	side := "long"

	rankings := e.getADLRanking(symbol, side)

	remainingDeficit := deficit
	for _, ranking := range rankings {
		if remainingDeficit <= 0 {
			break
		}

		pos := ranking.Position

		// 强制平仓该仓位
		e.forceClosing(pos)

		// 减少deficit
		remainingDeficit -= ranking.PnL

		// 通知用户被ADL
		e.notifyADL(pos.UserID, pos)
	}

	if remainingDeficit > 0 {
		// 仍有亏空,记录到平台损失
		e.metrics.PlatformLoss.Add(remainingDeficit)
	}
}

func (e *LiquidationEngine) forceClosing(pos *Position) {
	currentPrice := e.priceFeed.GetPrice(pos.Symbol)

	// 创建市价平仓订单
	order := e.createLiquidationOrder(pos, currentPrice)

	// 提交到撮合引擎
	e.matchEngine.SubmitOrder(order)

	// 删除仓位
	e.posMu.Lock()
	delete(e.positions, pos.UserID)
	e.posMu.Unlock()
}

4. 阶梯保证金制度

为了降低大仓位的风险,交易所通常采用阶梯保证金制度:仓位越大,维持保证金率越高。

// 阶梯保证金配置
type MarginTier struct {
	MinValue           float64 // 最小仓位价值
	MaxValue           float64 // 最大仓位价值
	MaintenanceMargin  float64 // 维持保证金率
	MaxLeverage        float64 // 最大杠杆
}

var BTCMarginTiers = []MarginTier{
	{0, 50000, 0.005, 125},        // 0-5万:0.5%,最大125倍
	{50000, 250000, 0.01, 100},    // 5万-25万:1%,最大100倍
	{250000, 1000000, 0.02, 50},   // 25万-100万:2%,最大50倍
	{1000000, 5000000, 0.05, 20},  // 100万-500万:5%,最大20倍
	{5000000, math.MaxFloat64, 0.1, 10}, // 500万+:10%,最大10倍
}

func GetMarginTier(symbol string, positionValue float64) *MarginTier {
	// 根据交易对获取阶梯配置
	tiers := BTCMarginTiers // 简化,实际应根据symbol查表

	for i := range tiers {
		if positionValue >= tiers[i].MinValue && positionValue < tiers[i].MaxValue {
			return &tiers[i]
		}
	}

	return &tiers[len(tiers)-1] // 默认返回最高档
}

// 更新Position的维持保证金率
func (p *Position) UpdateMaintenanceMarginRate(currentPrice float64) {
	positionValue := currentPrice * p.Quantity
	tier := GetMarginTier(p.Symbol, positionValue)
	p.MaintenanceMarginRate = tier.MaintenanceMargin
}

5. 部分清算

为了避免一次性清算所有仓位,可以采用部分清算策略。

func (e *LiquidationEngine) partialLiquidation(pos *Position, currentPrice float64) {
	// 1. 计算需要减少多少仓位才能恢复到安全水平
	targetMarginRatio := pos.MaintenanceMarginRate * 1.5 // 恢复到1.5倍维持保证金

	// 当前权益
	currentEquity := pos.Equity(currentPrice)

	// 目标仓位价值 = 当前权益 / 目标保证金率
	targetPositionValue := currentEquity / targetMarginRatio

	// 当前仓位价值
	currentPositionValue := currentPrice * pos.Quantity

	// 需要减少的仓位价值
	reduceValue := currentPositionValue - targetPositionValue

	// 需要平掉的数量
	reduceQuantity := reduceValue / currentPrice

	// 确保至少减少10%,最多100%
	reduceQuantity = math.Max(reduceQuantity, pos.Quantity*0.1)
	reduceQuantity = math.Min(reduceQuantity, pos.Quantity)

	// 2. 创建部分平仓订单
	var side string
	if pos.Side == "long" {
		side = "sell"
	} else {
		side = "buy"
	}

	order := &Order{
		OrderID:       generateOrderID(),
		UserID:        "LIQUIDATION_ENGINE",
		Symbol:        pos.Symbol,
		Side:          side,
		Type:          "market",
		Quantity:      reduceQuantity,
		IsLiquidation: true,
		Timestamp:     time.Now(),
	}

	// 3. 提交订单
	trades, _ := e.matchEngine.SubmitOrder(order)

	// 4. 更新仓位
	filledQuantity := 0.0
	for _, trade := range trades {
		filledQuantity += trade.Quantity
	}

	pos.Quantity -= filledQuantity

	// 5. 如果仓位归零,删除
	if pos.Quantity < 0.00001 {
		e.posMu.Lock()
		delete(e.positions, pos.UserID)
		e.posMu.Unlock()
	}
}

6. 极端行情应对

6.1 限价清算

在极端行情下(如闪崩),市价清算可能导致极差的成交价格。可以设置限价清算来避免这种情况。

func (e *LiquidationEngine) createLimitLiquidationOrder(pos *Position, currentPrice float64) *Order {
	var side string
	var limitPrice float64

	if pos.Side == "long" {
		side = "sell"
		// 限价卖出,价格不低于当前价的98%
		limitPrice = currentPrice * 0.98
	} else {
		side = "buy"
		// 限价买入,价格不高于当前价的102%
		limitPrice = currentPrice * 1.02
	}

	return &Order{
		OrderID:       generateOrderID(),
		UserID:        "LIQUIDATION_ENGINE",
		Symbol:        pos.Symbol,
		Side:          side,
		Type:          "limit",
		Price:         limitPrice,
		Quantity:      pos.Quantity,
		IsLiquidation: true,
		TimeInForce:   "IOC", // Immediate or Cancel
		Timestamp:     time.Now(),
	}
}

6.2 熔断机制

当价格波动超过一定阈值时,暂停清算,给市场冷静时间。

type CircuitBreaker struct {
	lastPrice     float64
	currentPrice  float64
	threshold     float64 // 熔断阈值,如0.1表示10%
	isTriggered   bool
	cooldownUntil time.Time
}

func (cb *CircuitBreaker) CheckAndTrigger(newPrice float64) bool {
	if cb.lastPrice == 0 {
		cb.lastPrice = newPrice
		return false
	}

	// 计算价格变化百分比
	change := math.Abs(newPrice-cb.lastPrice) / cb.lastPrice

	if change > cb.threshold {
		// 触发熔断,暂停5分钟
		cb.isTriggered = true
		cb.cooldownUntil = time.Now().Add(5 * time.Minute)
		return true
	}

	cb.lastPrice = newPrice
	return false
}

func (cb *CircuitBreaker) IsActive() bool {
	if cb.isTriggered && time.Now().Before(cb.cooldownUntil) {
		return true
	}

	if cb.isTriggered && time.Now().After(cb.cooldownUntil) {
		// 冷却结束,解除熔断
		cb.isTriggered = false
	}

	return false
}

// 在清算引擎中使用
func (e *LiquidationEngine) checkPosition(pos *Position) {
	currentPrice := e.priceFeed.GetPrice(pos.Symbol)

	// 检查熔断
	if e.circuitBreaker.CheckAndTrigger(currentPrice) {
		log.Printf("Circuit breaker triggered for %s", pos.Symbol)
		return
	}

	if e.circuitBreaker.IsActive() {
		// 熔断期间不进行清算
		return
	}

	// 正常清算逻辑
	if pos.ShouldLiquidate(currentPrice) {
		e.enqueueLiquidation(&LiquidationTask{...})
	}
}

7. 监控与告警

type LiquidationMetrics struct {
	// 清算统计
	SuccessfulLiquidations Counter
	FailedLiquidations     Counter
	CancelledLiquidations  Counter

	// ADL统计
	ADLEvents   Counter
	ADLPositions Counter

	// 队列监控
	QueueLength Gauge

	// 延迟监控
	LiquidationLatency Histogram

	// 资金监控
	InsuranceFundBalance Gauge
	PlatformLoss         Counter

	// 穿仓监控
	UnderWaterPositions Counter
	UnderWaterAmount    Gauge
}

// Prometheus导出
func (m *LiquidationMetrics) Export() string {
	return fmt.Sprintf(`
# HELP liquidation_successful_total Successful liquidations
# TYPE liquidation_successful_total counter
liquidation_successful_total %d

# HELP liquidation_queue_length Current liquidation queue length
# TYPE liquidation_queue_length gauge
liquidation_queue_length %d

# HELP insurance_fund_balance Current insurance fund balance
# TYPE insurance_fund_balance gauge
insurance_fund_balance %f

# HELP adl_events_total Total ADL events triggered
# TYPE adl_events_total counter
adl_events_total %d
`,
		m.SuccessfulLiquidations.Value(),
		m.QueueLength.Value(),
		m.InsuranceFundBalance.Value(),
		m.ADLEvents.Value(),
	)
}

// 告警规则
// - 清算队列长度 > 100:说明清算压力大
// - 保险基金 < 10万USDT:需要补充
// - 1小时内ADL事件 > 5次:市场极端波动
// - 平台损失 > 5万USDT/天:风控策略需调整

8. 极端行情案例分析

8.1 3·12黑天鹅事件

2020年3月12日,BTC从8000美元暴跌到3800美元,跌幅超过50%。这次极端行情暴露了清算系统可能面临的挑战:

典型问题:

  1. 清算订单堆积:队列长度可能超过5000
  2. 保险基金耗尽:可能触发多次ADL
  3. 撮合引擎延迟飙升:从5ms升到200ms
  4. 价格源不一致:不同交易所价差可达10%

应对策略:

  1. 紧急扩容:动态增加清算worker数量
  2. 优先级调整:大仓位优先清算,避免更大损失
  3. 限价保护:启用限价清算,防止成交价过差
  4. 人工介入:暂停部分异常仓位的清算,人工审核

可能结果:

  • 大量仓位被清算
  • 保险基金大幅减少
  • ADL平仓盈利仓位
  • 平台可能承担部分损失

8.2 设计要点总结

  1. 充分压测:压测应覆盖10-20倍峰值场景
  2. 多源价格:采用多个价格源加权,避免单点风险
  3. 保险基金:保持充足的保险基金缓冲
  4. ADL排序不合理:当时只按盈利排序,应加入杠杆因素

9. 清算系统优化方向

  1. 预测性清算:基于价格趋势预测,提前准备
  2. 流动性池:自建流动性池,避免市场滑点
  3. 分层清算:根据仓位大小采用不同清算策略
  4. 机器学习:预测穿仓风险,动态调整保证金率

小结

清算系统是交易所风险管理的最后一道防线,核心要点:

  1. 实时监控,快速响应
  2. 优先级队列,合理排序
  3. 保险基金和ADL双重保障
  4. 阶梯保证金降低大仓位风险
  5. 熔断机制应对极端行情
  6. 完善的监控和告警

下一章将讨论交易所的风控系统,包括限额管理、异常检测、反洗钱等内容。

Prev
撮合引擎高可用
Next
风控系统设计