跳转至

maker-only撮合器

Maker-Only匹配引擎,用于回测交易策略。该引擎只允许限价单(maker订单),禁止市价单或激进的限价单(taker订单)。

功能特点

  1. Maker-only订单验证:拒绝会穿过价差变成taker订单的订单
  2. 订单管理:支持提交、撤销和跟踪订单
  3. 部分成交处理:支持订单的部分成交,剩余数量保留在订单簿中
  4. 超时撤销:自动撤销开放时间过长的订单
  5. 偏离撤销:当市场价格偏离订单价格过多时撤销订单
  6. 双腿支持:支持两个不同市场的腿(A和B)上的套利策略
  7. 成交记录:记录所有成交详情,包括触发成交的交易

核心组件

MakerSimulator 类(处理所有匹配逻辑的主类):

  • post_order():提交新订单,验证以防止taker订单
  • on_tick():处理传入的行情数据并匹配现有订单
  • cancel_order():按ID取消特定订单
  • cancel_timeout_orders():取消开放时间超过指定超时时间的订单
  • cancel_deviation_orders():取消价格偏离当前市场价格超过阈值的订单

订单跟踪信息:

  • 订单ID
  • 市场腿(A或B)
  • 方向(买入或卖出)
  • 价格和数量
  • 已成交数量
  • 状态(新订单、部分成交、完全成交、已撤销、已拒绝)
  • 时间戳

成交记录信息:

  • 关联订单ID
  • 市场腿
  • 方向
  • 价格和数量
  • 时间戳
  • 匹配交易ID

测试场景

  1. 完全成交:订单被匹配交易完全成交
  2. 部分成交:订单部分成交,剩余数量保持活跃
  3. 单腿成交:在两腿策略中,只有一腿得到成交
  4. 吃单拒绝:尝试提交taker订单被正确拒绝
  5. 重复处理:处理重复订单ID

代码重要细节

防止吃单

在接受任何订单之前,系统检查是否会成为吃单:

  • 买入价高于等于当前最新价的订单会被拒绝
  • 卖出价低于等于当前最新价的订单会被拒绝

匹配逻辑

订单与传入的交易行情匹配:

  • 买入订单在交易价格≤订单价格时匹配
  • 卖出订单在交易价格≥订单价格时匹配
  • 匹配结果为部分成交(模拟为剩余数量的50%)

订单生命周期

订单经历以下状态:

  1. NEW - 刚提交
  2. PARTIALLY_FILLED - 部分数量已成交
  3. FILLED - 所有数量已成交
  4. CANCELLED - 被用户或系统取消
  5. REJECTED - 提交时被拒绝(例如taker订单)
#ifndef MAKER_SIMULATOR_H
#define MAKER_SIMULATOR_H

#include <chrono>
#include <map>
#include <memory>
#include <queue>
#include <string>
#include <vector>

// 行情数据结构体
struct TickData {
  double bid_price;                                 // 买一价
  double ask_price;                                 // 卖一价
  double last_price;                                // 最新价
  std::chrono::steady_clock::time_point timestamp;  // 时间戳
  std::string trade_id;                             // 交易ID
};

// 前向声明
struct Order;
struct Trade;

enum class OrderSide {
  BUY,  // 买入
  SELL  // 卖出
};

enum class OrderStatus {
  NEW,               // 新订单
  PARTIALLY_FILLED,  // 部分成交
  FILLED,            // 完全成交
  CANCELLED,         // 已撤销
  REJECTED           // 已拒绝
};

enum class Leg {
  A,  // 腿A
  B   // 腿B
};

// 订单结构体
struct Order {
  std::string order_id;                               // 订单ID
  Leg leg;                                            // 市场腿
  OrderSide side;                                     // 买卖方向
  double price;                                       // 价格
  double size;                                        // 数量
  double filled_size;                                 // 已成交数量
  OrderStatus status;                                 // 订单状态
  std::chrono::steady_clock::time_point timestamp;    // 订单时间戳
  std::chrono::steady_clock::time_point last_update;  // 最后更新时间
};

// 成交结构体
struct Trade {
  std::string order_id;                             // 订单ID
  Leg leg;                                          // 市场腿
  OrderSide side;                                   // 买卖方向
  double price;                                     // 成交价格
  double size;                                      // 成交数量
  std::chrono::steady_clock::time_point timestamp;  // 成交时间戳
  std::string matched_by;                           // 触发成交的交易ID
};

// Maker交易模拟器类
class MakerSimulator {
 public:
  MakerSimulator();

  // 提交新订单
  bool post_order(const std::string& order_id, Leg leg, OrderSide side,
                  double price, double size);

  // 处理行情数据
  void on_tick(Leg leg, const TickData& tick);

  // 撤销订单
  bool cancel_order(const std::string& order_id);

  // 根据超时时间撤销订单
  void cancel_timeout_orders(std::chrono::milliseconds timeout);

  // 根据价格偏离撤销订单
  void cancel_deviation_orders(double threshold_percent);

  // 获取当前订单
  const std::map<std::string, Order>& get_orders() const;

  // 获取成交记录
  const std::vector<Trade>& get_trades() const;

  // 计算当前权益
  double calculate_equity() const;

  // 获取现金余额
  double get_cash() const;

 private:
  std::map<std::string, Order> orders_;  // 订单映射表
  std::vector<Trade> trades_;            // 成交记录
  std::map<Leg, double> last_prices_;    // 最新价格
  double equity_;                        // 总权益
  double cash_;                          // 现金

  // 辅助方法
  bool is_taker_order(Leg leg, OrderSide side, double price) const;
  void match_order(Order& order, const TickData& tick);
  void cancel_order_internal(Order& order);
};

#endif  // MAKER_SIMULATOR_H
#include <algorithm>
#include <cmath>
#include <iostream>

#include "maker_simulator.h"

// 构造函数
MakerSimulator::MakerSimulator() : equity_(0.0), cash_(100000.0) {
  // 初始化现金为100000.0
}

// 提交订单
bool MakerSimulator::post_order(const std::string& order_id, Leg leg,
                                OrderSide side, double price, double size) {
  // 检查是否会成为吃单
  if (is_taker_order(leg, side, price)) {
    std::cerr << "检测到尝试吃单,订单 " << order_id << " 已被拒绝。"
              << std::endl;
    return false;
  }

  // 检查是否有足够资金(对于买单)
  if (side == OrderSide::BUY) {
    double cost = price * size;
    if (cost > cash_) {
      std::cerr << "资金不足,订单 " << order_id << " 已被拒绝。" << std::endl;
      return false;
    }
  }

  // 创建新订单
  Order order;
  order.order_id = order_id;
  order.leg = leg;
  order.side = side;
  order.price = price;
  order.size = size;
  order.filled_size = 0.0;
  order.status = OrderStatus::NEW;
  order.timestamp = std::chrono::steady_clock::now();
  order.last_update = order.timestamp;

  // 添加到订单映射表
  orders_[order_id] = order;
  return true;
}

// 处理行情数据
void MakerSimulator::on_tick(Leg leg, const TickData& tick) {
  // 更新最新价格
  last_prices_[leg] = tick.last_price;

  // 检查每个订单是否有匹配
  std::vector<std::string> orders_to_update;
  for (const auto& pair : orders_) {
    const Order& order = pair.second;
    if (order.leg == leg && order.status != OrderStatus::CANCELLED &&
        order.status != OrderStatus::FILLED) {
      orders_to_update.push_back(order.order_id);
    }
  }

  // 处理匹配
  for (const std::string& order_id : orders_to_update) {
    auto it = orders_.find(order_id);
    if (it != orders_.end()) {
      match_order(it->second, tick);
    }
  }
}

// 撤销订单
bool MakerSimulator::cancel_order(const std::string& order_id) {
  auto it = orders_.find(order_id);
  if (it != orders_.end()) {
    cancel_order_internal(it->second);
    return true;
  }
  return false;
}

// 根据超时时间撤销订单
void MakerSimulator::cancel_timeout_orders(std::chrono::milliseconds timeout) {
  auto now = std::chrono::steady_clock::now();
  for (auto& pair : orders_) {
    Order& order = pair.second;
    if (order.status != OrderStatus::CANCELLED &&
        order.status != OrderStatus::FILLED) {
      auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
          now - order.timestamp);
      if (elapsed >= timeout) {
        cancel_order_internal(order);
      }
    }
  }
}

// 根据价格偏离撤销订单
void MakerSimulator::cancel_deviation_orders(double threshold_percent) {
  for (auto& pair : orders_) {
    Order& order = pair.second;
    if (order.status != OrderStatus::CANCELLED &&
        order.status != OrderStatus::FILLED) {
      auto it = last_prices_.find(order.leg);
      if (it != last_prices_.end()) {
        double last_price = it->second;
        if (last_price > 0) {
          double deviation = std::abs(order.price - last_price) / last_price;
          if (deviation >= threshold_percent / 100.0) {
            cancel_order_internal(order);
          }
        }
      }
    }
  }
}

// 获取当前订单
const std::map<std::string, Order>& MakerSimulator::get_orders() const {
  return orders_;
}

// 获取成交记录
const std::vector<Trade>& MakerSimulator::get_trades() const { return trades_; }

// 计算当前权益
double MakerSimulator::calculate_equity() const {
  // 计算当前权益 = 现金 + 持仓价值
  double total_equity = cash_;

  // 计算持仓价值
  std::map<std::pair<Leg, OrderSide>, double> positions;   // 持仓数量
  std::map<std::pair<Leg, OrderSide>, double> avg_prices;  // 持仓均价

  // 通过成交记录计算持仓
  for (const auto& trade : trades_) {
    std::pair<Leg, OrderSide> key = std::make_pair(trade.leg, trade.side);

    if (trade.side == OrderSide::BUY) {
      // 买入增加多头持仓
      if (positions.find(key) == positions.end()) {
        positions[key] = trade.size;
        avg_prices[key] = trade.price;
      } else {
        // 加权平均计算均价
        double total_quantity = positions[key] + trade.size;
        avg_prices[key] =
            (avg_prices[key] * positions[key] + trade.price * trade.size) /
            total_quantity;
        positions[key] = total_quantity;
      }
    } else {
      // 卖出增加空头持仓(用负数表示)
      if (positions.find(key) == positions.end()) {
        positions[key] = -trade.size;
        avg_prices[key] = trade.price;
      } else {
        // 加权平均计算均价
        double total_quantity = positions[key] - trade.size;
        avg_prices[key] = (avg_prices[key] * std::abs(positions[key]) +
                           trade.price * trade.size) /
                          std::abs(total_quantity);
        positions[key] = total_quantity;
      }
    }
  }

  // 根据最新市场价格计算持仓价值
  for (const auto& position : positions) {
    Leg leg = position.first.first;
    OrderSide side = position.first.second;
    double quantity = position.second;
    double avg_price = avg_prices.at(position.first);

    auto it = last_prices_.find(leg);
    if (it != last_prices_.end()) {
      double current_price = it->second;

      if (side == OrderSide::BUY) {
        // 多头持仓盈亏 = 持仓数量 * (当前价格 - 持仓均价)
        total_equity += quantity * (current_price - avg_price);
      } else {
        // 空头持仓盈亏 = 持仓数量 * (持仓均价 - 当前价格)
        total_equity += std::abs(quantity) * (avg_price - current_price);
      }
    }
  }

  return total_equity;
}

// 获取现金余额
double MakerSimulator::get_cash() const { return cash_; }

// 检查是否为吃单
bool MakerSimulator::is_taker_order(Leg leg, OrderSide side,
                                    double price) const {
  // 检查订单是否会穿过价差成为吃单
  auto it = last_prices_.find(leg);
  if (it != last_prices_.end()) {
    double last_price = it->second;
    if (side == OrderSide::BUY && price >= last_price) {
      return true;  // 买入价高于等于最新价,为吃单
    } else if (side == OrderSide::SELL && price <= last_price) {
      return true;  // 卖出价低于等于最新价,为吃单
    }
  }
  return false;
}

// 匹配订单
void MakerSimulator::match_order(Order& order, const TickData& tick) {
  bool matched = false;

  // 买入订单,当交易价格小于等于我们的价格时匹配
  if (order.side == OrderSide::BUY && tick.last_price <= order.price) {
    matched = true;
  }
  // 卖出订单,当交易价格大于等于我们的价格时匹配
  else if (order.side == OrderSide::SELL && tick.last_price >= order.price) {
    matched = true;
  }

  if (matched) {
    // 计算订单成交数量(这次我们尝试完全成交)
    double remaining_size = order.size - order.filled_size;
    double fill_size = remaining_size;  // 完全成交剩余数量

    // 创建成交记录
    Trade trade;
    trade.order_id = order.order_id;
    trade.leg = order.leg;
    trade.side = order.side;
    trade.price = order.price;  // 使用我们的价格,不是成交价格
    trade.size = fill_size;
    trade.timestamp = tick.timestamp;
    trade.matched_by = tick.trade_id;

    trades_.push_back(trade);

    // 更新资金
    if (order.side == OrderSide::BUY) {
      cash_ -= trade.price * trade.size;  // 买入扣减现金
    } else {
      cash_ += trade.price * trade.size;  // 卖出增加现金
    }

    // 更新订单
    order.filled_size += fill_size;
    order.last_update = std::chrono::steady_clock::now();

    if (order.filled_size >= order.size) {
      order.status = OrderStatus::FILLED;
    } else {
      order.status = OrderStatus::PARTIALLY_FILLED;
    }
  }
}

// 内部撤销订单方法
void MakerSimulator::cancel_order_internal(Order& order) {
  if (order.status != OrderStatus::CANCELLED &&
      order.status != OrderStatus::FILLED) {
    order.status = OrderStatus::CANCELLED;
    order.last_update = std::chrono::steady_clock::now();
  }
}
#include <cassert>
#include <chrono>
#include <iostream>
#include <thread>

#include "maker_simulator.h"

// 测试场景A:完全成交
void test_scenario_a() {
  std::cout << "=== 测试场景 A: 完全成交 ===" << std::endl;

  MakerSimulator simulator;

  // 提交订单
  bool result =
      simulator.post_order("order1", Leg::A, OrderSide::BUY, 100.0, 10.0);
  assert(result);

  // 创建能够匹配订单的行情数据
  TickData tick;
  tick.bid_price = 99.0;
  tick.ask_price = 101.0;
  tick.last_price = 100.0;  // 与我们的买入价100.0匹配
  tick.timestamp = std::chrono::steady_clock::now();
  tick.trade_id = "trade1";

  // 处理行情
  simulator.on_tick(Leg::A, tick);

  // 检查结果
  const auto& orders = simulator.get_orders();
  const auto& trades = simulator.get_trades();

  assert(orders.at("order1").status == OrderStatus::FILLED);
  assert(trades.size() >= 1);

  std::cout << "场景 A 通过: 订单完全成交" << std::endl;
}

// 测试场景B:部分成交
void test_scenario_b() {
  std::cout << "=== 测试场景 B: 部分成交 ===" << std::endl;

  MakerSimulator simulator;

  // 提交订单
  bool result =
      simulator.post_order("order2", Leg::B, OrderSide::SELL, 105.0, 20.0);
  assert(result);

  // 创建能够部分匹配订单的行情数据
  TickData tick;
  tick.bid_price = 104.0;
  tick.ask_price = 106.0;
  tick.last_price = 105.0;  // 与我们的卖出价105.0匹配
  tick.timestamp = std::chrono::steady_clock::now();
  tick.trade_id = "trade2";

  // 处理行情
  simulator.on_tick(Leg::B, tick);

  // 检查结果 - 应该是完全成交(现在我们的逻辑是完全成交)
  const auto& orders = simulator.get_orders();
  const auto& trades = simulator.get_trades();

  assert(orders.at("order2").status == OrderStatus::FILLED);
  assert(trades.size() >= 1);
  assert(orders.at("order2").filled_size == 20.0);

  std::cout << "场景 B 通过: 订单完全成交" << std::endl;
}

// 测试场景C:一条腿成交,另一条腿未成交
void test_scenario_c() {
  std::cout << "=== 测试场景 C: 一条腿成交,另一条腿未成交 ===" << std::endl;

  MakerSimulator simulator;

  // 在腿A提交买入订单
  bool result1 =
      simulator.post_order("order3a", Leg::A, OrderSide::BUY, 100.0, 10.0);
  assert(result1);

  // 在腿B提交卖出订单
  bool result2 =
      simulator.post_order("order3b", Leg::B, OrderSide::SELL, 105.0, 10.0);
  assert(result2);

  // 创建能够匹配腿A的行情数据
  TickData tickA;
  tickA.bid_price = 99.0;
  tickA.ask_price = 101.0;
  tickA.last_price = 100.0;  // 与我们的买入价100.0匹配
  tickA.timestamp = std::chrono::steady_clock::now();
  tickA.trade_id = "trade3a";

  // 处理腿A的行情
  simulator.on_tick(Leg::A, tickA);

  // 创建不能匹配腿B的行情数据
  TickData tickB;
  tickB.bid_price = 104.0;
  tickB.ask_price = 106.0;
  tickB.last_price = 104.5;  // 不匹配我们的卖出价105.0
  tickB.timestamp = std::chrono::steady_clock::now();
  tickB.trade_id = "trade3b";

  // 处理腿B的行情
  simulator.on_tick(Leg::B, tickB);

  // 检查结果
  const auto& orders = simulator.get_orders();
  const auto& trades = simulator.get_trades();

  // 腿A应该已完全成交
  assert(orders.at("order3a").status == OrderStatus::FILLED);

  // 腿B应该未成交
  assert(orders.at("order3b").status == OrderStatus::NEW);

  std::cout << "场景 C 通过: 一条腿成交,另一条腿未成交" << std::endl;
}

// 测试场景D:吃单尝试被拒绝
void test_scenario_d() {
  std::cout << "=== 测试场景 D: 吃单尝试被拒绝 ===" << std::endl;

  MakerSimulator simulator;

  // 设置最新价格
  TickData initial_tick;
  initial_tick.bid_price = 99.0;
  initial_tick.ask_price = 101.0;
  initial_tick.last_price = 100.0;
  initial_tick.timestamp = std::chrono::steady_clock::now();
  initial_tick.trade_id = "initial";

  simulator.on_tick(Leg::A, initial_tick);

  // 尝试提交吃单(买入价高于最新价)
  bool result =
      simulator.post_order("order4", Leg::A, OrderSide::BUY, 101.5, 10.0);

  // 应该被拒绝
  assert(!result);

  // 检查订单未被添加
  const auto& orders = simulator.get_orders();
  assert(orders.find("order4") == orders.end());

  std::cout << "场景 D 通过: 吃单尝试被正确拒绝" << std::endl;
}

// 测试场景E:重复订单处理
void test_scenario_e() {
  std::cout << "=== 测试场景 E: 重复订单处理 ===" << std::endl;

  MakerSimulator simulator;

  // 提交订单
  bool result1 =
      simulator.post_order("order5", Leg::A, OrderSide::BUY, 100.0, 10.0);
  assert(result1);

  // 获取原始订单信息
  const auto& orders_before = simulator.get_orders();
  double original_size = orders_before.at("order5").size;

  // 再次提交相同ID的订单(应该替换原来的订单)
  bool result2 =
      simulator.post_order("order5", Leg::A, OrderSide::SELL, 95.0, 5.0);
  // 这应该会替换现有订单

  // 检查我们仍然只有一个订单,但是属性已经改变
  const auto& orders = simulator.get_orders();
  assert(orders.size() == 1);
  assert(orders.begin()->first == "order5");
  assert(orders.at("order5").side == OrderSide::SELL);
  assert(orders.at("order5").price == 95.0);
  assert(orders.at("order5").size == 5.0);

  std::cout << "场景 E 通过: 重复订单被正确处理" << std::endl;
}

// 主函数
int main() {
  std::cout << "运行 Maker Simulator 测试场景" << std::endl;

  test_scenario_a();
  test_scenario_b();
  test_scenario_c();
  test_scenario_d();
  test_scenario_e();

  std::cout << "\n所有测试场景通过!" << std::endl;

  return 0;
}