前言

        在量化交易、数字货币交易所、证券撮合系统等金融级后端开发中,订单是整个交易链路的核心载体。从简单的限价买入,到风控必备的止损,再到机构高频使用的 IOC / FOK 策略单,不同订单类型直接决定了成交逻辑、滑点控制、流动性消耗以及系统撮合效率。

        很多后端同学在对接交易所 API、实现撮合引擎或开发回测系统时,常常被各类订单名词绕晕:限价单、市价单、止损单、止损限价单、IOC、FOK、GTC 到底有什么区别?代码上又该如何建模与落地?

        本篇将从Java 后端开发视角出发,用生活化类比 + 代码模型 + 撮合逻辑,一次性讲透交易系统中最常用的订单类型,帮你建立清晰、可直接落地的技术认知。

一、先建立直觉:订单是什么?

你可以把交易所想象成一个外卖平台:

  • 你(买家)说:“我想花 50 块买一份烤鱼”

  • 餐厅(卖家)说:“我的烤鱼卖 52 块”

  • 交易所就是美团 / 饿了么,负责撮合双方订单

在金融市场里,一个 “订单” 本质上就是一个请求对象,Java 模型可以这样定义:

public class Order {
    private String orderId;        // 订单唯一标识
    private String userId;         // 用户ID
    private Side side;             // BUY 或 SELL
    private OrderType type;        // 订单类型(本篇核心)
    private BigDecimal price;      // 期望价格(并非所有类型都需要)
    private BigDecimal quantity;   // 委托数量
    private TimeInForce tif;       // 有效期策略(GTC/IOC/FOK)
    private long timestamp;        // 下单时间戳
}

public enum Side { BUY, SELL }

public enum OrderType { LIMIT, MARKET, STOP_LOSS, STOP_LIMIT }

public enum TimeInForce { GTC, IOC, FOK }

下面我们逐个拆解每一种订单类型的含义、行为与代码逻辑。

二、五大订单类型详解

1. Limit Order(限价单)——“我只接受这个价”

(1)生活类比:在闲鱼挂一件商品标价 100 元,只有买家出价 ≥ 100 你才愿意成交。

定义:指定一个目标价格,只有市场价格达到或优于该价格时,订单才会成交。

(2)示例

  • 下单:以 50.00 元买入 100 股茅台
  • 当前卖一价:52.00 元
  • 结果:不会立即成交,订单会被 “挂” 在订单簿上,等待对手方以 50.00 元卖出。

(3)程序员类比

        类似一个带条件判断的 API 请求,不满足条件则异步等待。

下面我们逐个拆解每一种订单类型的含义、行为与代码逻辑。
二、五大订单类型详解
1. Limit Order(限价单)——“我只接受这个价”
生活类比:你在闲鱼挂一件商品标价 100 元,只有买家出价 ≥ 100 你才愿意成交。
定义:指定一个目标价格,只有市场价格达到或优于该价格时,订单才会成交。
示例
你下单:以 50.00 元买入 100 股茅台
当前卖一价:52.00 元
结果:不会立即成交,订单会被 “挂” 在订单簿上,等待对手方以 50.00 元卖出。
程序员类比:类似一个带条件判断的 API 请求,不满足条件则异步等待。

(4)核心特点

  • 可以控制成交价格
  • 不保证一定成交(可能长期无法匹配)
  • 类似 CompletableFuture,提交后异步等待触发

2. Market Order(市价单)——“不管价格,现在就要成交”

(1)生活类比:冲进超市直接说 “给我拿一瓶水,多少钱都要”。

定义:不指定价格,以当前市场最优价格立即成交,优先吃尽对手盘深度。

(2)示例

  • 下单:市价买入 100 股茅台
  • 当前卖方盘口:

        卖一:52.00 元 × 60 股卖二:52.50 元 × 80 股

  • 结果:
    • 先成交卖一 60 股(52.00 元)
    • 再成交卖二 40 股(52.50 元)
    • 总花费:5220 元,平均成交价 52.20 元

(3)程序员类比

        无超时、无条件的立即执行,拿到什么算什么。

// 伪代码:市价单撮合逻辑
while (order.getRemainingQty().compareTo(BigDecimal.ZERO) > 0 && !orderBook.isEmpty()) {
    OrderBookLevel bestLevel = orderBook.getBestLevel(order.getSide());
    BigDecimal matchQty = order.getRemainingQty().min(bestLevel.getQty());
    execute(order, bestLevel.getPrice(), matchQty);
}

(4)核心特点

  • 保证成交(市场有流动性即可)
  • 不保证价格,存在滑点风险
  • 类似数据库 READ UNCOMMITTED 级别,不挑剔,优先执行

3. Stop Loss(止损单)——“价格跌到某个点,自动跑路”

(1)生活类比:告诉基金经理 “跌到 45 块就帮我全卖,我认亏离场”。

定义:设置一个触发价(Stop Price),当市场价格触及该价格时,自动转为市价单执行。

(2)示例

  • 持有茅台,当前价 50.00 元
  • 设置止损单:Stop Price = 45.00
  • 价格跌破 45.00 时,系统自动生成市价卖出单,以最优买价成交

(3)程序员类比

        典型的事件监听 + 触发器模式。

// 伪代码:止损单触发逻辑
@EventListener
public void onPriceUpdate(PriceEvent event) {
    for (StopOrder stop : pendingStopOrders) {
        if (event.getPrice().compareTo(stop.getStopPrice()) <= 0) {
            // 触发后转为市价单进入撮合引擎
            MarketOrder marketOrder = stop.convertToMarketOrder();
            matchingEngine.submit(marketOrder);
        }
    }
}

(4)核心特点

  • 本质是条件触发器,不是直接参与撮合的订单
  • 触发前不会出现在订单簿
  • 延伸:Stop Limit(止损限价单) 触发后生成限价单,多一层价格保护

4. IOC(Immediate or Cancel)——“能成多少成多少,剩下的不要了”

(1)生活类比:去奶茶店说 “有几杯给我几杯,不够就算了”。

定义:订单提交后立即尝试成交,能成交多少成交多少,未成交部分立即撤销,不挂单。

(2)示例

  • 下单:限价 50.00 买入 100 股(IOC)
  • 当前卖一:50.00 × 60 股
  • 结果:成交 60 股,剩余 40 股直接取消
// 伪代码
MatchResult result = matchingEngine.tryMatch(order);
if (result.getRemainingQty().compareTo(BigDecimal.ZERO) > 0) {
    // 未成交部分直接取消,不进入订单簿
    order.cancelRemaining();
}

5. FOK(Fill or Kill)——“要么全部成交,要么全部取消”

(1)生活类比:“我要 5 杯奶茶,凑不齐就一杯都不要”。

定义:必须一次性全额成交,若无法满足总量,则整个订单立即撤销,零成交。

(2)示例

  • 下单:限价 50.00 买入 100 股(FOK)
  • 当前卖一仅 60 股
  • 结果:无法全额成交,订单整体取消
// 伪代码
if (matchingEngine.canFullyMatch(order)) {
    matchingEngine.executeAll(order);
} else {
    order.cancel(); // 全部撤销
}

三、IOC vs FOK:用 SQL 事务类比

两者最核心的区别在于原子性可以用数据库事务直观理解:

特性 IOC FOK
行为 能成多少成多少,剩余撤销 要么全成,要么全不成
SQL 类比 部分提交:插入 1000 条成功 800 条则提交 800 条 原子事务:一条失败则全部回滚
事务特性 非原子性 原子性(All or Nothing)
适用场景 快速吃单,有多少成交多少 机构大额建仓,必须一次性完成

代码思维对比

// IOC 非原子执行
@Transactional(propagation = Propagation.SUPPORTS)
public void iocOrder(Order order) {
    int matched = tryMatchAsMuchAsPossible(order);
    cancelRemaining(order);
}

// FOK 原子执行
@Transactional(rollbackFor = Exception.class)
public void fokOrder(Order order) {
    if (!canFullyMatch(order)) {
        throw new InsufficientLiquidityException();
    }
    executeAll(order);
}

四、Java 建模:枚举 + 策略模式

        真实项目中,不建议用大量 if/elseswitch 堆砌撮合逻辑,推荐枚举 + 策略模式,结构清晰、易于扩展和测试。

// 1. 订单类型枚举
public enum OrderType {
    LIMIT, MARKET, STOP_LOSS, STOP_LIMIT
}

// 2. 撮合策略接口
public interface OrderMatchStrategy {
    MatchResult match(Order order, OrderBook orderBook);
}

// 3. 限价单策略
@Component
public class LimitOrderStrategy implements OrderMatchStrategy {
    @Override
    public MatchResult match(Order order, OrderBook orderBook) {
        List<Trade> trades = new ArrayList<>();
        while (order.hasRemaining()) {
            OrderBookLevel best = orderBook.getBestAsk();
            if (best == null || best.getPrice().compareTo(order.getPrice()) > 0) {
                break;
            }
            trades.add(executeTrade(order, best));
        }
        return new MatchResult(trades, order.getRemainingQty());
    }
}

// 4. 市价单策略
@Component
public class MarketOrderStrategy implements OrderMatchStrategy {
    @Override
    public MatchResult match(Order order, OrderBook orderBook) {
        List<Trade> trades = new ArrayList<>();
        while (order.hasRemaining() && orderBook.hasBestAsk()) {
            OrderBookLevel best = orderBook.getBestAsk();
            trades.add(executeTrade(order, best));
        }
        return new MatchResult(trades, order.getRemainingQty());
    }
}

// 5. 策略工厂(Spring 自动注入管理)
@Component
public class OrderStrategyFactory {
    private final Map<OrderType, OrderMatchStrategy> strategies;

    public OrderStrategyFactory(List<OrderMatchStrategy> strategyList) {
        this.strategies = strategyList.stream()
            .collect(Collectors.toMap(
                s -> resolveType(s),
                Function.identity()
            ));
    }

    public OrderMatchStrategy getStrategy(OrderType type) {
        return strategies.get(type);
    }
}

为什么用策略模式?

        每种订单撮合逻辑差异巨大,集中在一个方法中会迅速变成难以维护的 “屎山”。策略模式让逻辑内聚、可单测、可插拔扩展。

五、撮合引擎中的处理优先级

1.基于 SpringBoot 实现简易撮合引擎时,遵循价格优先、时间优先原则:

  • 买单:价格高优先;同价则时间早优先
  • 卖单:价格低优先;同价则时间早优先

2.推荐数据结构

  • 买单簿:TreeMap<BigDecimal, LinkedList<Order>> 按价格降序
  • 卖单簿:TreeMap<BigDecimal, LinkedList<Order>> 按价格升序

3.标准处理流程

新订单进入
    │
    ├── 是否为 Stop 类订单?
    │     └── 是 → 放入监控队列,等待价格触发
    │
    ├── 是否为市价单?
    │     └── 是 → 直接吃对手盘,不挂单
    │
    └── 是否为限价单?
          └── 尝试撮合
                ├── 可成交 → 立即成交
                └── 不可成交 → 根据 TimeInForce 处理
                      ├── GTC → 挂单等待
                      ├── IOC → 撤销剩余部分
                      └── FOK → 整单撤销

六、实际交易所 API 示例(以币安为例)

真实交易所下单接口结构高度统一,以币安现货接口为例:

POST /api/v3/order
参数:
  symbol=BTCUSDT          // 交易对
  side=BUY                // 买卖方向
  type=LIMIT              // 订单类型
  timeInForce=GTC         // 有效期策略
  quantity=0.01           // 数量
  price=30000.00          // 价格
  timestamp=1700000000000 // 时间戳
  signature=xxx           // HMAC-SHA256 签名

不同订单类型必填参数对比:

类型 必填参数
LIMIT price, quantity, timeInForce
MARKET quantity(或 quoteOrderQty)
STOP_LOSS quantity, stopPrice
STOP_LOSS_LIMIT price, quantity, stopPrice, timeInForce

注意:市价单不需要 price,系统自动以最优价撮合成交。

七、总结速查表

订单类型 一句话解释 保证成交? 保证价格? 会挂单?
Limit 只接受指定价格
Market 不看价格,立即成交
Stop Loss 价格触发后自动市价成交 触发后 ✅ ❌(触发前不在簿)
IOC 能成多少成多少,剩余撤销 部分 ✅
FOK 全额成交或全部撤销 全部或 ❌

结尾

        订单类型是交易系统最基础、最核心的设计单元,无论是自研撮合引擎、对接第三方交易所、开发量化策略回测,还是做高并发交易风控,都离不开对这些基础概念的精准理解。理解限价单与市价单的滑点差异、IOC 与 FOK 的原子性区别、止损单的触发机制,不仅能让你写出更健壮的交易代码,也能在对接真实交易所 API 时少踩大量坑。

        后续我们会基于本篇模型,逐步实现完整的订单簿、撮合引擎、成交推送与资金清算,一步步搭建出可运行的极简交易系统。

欢迎关注后续更新,一起从0到1搭建金融级交易后端系统。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐