251 lines
7.2 KiB
Markdown
251 lines
7.2 KiB
Markdown
|
|
## qorderprocessor
|
|||
|
|
|
|||
|
|
完整头文件和cpp文件
|
|||
|
|
|
|||
|
|
以下是完整的头文件和实现文件代码,根据您提供的JSON格式订单簿数据进行了完整实现:
|
|||
|
|
|
|||
|
|
### 头文件 `qorderprocessor.h`
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
#ifndef QORDERPROCESSOR_H
|
|||
|
|
#define QORDERPROCESSOR_H
|
|||
|
|
|
|||
|
|
#include <QObject>
|
|||
|
|
#include <QVector>
|
|||
|
|
#include <QThreadPool>
|
|||
|
|
#include <QMutex>
|
|||
|
|
#include <QtConcurrent>
|
|||
|
|
|
|||
|
|
struct OrderBookItem {
|
|||
|
|
double price = 0.0;
|
|||
|
|
double volume = 0.0;
|
|||
|
|
int orderCount = 0;
|
|||
|
|
|
|||
|
|
bool isValid() const { return price > 0 && volume > 0; }
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
struct OrderBookData {
|
|||
|
|
QString securityCode;
|
|||
|
|
QString securityName;
|
|||
|
|
QVector<OrderBookItem> asks; // 卖盘
|
|||
|
|
QVector<OrderBookItem> bids; // 买盘
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
class QOrderProcessor : public QObject
|
|||
|
|
{
|
|||
|
|
Q_OBJECT
|
|||
|
|
public:
|
|||
|
|
explicit QOrderProcessor(QObject *parent = nullptr);
|
|||
|
|
~QOrderProcessor();
|
|||
|
|
|
|||
|
|
void processOrderBook(const QByteArray& jsonData);
|
|||
|
|
|
|||
|
|
signals:
|
|||
|
|
void maxAskOrderReady(double price, double volume, int orderCount);
|
|||
|
|
void maxBidOrderReady(double price, double volume, int orderCount);
|
|||
|
|
void maxOrdersReady(const OrderBookItem& maxAsk, const OrderBookItem& maxBid);
|
|||
|
|
void parseError(const QString& error);
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
OrderBookData parseOrderBookJson(const QByteArray& jsonData) const;
|
|||
|
|
std::pair<OrderBookItem, OrderBookItem> findMaxOrder(const QByteArray& jsonData) const;
|
|||
|
|
OrderBookItem findMaxVolumeItem(const QVector<OrderBookItem>& items) const;
|
|||
|
|
|
|||
|
|
QThreadPool m_threadPool;
|
|||
|
|
mutable QMutex m_resultMutex;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
#endif // QORDERPROCESSOR_H
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 实现文件 `qorderprocessor.cpp`
|
|||
|
|
|
|||
|
|
cpp
|
|||
|
|
|
|||
|
|
复制
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
#include "qorderprocessor.h"
|
|||
|
|
#include <QJsonDocument>
|
|||
|
|
#include <QJsonObject>
|
|||
|
|
#include <QJsonArray>
|
|||
|
|
#include <QDebug>
|
|||
|
|
#include <immintrin.h> // SIMD指令集头文件
|
|||
|
|
|
|||
|
|
QOrderProcessor::QOrderProcessor(QObject *parent)
|
|||
|
|
: QObject(parent)
|
|||
|
|
{
|
|||
|
|
const int threads = qBound(2, QThread::idealThreadCount() - 1, 8);
|
|||
|
|
m_threadPool.setMaxThreadCount(threads);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QOrderProcessor::~QOrderProcessor()
|
|||
|
|
{
|
|||
|
|
m_threadPool.waitForDone();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
OrderBookData QOrderProcessor::parseOrderBookJson(const QByteArray& jsonData) const
|
|||
|
|
{
|
|||
|
|
OrderBookData result;
|
|||
|
|
QJsonParseError parseError;
|
|||
|
|
QJsonDocument doc = QJsonDocument::fromJson(jsonData, &parseError);
|
|||
|
|
|
|||
|
|
if(parseError.error != QJsonParseError::NoError) {
|
|||
|
|
emit this->parseError(parseError.errorString());
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QJsonObject root = doc.object();
|
|||
|
|
if(!root.contains("s2c")) {
|
|||
|
|
emit this->parseError("Missing 's2c' field in JSON");
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QJsonObject s2c = root["s2c"].toObject();
|
|||
|
|
QJsonObject security = s2c["security"].toObject();
|
|||
|
|
|
|||
|
|
result.securityCode = security["code"].toString();
|
|||
|
|
result.securityName = s2c["name"].toString();
|
|||
|
|
|
|||
|
|
// 解析卖盘(asks)
|
|||
|
|
if(s2c.contains("orderBookAskList")) {
|
|||
|
|
QJsonArray askArray = s2c["orderBookAskList"].toArray();
|
|||
|
|
for(const QJsonValue& val : askArray) {
|
|||
|
|
QJsonObject obj = val.toObject();
|
|||
|
|
OrderBookItem item;
|
|||
|
|
item.price = obj["price"].toDouble();
|
|||
|
|
item.volume = obj["volume"].toString().toDouble(); // 字符串转double
|
|||
|
|
item.orderCount = obj["orederCount"].toInt(); // 注意原数据有拼写错误
|
|||
|
|
result.asks.append(item);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 解析买盘(bids)
|
|||
|
|
if(s2c.contains("orderBookBidList")) {
|
|||
|
|
QJsonArray bidArray = s2c["orderBookBidList"].toArray();
|
|||
|
|
for(const QJsonValue& val : bidArray) {
|
|||
|
|
QJsonObject obj = val.toObject();
|
|||
|
|
OrderBookItem item;
|
|||
|
|
item.price = obj["price"].toDouble();
|
|||
|
|
item.volume = obj["volume"].toString().toDouble();
|
|||
|
|
item.orderCount = obj["orederCount"].toInt();
|
|||
|
|
result.bids.append(item);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
OrderBookItem QOrderProcessor::findMaxVolumeItem(const QVector<OrderBookItem>& items) const
|
|||
|
|
{
|
|||
|
|
if(items.isEmpty()) return {};
|
|||
|
|
|
|||
|
|
#ifdef __AVX2__
|
|||
|
|
// AVX2 SIMD优化版本
|
|||
|
|
const double* volumes = &items[0].volume;
|
|||
|
|
const size_t size = items.size();
|
|||
|
|
|
|||
|
|
__m256d maxVec = _mm256_set1_pd(-DBL_MAX);
|
|||
|
|
double maxVolume = -DBL_MAX;
|
|||
|
|
OrderBookItem result;
|
|||
|
|
|
|||
|
|
size_t i = 0;
|
|||
|
|
for(; i + 4 <= size; i += 4) {
|
|||
|
|
__m256d current = _mm256_loadu_pd(volumes + i);
|
|||
|
|
__m256d cmp = _mm256_cmp_pd(current, maxVec, _CMP_GT_OS);
|
|||
|
|
|
|||
|
|
if(_mm256_movemask_pd(cmp)) {
|
|||
|
|
// 需要逐个比较
|
|||
|
|
for(size_t j = 0; j < 4; ++j) {
|
|||
|
|
if(items[i + j].volume > maxVolume) {
|
|||
|
|
maxVolume = items[i + j].volume;
|
|||
|
|
result = items[i + j];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
maxVec = _mm256_set1_pd(maxVolume);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 处理剩余元素
|
|||
|
|
for(; i < size; ++i) {
|
|||
|
|
if(items[i].volume > maxVolume) {
|
|||
|
|
maxVolume = items[i].volume;
|
|||
|
|
result = items[i];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
#else
|
|||
|
|
// 普通版本
|
|||
|
|
return *std::max_element(items.begin(), items.end(),
|
|||
|
|
[](const OrderBookItem& a, const OrderBookItem& b) {
|
|||
|
|
return a.volume < b.volume;
|
|||
|
|
});
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::pair<OrderBookItem, OrderBookItem> QOrderProcessor::findMaxOrder(const QByteArray& jsonData) const
|
|||
|
|
{
|
|||
|
|
OrderBookData data = parseOrderBookJson(jsonData);
|
|||
|
|
|
|||
|
|
OrderBookItem maxAsk = findMaxVolumeItem(data.asks);
|
|||
|
|
OrderBookItem maxBid = findMaxVolumeItem(data.bids);
|
|||
|
|
|
|||
|
|
return {maxAsk, maxBid};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void QOrderProcessor::processOrderBook(const QByteArray& jsonData)
|
|||
|
|
{
|
|||
|
|
QtConcurrent::run(&m_threadPool, [this, jsonData]() {
|
|||
|
|
auto result = findMaxOrder(jsonData);
|
|||
|
|
|
|||
|
|
QMutexLocker lock(&m_resultMutex);
|
|||
|
|
|
|||
|
|
// 发射卖盘最大订单信号
|
|||
|
|
if(result.first.isValid()) {
|
|||
|
|
emit maxAskOrderReady(result.first.price,
|
|||
|
|
result.first.volume,
|
|||
|
|
result.first.orderCount);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 发射买盘最大订单信号
|
|||
|
|
if(result.second.isValid()) {
|
|||
|
|
emit maxBidOrderReady(result.second.price,
|
|||
|
|
result.second.volume,
|
|||
|
|
result.second.orderCount);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 同时发射完整结果信号
|
|||
|
|
emit maxOrdersReady(result.first, result.second);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 主要改进说明:
|
|||
|
|
|
|||
|
|
1. **完整的数据结构**:
|
|||
|
|
- 定义了`OrderBookItem`和`OrderBookData`结构体来精确匹配JSON数据结构
|
|||
|
|
- 处理了volume字段从字符串到double的转换
|
|||
|
|
2. **健壮的JSON解析**:
|
|||
|
|
- 添加了完整的错误检查和处理
|
|||
|
|
- 处理了字段缺失的情况
|
|||
|
|
- 添加了parseError信号报告解析错误
|
|||
|
|
3. **优化的查找算法**:
|
|||
|
|
- 提供了AVX2 SIMD优化版本和普通版本
|
|||
|
|
- 通过预处理器指令自动选择最佳实现
|
|||
|
|
4. **线程安全**:
|
|||
|
|
- 使用QMutex保护共享数据
|
|||
|
|
- 通过QtConcurrent实现多线程处理
|
|||
|
|
5. **详细的信号通知**:
|
|||
|
|
- 分别通知买卖盘的最大订单
|
|||
|
|
- 提供组合通知信号
|
|||
|
|
- 添加了数据有效性检查
|
|||
|
|
6. **可扩展性**:
|
|||
|
|
- 结构设计便于添加新的处理逻辑
|
|||
|
|
- 支持未来添加更多分析功能
|
|||
|
|
|
|||
|
|
这个实现完整处理了您提供的JSON格式订单簿数据,并提供了高性能的多线程处理能力。
|