高性能订单路由与智能拆单算法:Qt在量化交易系统中的核心架构——毫秒级延迟下如何隐藏你的交易意图?

副标题:从TWAP/VWAP到机器学习驱动的智能拆单,源码级剖析订单路由引擎的架构设计与性能优化


一、引言:为什么需要订单路由与拆单?

在量化交易系统中,当你需要买入10万股茅台(600519)时,直接下一个10万股的市价单会立即冲击市场,导致:

  • 市场冲击(Market Impact):大单暴露,价格滑点急剧扩大
  • 信息不对称风险:被高频交易者识别并front-run
  • 成交率下降:流动性不足时无法完全成交

订单路由(Order Routing)智能拆单(Smart Order Splitting) 是解决这些问题的核心技术。本文从Qt/C++实战角度,完整剖析一个生产级订单路由引擎的架构设计。


二、系统架构:订单路由的分层模型

复制代码
┌──────────────────────────────────────────────────┐
│  Layer 4: 策略层  (量化策略发出原始订单)           │
│    OrderRequest { symbol, side, qty, orderType } │
├──────────────────────────────────────────────────┤
│  Layer 3: 拆单引擎 (Order Splitter)              │
│    TWAP / VWAP / POV / Implementation Shortfall  │
├──────────────────────────────────────────────────┤
│  Layer 2: 路由引擎 (Order Router)                │
│    券商选择 / 席位选择 / 智能路由                   │
├──────────────────────────────────────────────────┤
│  Layer 1: 执行层  (Order Executor)               │
│    CTP / OMS / 券商API 适配器                     │
└──────────────────────────────────────────────────┘

三、订单拆单算法详解

3.1 TWAP(时间加权平均价格)算法

TWAP将大单均匀分散到指定时间段内:

cpp 复制代码
/**
 * TWAP拆单引擎
 * 策略:将totalQty均匀分散到N个时间片,每个时间片发送等量子单
 */
class TWAPOrderSplitter : public QObject
{
    Q_OBJECT

public:
    struct Config {
        QString symbol;           // 标的代码
        double totalQty;          // 总数量
        qint64 startTime;         // 开始时间(Unix时间戳ms)
        qint64 endTime;           // 结束时间
        int numSlices;            // 拆分数(时间片数量)
        double maxSliceQty;       // 单笔最大数量
        double minSliceQty;       // 单笔最小数量
        int randomJitterMs;       // 随机抖动(隐藏模式)
    };

    explicit TWAPOrderSplitter(const Config &config, QObject *parent = nullptr)
        : QObject(parent), m_config(config), m_executedQty(0)
    {
        calculateSlices();
        startTimers();
    }

signals:
    void sliceOrderGenerated(const Order &order);  // 发出子单
    void executionComplete();
    void progressUpdated(double pct, double avgPrice);

private:
    void calculateSlices()
    {
        qint64 totalDuration = m_config.endTime - m_config.startTime;
        qint64 sliceDuration = totalDuration / m_config.numSlices;

        double baseQty = m_config.totalQty / m_config.numSlices;

        m_slices.clear();
        double remaining = m_config.totalQty;

        for (int i = 0; i < m_config.numSlices && remaining > 0; ++i) {
            Slice s;
            s.sliceIndex = i;
            s.execTime = m_config.startTime + i * sliceDuration;

            // 加入随机扰动(隐藏算法模式)
            if (m_config.randomJitterMs > 0) {
                s.execTime += QRandomGenerator::global()->bounded(
                    -m_config.randomJitterMs, m_config.randomJitterMs);
            }

            s.quantity = qMin(baseQty, remaining);
            s.quantity = qBound(m_config.minSliceQty,
                                 s.quantity,
                                 m_config.maxSliceQty);

            remaining -= s.quantity;
            m_slices << s;
        }

        // 剩余量加到最后一个slice
        if (remaining > 0 && !m_slices.isEmpty()) {
            m_slices.last().quantity += remaining;
        }
    }

    void startTimers()
    {
        for (const Slice &s : m_slices) {
            auto *timer = new QTimer(this);
            timer->setSingleShot(true);
            timer->setInterval(std::max(0LL,
                s.execTime - QDateTime::currentMSecsSinceEpoch()));

            QObject::connect(timer, &QTimer::timeout,
                this, [this, s]() {
                    executeSlice(s);
                });

            timer->start();
            m_timers << timer;
        }
    }

    void executeSlice(const Slice &s)
    {
        Order order;
        order.symbol = m_config.symbol;
        order.side = (m_config.totalQty > 0) ? Order::Buy : Order::Sell;
        order.quantity = s.quantity;
        order.orderType = Order::Limit;
        order.price = m_currentMarketPrice;  // 使用当前市场价
        order.sliceIndex = s.sliceIndex;

        m_executedQty += s.quantity;
        emit sliceOrderGenerated(order);

        if (qAbs(m_config.totalQty - m_executedQty) < 0.001) {
            emit executionComplete();
        }
    }

    struct Slice {
        int sliceIndex;
        qint64 execTime;
        double quantity;
    };

    Config m_config;
    QList<Slice> m_slices;
    QList<QTimer*> m_timers;
    double m_executedQty;
    double m_currentMarketPrice;
};

3.2 VWAP(成交量加权平均价格)算法

VWAP根据市场成交量分布动态调整拆单节奏:

cpp 复制代码
/**
 * VWAP拆单引擎
 * 策略:根据历史成交量曲线,在高流动性时段多发单
 */
class VWAPOrderSplitter : public QObject
{
    Q_OBJECT

public:
    struct HistoricalVolumeProfile {
        // 每个时间段的成交量占比(基于历史数据)
        // 例如:09:30-09:45 = 8%, 09:45-10:00 = 6%, ...
        QVector<QPair<QTime, double>> volumeCurve;
    };

    explicit VWAPOrderSplitter(const QString &symbol,
                                double totalQty,
                                const HistoricalVolumeProfile &profile,
                                QObject *parent = nullptr)
        : QObject(parent), m_symbol(symbol)
        , m_totalQty(totalQty), m_profile(profile)
    {
        buildExecutionSchedule();
    }

signals:
    void sliceOrderGenerated(const Order &order);

private:
    void buildExecutionSchedule()
    {
        // 根据历史成交量分布,计算每段时间应执行的量
        double cumulativePct = 0.0;

        for (const auto &entry : m_profile.volumeCurve) {
            QTime timeSlot = entry.first;
            double volumePct = entry.second;  // 该时段成交量占比

            ScheduleItem item;
            item.execTime = QDateTime(QDate::currentDate(), timeSlot);
            item.targetQty = m_totalQty * volumePct;
            item.cumulativePct = cumulativePct + volumePct;
            cumulativePct += volumePct;

            m_schedule << item;
        }
    }

    void onMarketTimeUpdate()
    {
        // 实时检查是否到达执行时间点
        QDateTime now = QDateTime::currentDateTime();

        for (auto it = m_schedule.begin(); it != m_schedule.end(); ) {
            if (now >= it->execTime && !it->executed) {
                Order order;
                order.symbol = m_symbol;
                order.quantity = it->targetQty;
                order.orderType = Order::Limit;
                // VWAP价格:使用近期VWAP作为参考
                order.price = calculateRealTimeVWAP();

                emit sliceOrderGenerated(order);
                it->executed = true;
            }
            ++it;
        }
    }

    double calculateRealTimeVWAP()
    {
        // VWAP = Σ(Price × Volume) / Σ(Volume)
        double sumPV = 0.0, sumV = 0.0;
        for (const auto &tick : m_recentTrades) {
            sumPV += tick.price * tick.volume;
            sumV += tick.volume;
        }
        return sumV > 0 ? sumPV / sumV : m_fallbackPrice;
    }

    struct ScheduleItem {
        QDateTime execTime;
        double targetQty;
        double cumulativePct;
        bool executed = false;
    };

    QString m_symbol;
    double m_totalQty;
    HistoricalVolumeProfile m_profile;
    QList<ScheduleItem> m_schedule;
    QList<TradeTick> m_recentTrades;
    double m_fallbackPrice;
};

3.3 POV(Percentage of Volume)算法

POV根据市场实时成交量动态调整发送速率:

cpp 复制代码
/**
 * POV拆单引擎
 * 策略:保持订单发送量不超过市场成交量的特定比例(如10%)
 * 优势:被动跟随市场,市场冲击最小
 */
class POVOrderSplitter : public QObject
{
    Q_OBJECT

public:
    struct Config {
        double targetPOV;      // 目标参与度,如0.10表示10%
        double maxParticipation; // 最大参与度上限
        qint64 lookbackMs;     // 成交量回溯窗口(ms)
        double minOrderQty;    // 最小子单量
    };

    explicit POVOrderSplitter(const Config &config, QObject *parent = nullptr)
        : QObject(parent), m_config(config), m_remainingQty(0)
    {}

    void start(const QString &symbol, double totalQty)
    {
        m_symbol = symbol;
        m_remainingQty = totalQty;
        m_startTime = QDateTime::currentMSecsSinceEpoch();

        // 启动高频成交量监控(tick级)
        connect(&m_tickTimer, &QTimer::timeout,
                this, &POVOrderSplitter::onTick);
        m_tickTimer.start(100);  // 100ms检查一次
    }

signals:
    void sliceOrderGenerated(const Order &order);

private:
    void onTick()
    {
        // 1. 计算近期市场成交量
        qint64 now = QDateTime::currentMSecsSinceEpoch();
        qint64 lookbackStart = now - m_config.lookbackMs;

        double marketVolume = calculateMarketVolumeInWindow(
            lookbackStart, now);

        // 2. 根据POV计算本周期可发送量
        double maxQtyThisCycle = marketVolume * m_config.targetPOV;
        double qtyToSend = qMin(maxQtyThisCycle, m_remainingQty);
        qtyToSend = qMax(qtyToSend, m_config.minOrderQty);

        if (qtyToSend > 0 && m_remainingQty > 0) {
            Order order;
            order.symbol = m_symbol;
            order.quantity = qtyToSend;
            order.orderType = Order::Limit;
            order.price = getMidPrice();  // 买卖中间价

            emit sliceOrderGenerated(order);
            m_remainingQty -= qtyToSend;
        }

        // 3. 如果参与度超限,暂停发送
        double currentPOV = calculateCurrentParticipation();
        if (currentPOV > m_config.maxParticipation) {
            // 暂停,等待市场成交量上升
            m_pauseUntil = now + 5000;  // 暂停5秒
        }
    }

    double calculateMarketVolumeInWindow(qint64 start, qint64 end)
    {
        double vol = 0;
        for (const auto &tick : m_marketTicks) {
            if (tick.timestamp >= start && tick.timestamp <= end) {
                vol += tick.volume;
            }
        }
        return vol;
    }

    QString m_symbol;
    double m_remainingQty;
    Config m_config;
    QTimer m_tickTimer;
    qint64 m_startTime;
    qint64 m_pauseUntil = 0;
    QList<MarketTick> m_marketTicks;
};

四、智能订单路由(Smart Order Router, SOR)

4.1 多券商/多席位路由策略

cpp 复制代码
/**
 * 智能订单路由器
 * 功能:根据价格、流动性、手续费选择最优执行路径
 */
class SmartOrderRouter : public QObject
{
    Q_OBJECT

public:
    struct Venue {               // 交易场所(券商/交易所)
        QString venueId;
        QString name;
        double feeRate;          // 手续费率
        int latencyMs;           // 延迟(ms)
        double availableLiquidity; // 可用流动性
        bool isActive;
    };

    explicit SmartOrderRouter(QObject *parent = nullptr) : QObject(parent) {}

    void addVenue(const Venue &venue) { m_venues << venue; }

    /**
     * 核心路由决策
     * 返回:最优场所列表(可能拆分到多个场所)
     */
    QList<RoutingDecision> route(const Order &order)
    {
        QList<RoutingDecision> decisions;

        if (order.orderType == Order::Market) {
            // 市价单:优先选择流动性最好的场所
            decisions = routeMarketOrder(order);
        } else {
            // 限价单:优先选择价格最好的场所
            decisions = routeLimitOrder(order);
        }

        return decisions;
    }

private:
    QList<RoutingDecision> routeMarketOrder(const Order &order)
    {
        // 策略:将订单拆分到多个场所,降低市场冲击
        QList<Venue*> sortedVenues = sortVenuesByLiquidity();

        double remaining = order.quantity;
        QList<RoutingDecision> result;

        for (Venue *v : sortedVenues) {
            if (remaining <= 0) break;
            if (!v->isActive) continue;

            RoutingDecision d;
            d.venue = v;
            d.quantity = qMin(remaining, v->availableLiquidity * 0.1);
            d.estimatedCost = d.quantity * v->feeRate;
            d.priority = calculatePriority(*v, order);

            remaining -= d.quantity;
            result << d;
        }

        return result;
    }

    QList<RoutingDecision> routeLimitOrder(const Order &order)
    {
        // 策略:选择价格最好的场所(最优买卖价)
        QList<Venue*> sortedVenues = sortVenuesByPrice(order.side);

        // 限价单通常只发到最优价格的场所
        if (!sortedVenues.isEmpty()) {
            RoutingDecision d;
            d.venue = sortedVenues.first();
            d.quantity = order.quantity;
            d.estimatedCost = order.quantity * d.venue->feeRate;
            return {d};
        }

        return {};
    }

    /**
     * 综合评分:价格优势(40%) + 流动性(30%) + 延迟(20%) + 手续费(10%)
     */
    double calculatePriority(const Venue &v, const Order &order)
    {
        double priceScore = normalizePriceScore(v, order) * 0.4;
        double liquidityScore = qBound(0.0, v.availableLiquidity / 1000000.0, 1.0) * 0.3;
        double latencyScore = (100.0 - qBound(0, v.latencyMs, 100)) / 100.0 * 0.2;
        double feeScore = (0.001 - qBound(0.0, v.feeRate, 0.001)) / 0.001 * 0.1;

        return priceScore + liquidityScore + latencyScore + feeScore;
    }

    QList<Venue*> sortVenuesByLiquidity()
    {
        QList<Venue*> result;
        for (auto &v : m_venues) result << &v;
        std::sort(result.begin(), result.end(),
            [](Venue *a, Venue *b) {
                return a->availableLiquidity > b->availableLiquidity;
            });
        return result;
    }

    struct RoutingDecision {
        Venue *venue;
        double quantity;
        double estimatedCost;
        double priority;
    };

    QList<Venue> m_venues;
};

4.2 延迟敏感的路由优化

cpp 复制代码
/**
 * 低延迟路由优化器
 * 使用Qt的信号槽机制和QTimer高精度定时器
 */
class LowLatencyRouter : public QObject
{
    Q_OBJECT

public:
    explicit LowLatencyRouter(QObject *parent = nullptr)
        : QObject(parent)
    {
        // 使用Qt::PreciseTimer实现高精度定时
        m_preciseTimer = new QTimer(this);
        m_preciseTimer->setTimerType(Qt::PreciseTimer);
        connect(m_preciseTimer, &QTimer::timeout,
                this, &LowLatencyRouter::onPreciseTick);
    }

    void routeWithMinLatency(const Order &order)
    {
        // 并行发送到所有场所,谁先成交算谁的
        // 使用Qt Concurrent实现并行下单
        QList<QFuture<void>> futures;
        for (const auto &venue : m_venues) {
            QFuture<void> f = QtConcurrent::run([this, order, venue]() {
                sendOrderToVenue(order, venue);
            });
            futures << f;
        }

        // 等待第一个成交确认(使用Qt信号槽)
        QEventLoop loop;
        QFutureWatcher<void> watcher;
        connect(&watcher, &QFutureWatcher<void>::finished,
                &loop, &QEventLoop::quit);
        watcher.setFuture(futures.first());
        loop.exec();
    }

private:
    void sendOrderToVenue(const Order &order, const Venue &venue)
    {
        // 记录发送时间(用于延迟分析)
        qint64 sendTime = QDateTime::currentMSecsSinceEpoch();

        // 通过券商API发送订单
        QString orderId = venue.api->sendOrder(order);

        // 等待成交确认(使用QTimer做超时管理)
        auto *timeoutTimer = new QTimer(this);
        timeoutTimer->setSingleShot(true);
        timeoutTimer->setInterval(5000);  // 5秒超时

        connect(timeoutTimer, &QTimer::timeout, this, [orderId, venue]() {
            qWarning() << "Order" << orderId
                       << "to venue" << venue.name << "timed out";
        });

        timeoutTimer->start();
    }

    QTimer *m_preciseTimer;
    QList<Venue> m_venues;
};

五、Implementation Shortfall(IS)算法

IS算法考虑市场冲击和时机风险,动态调整执行节奏:

cpp 复制代码
/**
 * Implementation Shortfall 拆单引擎
 * 目标:最小化冲击成本 + 时机风险
 */
class ISOrderSplitter : public QObject
{
    Q_OBJECT

public:
    struct Config {
        double riskAversion;     // 风险厌恶系数(0-1)
        double marketImpactFactor; // 市场冲击因子
        int timeHorizonMinutes;  // 执行时间范围
    };

    explicit ISOrderSplitter(const Config &config, QObject *parent = nullptr)
        : QObject(parent), m_config(config)
    {}

    QVector<double> calculateOptimalSchedule(double totalQty)
    {
        /**
         * 使用Almgren-Chriss模型计算最优执行轨迹
         *
         * 目标函数:
         *   min E[(X_T - Σp_i·q_i)²] + λ·Var[Σp_i·q_i]
         * 其中 λ = riskAversion
         *
         * 解析解(简化版):
         *   q_t = (2·(T-t) / T²) · Q_total   (线性执行)
         * 或更优的:
         *   q_t = (η/(2λσ²)) · (p_t - p_0)   (根据价格偏离动态调整)
         */

        int T = m_config.timeHorizonMinutes;
        QVector<double> schedule(T, 0.0);

        double eta = m_config.marketImpactFactor;   // 冲击系数
        double lambda = m_config.riskAversion;       // 风险厌恶
        double sigma = calculateVolatility();        // 波动率

        // Almgren-Chriss最优执行率
        double k = qSqrt(eta / (lambda * sigma * sigma));
        double c1 = (1.0 - qExp(-k * T)) / (1.0 + qExp(-k * T));
        double c2 = (1.0 + qExp(-k * T)) / (1.0 - qExp(-k * T));

        for (int t = 0; t < T; ++t) {
            double tau = T - t;
            double numerator = qExp(k * tau) - qExp(-k * tau);
            double denominator = qExp(k * T) - qExp(-k * T);
            double frac = numerator / denominator;

            schedule[t] = totalQty * frac;  // 第t分钟执行量
        }

        return schedule;
    }

private:
    double calculateVolatility() const
    {
        // 使用近期收益率计算波动率(标准差)
        QList<double> returns;
        for (int i = 1; i < m_priceHistory.size(); ++i) {
            double r = qLn(m_priceHistory[i] / m_priceHistory[i-1]);
            returns << r;
        }

        double mean = std::accumulate(returns.begin(), returns.end(), 0.0)
                     / returns.size();
        double variance = 0;
        for (double r : returns) {
            variance += (r - mean) * (r - mean);
        }

        return qSqrt(variance / returns.size());
    }

    Config m_config;
    QList<double> m_priceHistory;
};

六、性能优化:低延迟关键技术

6.1 使用内存池避免动态分配

cpp 复制代码
/**
 * 订单对象内存池
 * 避免高频交易场景下QObject创建/销毁的开销
 */
template<typename T>
class ObjectPool
{
public:
    explicit ObjectPool(int initialSize = 1024)
    {
        for (int i = 0; i < initialSize; ++i) {
            m_freeList.append(new T);
        }
    }

    T* acquire()
    {
        if (m_freeList.isEmpty()) {
            // 池已空,创建新的(应该很少发生)
            return new T;
        }
        return m_freeList.takeLast();
    }

    void release(T *obj)
    {
        obj->reset();  // 重置对象状态
        m_freeList.append(obj);
    }

    ~ObjectPool()
    {
        qDeleteAll(m_freeList);
    }

private:
    QList<T*> m_freeList;
};

6.2 使用无锁队列进行跨线程通信

cpp 复制代码
#include <QAtomicInt>
#include <QAtomicPointer>

/**
 * 无锁环形缓冲区(Lock-Free Ring Buffer)
 * 用于订单路由引擎的高频跨线程通信
 */
template<typename T, int Size>
class LockFreeRingBuffer
{
public:
    LockFreeRingBuffer() : m_head(0), m_tail(0) {}

    bool enqueue(const T &item)
    {
        int head = m_head.loadAcquire();
        int nextHead = (head + 1) % Size;

        if (nextHead == m_tail.loadAcquire()) {
            return false;  // 队列满
        }

        m_buffer[head] = item;
        m_head.storeRelease(nextHead);
        return true;
    }

    bool dequeue(T &item)
    {
        int tail = m_tail.loadAcquire();

        if (tail == m_head.loadAcquire()) {
            return false;  // 队列空
        }

        item = m_buffer[tail];
        m_tail.storeRelease((tail + 1) % Size);
        return true;
    }

private:
    T m_buffer[Size];
    QAtomicInt m_head;
    QAtomicInt m_tail;
};

6.3 使用Qt::DirectConnection减少信号槽开销

cpp 复制代码
// 在高频场景下,使用Qt::DirectConnection避免事件队列延迟
connect(marketDataFeed, &MarketDataFeed::tickArrived,
        this, &OrderRouter::onTickArrived,
        Qt::DirectConnection);  // 同步调用,无队列延迟

// 注意:DirectConnection要求槽函数在同一线程,
// 跨线程场景仍需使用QueuedConnection

七、完整实战:订单路由系统Demo

cpp 复制代码
#include <QApplication>
#include <QMainWindow>
#include <QWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QComboBox>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QLabel>
#include <QTextEdit>
#include <QTimer>
#include <QDateTime>
#include <QRandomGenerator>
#include <QtConcurrent>
#include <QFutureWatcher>

// ============ 数据结构 ============

struct Order {
    enum Side { Buy, Sell } side;
    enum Type { Market, Limit } orderType;
    QString orderId;
    QString symbol;
    double quantity;
    double price;
    int sliceIndex = -1;
    qint64 timestamp;
};

struct ExecutionReport {
    QString orderId;
    QString execId;
    double filledQty;
    double filledPrice;
    qint64 timestamp;
    QString venueId;
};

// ============ 拆单引擎 ============

class OrderSplitterEngine : public QObject
{
    Q_OBJECT

public:
    explicit OrderSplitterEngine(QObject *parent = nullptr) : QObject(parent) {}

    void submitOrder(const Order &order, const QString &algorithm)
    {
        m_originalOrder = order;
        m_algorithm = algorithm;
        m_executedQty = 0;
        m_startTime = QDateTime::currentMSecsSinceEpoch();

        if (algorithm == "TWAP") {
            startTWAP();
        } else if (algorithm == "VWAP") {
            startVWAP();
        } else if (algorithm == "POV") {
            startPOV();
        }
    }

signals:
    void sliceGenerated(const Order &slice);
    void executionUpdate(double pct, double avgPrice);
    void executionComplete();

private:
    void startTWAP()
    {
        // 模拟:10个时间片,每个1秒
        int numSlices = 10;
        double qtyPerSlice = m_originalOrder.quantity / numSlices;

        auto *timer = new QTimer(this);
        connect(timer, &QTimer::timeout, this, [=, &qtyPerSlice]() mutable {
            static int sliceIdx = 0;
            if (sliceIdx >= numSlices) {
                timer->stop();
                emit executionComplete();
                return;
            }

            Order slice = m_originalOrder;
            slice.quantity = qtyPerSlice;
            slice.sliceIndex = sliceIdx;
            slice.timestamp = QDateTime::currentMSecsSinceEpoch();

            emit sliceGenerated(slice);

            m_executedQty += qtyPerSlice;
            sliceIdx++;

            emit executionUpdate(
                m_executedQty / m_originalOrder.quantity * 100.0,
                m_estimatedAvgPrice);
        });
        timer->start(1000);  // 每秒一个slice
    }

    void startVWAP()
    {
        // 简化:使用模拟成交量曲线
        QVector<double> volumeWeights = {0.08, 0.06, 0.07, 0.05, 0.06,
                                         0.08, 0.10, 0.12, 0.15, 0.23};
        double cumulative = 0;
        for (int i = 0; i < volumeWeights.size(); ++i) {
            QTimer::singleShot(i * 1000, this, [=]() {
                Order slice = m_originalOrder;
                slice.quantity = m_originalOrder.quantity * volumeWeights[i];
                slice.sliceIndex = i;
                slice.timestamp = QDateTime::currentMSecsSinceEpoch();
                emit sliceGenerated(slice);
            });
        }
    }

    void startPOV()
    {
        // 模拟:根据市场成交量动态调整
        auto *timer = new QTimer(this);
        connect(timer, &QTimer::timeout, this, [this]() {
            // 模拟市场成交量
            double marketVol = 1000 + QRandomGenerator::global()->bounded(500);
            double maxQty = marketVol * 0.10;  // 10% POV

            if (m_executedQty < m_originalOrder.quantity) {
                Order slice = m_originalOrder;
                slice.quantity = qMin(maxQty,
                    m_originalOrder.quantity - m_executedQty);
                slice.timestamp = QDateTime::currentMSecsSinceEpoch();
                emit sliceGenerated(slice);
                m_executedQty += slice.quantity;
            } else {
                timer->stop();
                emit executionComplete();
            }
        });
        timer->start(500);
    }

    Order m_originalOrder;
    QString m_algorithm;
    double m_executedQty = 0;
    double m_estimatedAvgPrice = 178.50;
    qint64 m_startTime;
};

// ============ 主窗口 ============

class OrderRoutingDemo : public QMainWindow
{
    Q_OBJECT

public:
    explicit OrderRoutingDemo(QWidget *parent = nullptr)
        : QMainWindow(parent)
    {
        setupUI();
        m_splitter = new OrderSplitterEngine(this);

        connect(m_splitter, &OrderSplitterEngine::sliceGenerated,
                this, &OrderRoutingDemo::onSliceGenerated);
        connect(m_splitter, &OrderSplitterEngine::executionUpdate,
                this, &OrderRoutingDemo::onExecutionUpdate);
        connect(m_splitter, &OrderSplitterEngine::executionComplete,
                this, [this]() {
                    m_log->append("✅ 执行完成!");
                });
    }

private:
    void setupUI()
    {
        auto *central = new QWidget(this);
        setCentralWidget(central);
        auto *mainLayout = new QVBoxLayout(central);

        // 控制面板
        auto *ctrlPanel = new QHBoxLayout;
        ctrlPanel->addWidget(new QLabel("标的:"));
        m_symbolCombo = new QComboBox;
        m_symbolCombo->addItems({"600519.SH", "000001.SZ", "AAPL.O", "TSLA.O"});
        ctrlPanel->addWidget(m_symbolCombo);

        ctrlPanel->addWidget(new QLabel("数量:"));
        m_qtySpin = new QDoubleSpinBox;
        m_qtySpin->setRange(100, 1000000);
        m_qtySpin->setValue(10000);
        m_qtySpin->setSingleStep(100);
        ctrlPanel->addWidget(m_qtySpin);

        ctrlPanel->addWidget(new QLabel("算法:"));
        m_algoCombo = new QComboBox;
        m_algoCombo->addItems({"TWAP", "VWAP", "POV"});
        ctrlPanel->addWidget(m_algoCombo);

        auto *startBtn = new QPushButton("开始拆单");
        connect(startBtn, &QPushButton::clicked,
                this, &OrderRoutingDemo::onStartSplit);
        ctrlPanel->addWidget(startBtn);

        mainLayout->addLayout(ctrlPanel);

        // 进度显示
        m_progressLabel = new QLabel("进度: 0%  |  预计均价: --");
        mainLayout->addWidget(m_progressLabel);

        // 日志
        m_log = new QTextEdit;
        m_log->setReadOnly(true);
        m_log->setFont(QFont("Consolas", 9));
        mainLayout->addWidget(new QLabel("执行日志:"));
        mainLayout->addWidget(m_log);

        setWindowTitle("Qt订单路由与拆单算法实战");
        resize(900, 600);
    }

private slots:
    void onStartSplit()
    {
        m_log->clear();
        m_log->append(QString("🚀 开始拆单: %1, 数量: %2, 算法: %3")
                      .arg(m_symbolCombo->currentText())
                      .arg(m_qtySpin->value())
                      .arg(m_algoCombo->currentText()));

        Order order;
        order.symbol = m_symbolCombo->currentText();
        order.side = Order::Buy;
        order.orderType = Order::Limit;
        order.quantity = m_qtySpin->value();
        order.price = 178.50;

        m_splitter->submitOrder(order, m_algoCombo->currentText());
    }

    void onSliceGenerated(const Order &slice)
    {
        QString msg = QString("[%1] Slice #%2: %3 × %4 @ %5")
                      .arg(QDateTime::fromMSecsSinceEpoch(slice.timestamp)
                           .toString("hh:mm:ss.zzz"))
                      .arg(slice.sliceIndex)
                      .arg(slice.quantity)
                      .arg(slice.symbol)
                      .arg(slice.price, 0, 'f', 2);
        m_log->append(msg);
    }

    void onExecutionUpdate(double pct, double avgPrice)
    {
        m_progressLabel->setText(
            QString("进度: %1%  |  预计均价: $%2")
            .arg(pct, 0, 'f', 1)
            .arg(avgPrice, 0, 'f', 2));
    }

private:
    QComboBox *m_symbolCombo;
    QDoubleSpinBox *m_qtySpin;
    QComboBox *m_algoCombo;
    QLabel *m_progressLabel;
    QTextEdit *m_log;
    OrderSplitterEngine *m_splitter;
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QApplication::setFont(QFont("Microsoft YaHei", 9));

    OrderRoutingDemo demo;
    demo.show();

    return app.exec();
}

#include "main.moc"

八、总结与算法选择指南

算法 适用场景 市场冲击 时机风险 实现复杂度
TWAP 流动性好的大盘股
VWAP 跟随市场节奏
POV 隐藏交易意图 最低
IS 平衡冲击与风险 低-中 低-中
手动拆解 小单/非敏感订单

核心原则:

  1. 大单必须拆,不拆必被盯
  2. 算法选择取决于流动性、波动率、时间敏感性
  3. 路由优化是毫秒级的竞争,必须精雕细琢
  4. 回测是验证拆单算法的唯一标准

《注:若有发现问题欢迎大家提出来纠正》

以上仅为技术分享参考,不构成投资建议

相关推荐
Scott9999HH5 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社6 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海6 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖7 小时前
JDK 26 新特性详解
java·开发语言
马优晨8 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
2601_960567969 小时前
电商套图自动化效率的工程量化分析——从逐张生成到批量套图的架构演进
运维·架构·自动化
shiyi.十一9 小时前
第2章:应用层 — 知识要点与架构
网络·计算机网络·架构
人邮异步社区10 小时前
怎么把C语言学到精通?
c语言·开发语言
张忠琳10 小时前
【NVIDIA】 NVIDIA Container Toolkit v1.19.1 — OCI 模块超深度分析之三
云原生·容器·架构·kubernetes·nvidia
心平气和量大福大10 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf