打开导航 打开导航 Open menu
量化交易系统开发(C++)/ 期权策略与风控 / 行业研究分析
量化交易系统開發(C++)/ 期权策略与风控 / 行业研究分析
C++ trading systems / options strategy & risk controls / equity research
adrian@adrianxv.cn
文章目录

交易系统:Order Manager 交易系统:Order Manager 交易系统:Order Manager

OrderManager 接收策略想要的订单意图,用本地状态和交易所回报来决定下一步该发新单、撤单还是等待。

讲到订单管理,最重要的就是理清楚一张订单可以有哪些状态。在本书当中,订单状态的定义比较简单,没有引入部分成交之类的细分状态。

enum class OMOrderState : int8_t {
    INVALID = 0,
    PENDING_NEW = 1,
    LIVE = 2,
    PENIDNG_CANCEL = 3,
    DEAD = 4
};

因此 OMOrder 的状态机如下图所示:

alt text

OrderManager 成员对象

typedef std::array<OMOrder, sideToIndex(Side::MAX) + 1> OMOrderSideHashMap;
// 这里花里胡哨的,是不是实质上就是买单和卖单分两边来管理?
typedef std::array<OMOrderSideHashMap, ME_MAX_TICKERS> OMOrderTickerSideHashMap;

class OrderManager {
private:
    TradeEngine* trade_engine_ = nullptr;
    cost RiskManager& risk_manager_;

    std::string time_str_;
    Common::Logger* logger_ = nullptr;

    OMOrderTickerSideHashMap ticker_side_order_;
    OrderId next_order_id_ = 1;
}

ticker_side_order_ 是二维数组,可以用“品种 + 买卖方向”来查找订单

typedef std::array<OMOrder, sideToIndex(Side::MAX) + 1> OMOrderSideHashMap;
typedef std::array<OMOrderSideHashMap, ME_MAX_TICKERS> OMOrderTickerSideHashMap;

OMOrderTickerSideHashMap ticker_side_order_;
OMOrder = ticker_side_order_[ticker_id][sideToIndex(Side::BUY / SELL)];

这里的 ticker_side_order_ 这个二维数组保存的是 OMOrder 对象,而不是指向这种对象的指针。我们可以发现,OrderManager 直接持有对象,没有通过内存池分配内存块。原因如下:

  1. 单一客户端的订单不多,且加以业务规则限制:每个 ticker 的买方和卖方各自最多只能有一张订单
  2. 单一客户端的订单不像订单簿那样需要频繁插入删除。订单状态变化只需修改已有对象的字段,无需频繁创建、销毁订单对象
  3. ticker_side_order_ 这个二维数组构造的时候,已经是固定大小且分配好内存了,因此后续使用的时候不会出现动态内存分配

因此 ticker_side_order_ 当中的 OMOrder 对象不会销毁,而是其字段不断地被修改。在以下几种情况下其字段会修改:

  1. 由 newOrder() 发出新订单的时候,全部字段重写
  2. 由 cancelOrder() 撤单的时候,更新 order_state_ 字段
  3. 全部成交、撤单成功之类的其它情况下,由 onOrderUpdate(事件类型) 修改其字段

OrderManager 向策略提供的唯一接口是 moveOrders()

newOrder()

auto OrderManager::newOrder(OMOrder* order, TickerId ticker_id, Price price, Side side, Qty qty) noexcept {
    // 根据传入的参数构造 MEClientRequest
    const Exchange::MEClientRequest new_request{Exchange::ClientRequestType::NEW, trade_engine_->clientId(), ticker_id, next_order_id_, side, price, qty};

    trade_engine_->sendClientRequest(&new_request);

    // 把 order 的状态修改为 PENDING_NEW
    // *order 是内部使用的结构体 OMOrder 类型的
    *order = {ticker_id, next_order_id_, side, price, qty, OMOrderState::PENDING_NEW};
    ++next_order_id_;
}

newOrder() 当中对于 order 对象修改的字段比较多

cancelOrder()

auto OrderManager::cancelOrder(OMOrder* order) noexcept {
    // 根据传入的参数构造 MEClientRequest
    const Exchange::MEClientRequest cancel_request{Exchange::ClientRequestType::CANCEL, trade_engine_->clientId(), order->ticker_id_, order->order_id_, order->side_, order->price_, order->qty_};

    trade_engine_->sendClientRequest(&cancel_request);

    order->order_state_ = OMOrderState::PENDING_CANCEL;
}

撤单的时候对于被撤订单在 ticker_side_order_ 当中的 OMOrder 对象,只修改其 order_state_ 字段,意味着其它字段保持原样,直到同 ticker 同方向有新订单时才被 addOrder() 覆盖掉。

moveOrder()

根据传入的目标 ticker、方向、价格和数量,检查一个 OMOrder 订单的当前状态。如果和期望状态不符,则靠撤单/重发新单来向目标靠拢。之所以说是向目标靠拢,是因为 OrderManager 只负责发单,而达成目标还需要交易所接受 OrderManager 的意图。

auto OrderManager::moveOrder(OMOrder* order, TickerId ticker_id, Price price, Side side, Qty qty) noexcept {
    // 根据订单状态来决定操作
    switch(order->order_state_) {
        case OMOrderState::LIVE: {
            // 和期望不符,直接撤单
            if (order->price_ != price || order->qty_ != qty) { cancelOrder(order); }
            break;
        }

        case OMOrderState::INVALID: 
        case OMOrderState::DEAD: {
            // 在这种情况下就要重新发单是不是?
            if (LIKELY(price != Price_INVALID)) {
                const auto risk_result = risk_manager_.checkPreTradeRisk(ticker_id, side, qty);
                
                if (LIKELY(risk_result == RiskCheckResult::ALLOWED)) {
                    newOrder(order, ticker_id, price, side, qty);
                }
                else {  // 风控未通过,不准发单
                    logger->log(......);
                }
            }
            break;
        }

        case OMOrderState::PENDING_NEW:
        case OMOrderState::PENDING_CANCEL:
            break;
    }
}

moveOrders()

这个方法是 OrderManager 面向策略的唯一接口(即前面定义的 newOrder(), cancelOrder()moveOrder() 都是 OrderManager 的内部辅助方法)。策略想要达成发新单、撤单、确保已发出的订单与策略意图相符的目的,都要调用本方法。

auto OrderManager::moveOrders(TickerId ticker_id, Price bid_price, Price ask_price, Qty bid_qty, Qty ask_qty) noexcept {
    auto bid_order = &(ticker_side_order_.at(ticker_id).at(sideToIndex(side)));
    moveOrder(bid_order, ticker_id, bid_price, Side::BUY, bid_qty);

    auto ask_order = &(ticker_side_order_.at(ticker_id)).at(sideToIndex(Side::SELL));
    moveOrder(ask_order, ticker_id, ask_price, Side::SELL, ask_qty);
}

这里不存在构造订单对象的过程。注意 OrderManager::ticker_side_order_ 这个二维数组保存的是 OMOrder 对象,且这些对象在这个二维数组构造的时候就被构造了

onOrderUpdate

根据私有订单回调更新 ticker_side_order_ 当中订单的状态

更新后只有三种情况:LIVE、DEAD 或维持现状

在 CANCEL_REJECTED 和 INVALID 的情况下,维持现状

auto onOrderUpdate(const Exchange::MEClientResponse* client_response) noexcept {
    auto order = &(ticker_side_order_.at(client_response->ticker_id_).at(sideToIndex(client_response->side_)));

    switch(client_response->type_) {
        case MEClientResponseType::ACCEPTED: {
            order->order_state_ = OMOrderState::LIVE;
            break;
        }
        case MEClientResponseType::FILLED: {
            order->order_state_ = OMOrderState::DEAD;
            break;
        }
        case MEClientResponseType::CANCELLED: {
            order->order_state_ = OMOrderState::DEAD;
            break;
        }
        case MEClientResponseType::CANCEL_REJECTED:
        case MEClientResponseType::INVALID: {
            break; // 维持原状不变
        }
    }
}