副标题:从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 | 平衡冲击与风险 | 低-中 | 低-中 | 高 |
| 手动拆解 | 小单/非敏感订单 | 高 | 低 | 低 |
核心原则:
- 大单必须拆,不拆必被盯
- 算法选择取决于流动性、波动率、时间敏感性
- 路由优化是毫秒级的竞争,必须精雕细琢
- 回测是验证拆单算法的唯一标准
《注:若有发现问题欢迎大家提出来纠正》
以上仅为技术分享参考,不构成投资建议