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

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

交易基础概念

1. 订单类型

1.1 限价单 (Limit Order)

指定价格和数量的订单。只有当市场价格达到或优于指定价格时才会成交。

特点:

  • 可以控制成交价格
  • 不保证一定成交
  • 可能部分成交

示例:

买入限价单:
- 价格:50,000 USDT
- 数量:0.1 BTC
- 含义:以不高于 50,000 USDT 的价格买入 0.1 BTC

数据结构:

type LimitOrder struct {
    OrderID   string
    UserID    string
    Symbol    string  // "BTC/USDT"
    Side      string  // "buy" or "sell"
    Price     float64 // 限定价格
    Quantity  float64 // 数量
    Filled    float64 // 已成交数量
    Status    string  // "pending", "partial", "filled", "cancelled"
    CreatedAt time.Time
}

1.2 市价单 (Market Order)

以当前市场最优价格立即成交的订单。

特点:

  • 保证成交(如果有足够流动性)
  • 价格不确定
  • 可能有滑点

示例:

买入市价单:
- 数量:0.1 BTC
- 含义:以当前市场最低卖价买入 0.1 BTC

数据结构:

type MarketOrder struct {
    OrderID   string
    UserID    string
    Symbol    string
    Side      string
    Quantity  float64 // 要买/卖的数量
    Status    string
    CreatedAt time.Time
}

1.3 止损单 (Stop Order)

当价格达到止损价时,自动触发的市价单或限价单。

类型:

  • 止损限价单 (Stop-Limit):触发后变成限价单
  • 止损市价单 (Stop-Market):触发后变成市价单

示例:

止损卖出:
- 止损价:48,000 USDT
- 限价:47,500 USDT
- 数量:0.1 BTC
- 含义:当价格跌到 48,000 时,以不低于 47,500 的价格卖出

数据结构:

type StopOrder struct {
    OrderID     string
    UserID      string
    Symbol      string
    Side        string
    StopPrice   float64 // 触发价格
    LimitPrice  float64 // 限价(可选)
    Quantity    float64
    OrderType   string  // "stop_market" or "stop_limit"
    Triggered   bool    // 是否已触发
    Status      string
    CreatedAt   time.Time
}

1.4 冰山单 (Iceberg Order)

大单拆分成多个小单,隐藏真实订单量。

特点:

  • 只显示部分数量
  • 成交后自动挂出下一部分
  • 避免影响市场价格

示例:

冰山买单:
- 总数量:10 BTC
- 显示数量:0.5 BTC
- 价格:50,000 USDT
- 含义:总共买10 BTC,但每次只在盘口显示 0.5 BTC

1.5 时间有效性 (Time in Force)

订单的生效时间策略。

类型全称说明
GTCGood Till Cancel一直有效,直到成交或撤销
IOCImmediate or Cancel立即成交,未成交部分撤销
FOKFill or Kill全部成交或全部撤销
GTDGood Till Date有效期到指定日期

2. 交易对

2.1 基础货币 vs 计价货币

交易对格式:基础货币/计价货币

示例:

  • BTC/USDT:用 USDT 买卖 BTC
    • 基础货币:BTC
    • 计价货币:USDT
    • 价格:1 BTC = 50,000 USDT

2.2 交易对配置

type TradingPair struct {
    Symbol          string  // "BTC/USDT"
    BaseAsset       string  // "BTC"
    QuoteAsset      string  // "USDT"

    // 价格精度
    PricePrecision  int     // 小数位数
    PriceTickSize   float64 // 最小价格变动单位

    // 数量精度
    QuantityPrecision int
    MinQuantity      float64 // 最小下单量
    MaxQuantity      float64 // 最大下单量

    // 金额限制
    MinNotional      float64 // 最小成交额

    // 手续费
    MakerFee        float64 // Maker手续费率
    TakerFee        float64 // Taker手续费率

    // 状态
    Status          string  // "active", "suspended"
}

配置示例:

{
    "symbol": "BTC/USDT",
    "baseAsset": "BTC",
    "quoteAsset": "USDT",
    "pricePrecision": 2,
    "priceTickSize": 0.01,
    "quantityPrecision": 6,
    "minQuantity": 0.000001,
    "maxQuantity": 1000,
    "minNotional": 10,
    "makerFee": 0.001,
    "takerFee": 0.002
}

3. Maker vs Taker

3.1 定义

Maker(挂单方):

  • 提供流动性
  • 订单进入订单簿等待成交
  • 手续费较低(甚至为负,即返佣)

Taker(吃单方):

  • 消耗流动性
  • 订单立即与订单簿中的订单成交
  • 手续费较高

3.2 判断逻辑

func determineMakerTaker(order *Order, matchedPrice float64) string {
    if order.Type == "market" {
        return "taker" // 市价单总是taker
    }

    if order.Side == "buy" {
        if order.Price >= matchedPrice {
            return "taker" // 买价高于或等于成交价,立即成交
        }
        return "maker"
    } else {
        if order.Price <= matchedPrice {
            return "taker" // 卖价低于或等于成交价,立即成交
        }
        return "maker"
    }
}

3.3 手续费计算

func calculateFee(tradingPair *TradingPair, amount float64, role string) float64 {
    var feeRate float64

    if role == "maker" {
        feeRate = tradingPair.MakerFee
    } else {
        feeRate = tradingPair.TakerFee
    }

    return amount * feeRate
}

// 示例
// 成交:0.1 BTC @ 50,000 USDT
// 成交额:5,000 USDT
// Taker手续费(0.2%):5,000 * 0.002 = 10 USDT
// Maker手续费(0.1%):5,000 * 0.001 = 5 USDT

4. 订单簿 (Order Book)

4.1 订单簿结构

订单簿包含两部分:

  • Bids(买单):按价格从高到低排列
  • Asks(卖单):按价格从低到高排列

示例:

Asks (卖单)
50,003  0.5 BTC
50,002  1.2 BTC
50,001  0.8 BTC
------------ 最优价差 ------------
50,000  1.0 BTC  ← 最高买价 (Best Bid)
49,999  0.6 BTC
49,998  2.0 BTC
Bids (买单)

4.2 数据结构

type OrderBook struct {
    Symbol string
    Bids   *PriceLevel // 买盘
    Asks   *PriceLevel // 卖盘
    mu     sync.RWMutex
}

type PriceLevel struct {
    levels map[float64]*Level // 价格 -> 订单列表
}

type Level struct {
    Price    float64
    Quantity float64
    Orders   []*Order
}

4.3 深度数据

深度数据是订单簿的聚合视图。

格式:

{
    "symbol": "BTC/USDT",
    "bids": [
        ["50000.00", "1.234"],
        ["49999.00", "0.567"],
        ["49998.00", "2.345"]
    ],
    "asks": [
        ["50001.00", "0.876"],
        ["50002.00", "1.234"],
        ["50003.00", "0.543"]
    ],
    "timestamp": 1640000000000
}

5. 成交记录

5.1 Trade结构

type Trade struct {
    TradeID      string
    Symbol       string
    BuyOrderID   string
    SellOrderID  string
    BuyUserID    string
    SellUserID   string
    Price        float64
    Quantity     float64
    BuyerMaker   bool    // 买方是否为Maker
    Timestamp    time.Time
}

5.2 成交推送

{
    "event": "trade",
    "symbol": "BTC/USDT",
    "tradeId": "123456789",
    "price": "50000.00",
    "quantity": "0.1",
    "side": "buy",
    "timestamp": 1640000000000
}

6. Ticker数据

Ticker是24小时统计数据。

type Ticker struct {
    Symbol        string
    LastPrice     float64 // 最新成交价
    OpenPrice     float64 // 24h开盘价
    HighPrice     float64 // 24h最高价
    LowPrice      float64 // 24h最低价
    Volume        float64 // 24h成交量(基础货币)
    QuoteVolume   float64 // 24h成交额(计价货币)
    PriceChange   float64 // 24h价格变化
    PriceChangePercent float64 // 24h涨跌幅
    BidPrice      float64 // 当前最高买价
    AskPrice      float64 // 当前最低卖价
    Timestamp     time.Time
}

示例:

{
    "symbol": "BTC/USDT",
    "lastPrice": "50000.00",
    "openPrice": "48000.00",
    "highPrice": "51000.00",
    "lowPrice": "47500.00",
    "volume": "1234.56",
    "quoteVolume": "61234567.89",
    "priceChange": "2000.00",
    "priceChangePercent": "4.17",
    "bidPrice": "49999.00",
    "askPrice": "50001.00",
    "timestamp": 1640000000000
}

7. K线数据

K线(蜡烛图)记录一段时间内的价格变化。

7.1 K线结构

type Kline struct {
    Symbol    string
    Interval  string    // "1m", "5m", "1h", "1d"
    OpenTime  time.Time
    CloseTime time.Time
    Open      float64   // 开盘价
    High      float64   // 最高价
    Low       float64   // 最低价
    Close     float64   // 收盘价
    Volume    float64   // 成交量
    Trades    int       // 成交笔数
}

7.2 K线周期

周期说明
1m1分钟
5m5分钟
15m15分钟
30m30分钟
1h1小时
4h4小时
1d1天
1w1周
1M1月

7.3 K线生成

func generateKline(trades []*Trade, interval string) *Kline {
    if len(trades) == 0 {
        return nil
    }

    kline := &Kline{
        Symbol:   trades[0].Symbol,
        Interval: interval,
        Open:     trades[0].Price,
        High:     trades[0].Price,
        Low:      trades[0].Price,
        Close:    trades[len(trades)-1].Price,
        OpenTime: trades[0].Timestamp,
        CloseTime: trades[len(trades)-1].Timestamp,
        Volume:   0,
        Trades:   len(trades),
    }

    for _, trade := range trades {
        if trade.Price > kline.High {
            kline.High = trade.Price
        }
        if trade.Price < kline.Low {
            kline.Low = trade.Price
        }
        kline.Volume += trade.Quantity
    }

    return kline
}

8. 账户与余额

8.1 账户类型

现货账户:

  • 用于币币交易
  • 资产完全属于用户

杠杆账户:

  • 可以借贷资金
  • 有爆仓风险

合约账户:

  • 用于合约交易
  • 使用保证金模式

8.2 余额类型

type Balance struct {
    UserID    string
    Currency  string
    Available float64 // 可用余额
    Frozen    float64 // 冻结余额(挂单占用)
    Total     float64 // 总余额 = Available + Frozen
}

8.3 余额变动

下单时:

// 冻结余额
balance.Available -= orderAmount
balance.Frozen += orderAmount

成交时:

// 买单成交
balance.Frozen -= quoteAmount        // 解冻计价货币
balance.Available += baseAmount      // 增加基础货币

// 卖单成交
balance.Frozen -= baseAmount         // 解冻基础货币
balance.Available += quoteAmount     // 增加计价货币

撤单时:

// 解冻余额
balance.Frozen -= orderAmount
balance.Available += orderAmount

9. 滑点 (Slippage)

滑点是预期价格与实际成交价格的差异。

9.1 产生原因

  • 订单簿深度不足
  • 市价单吃掉多个价格档位
  • 网络延迟导致价格变化

9.2 计算示例

订单簿卖盘:
50,001  0.5 BTC
50,002  0.3 BTC
50,003  0.5 BTC

用户下市价买单:1.0 BTC

成交情况:
0.5 BTC @ 50,001 = 25,000.5 USDT
0.3 BTC @ 50,002 = 15,000.6 USDT
0.2 BTC @ 50,003 = 10,000.6 USDT
-------------------------
总计:1.0 BTC,花费 50,001.7 USDT

平均成交价:50,001.7 / 1.0 = 50,001.7 USDT
预期价格(最优卖价):50,001 USDT
滑点:50,001.7 - 50,001 = 0.7 USDT
滑点率:0.7 / 50,001 = 0.0014% = 0.14个基点

9.3 滑点控制

func calculateSlippage(marketPrice, executionPrice float64) float64 {
    return (executionPrice - marketPrice) / marketPrice
}

func checkSlippage(order *MarketOrder, maxSlippage float64) error {
    marketPrice := getMarketPrice(order.Symbol, order.Side)
    estimatedPrice := estimateExecutionPrice(order)

    slippage := calculateSlippage(marketPrice, estimatedPrice)

    if slippage > maxSlippage {
        return fmt.Errorf("slippage %.2f%% exceeds maximum %.2f%%",
            slippage*100, maxSlippage*100)
    }

    return nil
}

小结

本章介绍了交易所的基础概念,包括:

  • 订单类型(限价、市价、止损等)
  • 交易对配置
  • Maker vs Taker
  • 订单簿结构
  • 成交、Ticker、K线数据
  • 账户余额管理
  • 滑点计算

下一章将深入讲解撮合引擎的原理和实现。

Prev
交易所技术架构总览
Next
撮合引擎原理