Files
QTradeProgram/Sqbase/qorderprocessor.cpp
2025-09-01 10:02:14 +08:00

282 lines
7.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "qorderprocessor.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QDebug>
#include <immintrin.h>
#include <algorithm>
#include "qlogmanager.h"
QOrderProcessor::QOrderProcessor(QObject *parent)
: QObject(parent)
{
int idealThreads = QThread::idealThreadCount();
//m_threadPool.setMaxThreadCount(qBound(4, idealThreads, 16));
m_threadPool.setMaxThreadCount(qBound(4, 6, 8));
}
QOrderProcessor::~QOrderProcessor()
{
m_threadPool.waitForDone();
}
void QOrderProcessor::setProcessingEnabled(bool enabled)
{
QMutexLocker lock(&m_dataMutex);
m_enabled = enabled;
}
double QOrderProcessor::sumQuantity(const QVector<OrderBookEntry>& items)const {
return std::accumulate(items.begin(), items.end(), 0.0,
[](double sum, const OrderBookEntry& item) {
return sum + item.volume;
});
}
/*
1. 找到列表中的最大值和次大值
2. 最大值是次大值的指定倍数
*/
OrderBookEntry QOrderProcessor::findMaxVolumeItemEx(const QVector<OrderBookEntry>& items, double volumeRatio) const
{
if (items.isEmpty())
return{};
// 特殊情况处理:只有一个元素时无法比较倍数
if (items.size() == 1) {
return volumeRatio <= 1.0 ? items[0] : OrderBookEntry{};
}
// 初始化最大值和次大值
const OrderBookEntry* maxItem = &items[0];
const OrderBookEntry* secondMaxItem = nullptr;
double secondMaxVolume = -1.0;
// 遍历查找最大值和次大值
for (int i = 1; i < items.size(); ++i) {
const OrderBookEntry& item = items[i];
if (item.volume > maxItem->volume) {
// 更新次大值为原最大值
secondMaxItem = maxItem;
secondMaxVolume = maxItem->volume;
// 更新最大值
maxItem = &item;
}
else if (!secondMaxItem || item.volume > secondMaxVolume) {
// 更新次大值
secondMaxItem = &item;
secondMaxVolume = item.volume;
}
}
// 检查是否满足倍数条件
constexpr double EPSILON = 1e-9;
if (secondMaxItem && maxItem->volume + EPSILON >= secondMaxVolume * volumeRatio) {
return *maxItem;
}
return OrderBookEntry{};
}
QVector<BigOrderInfo> QOrderProcessor::findMaxVolumeItem(const OrderBookData & data) const
{
bool findBigOrder = false;
BigOrderInfo bigOrderInfo;
QVector<BigOrderInfo> bigOrderInfoList;
float volume = m_replyCodeQuantity[data.code];
const OrderBookEntry* maxItem;
QVector<OrderBookEntry> items = data.asks;
for (int i = 0; i < items.size(); i++) {
// 不处理刚打开程序时,推送过来的摆盘数据
if (data.askTime == NULL)
continue;
// 同一个价格挡位的订单中股票数量大于,阈值才有可能是大单
if (volume < items[i].volume) {
for (int j = 0; j< items[i].details.size(); j++) // 超过list的最大数量就不会返回数据了
{
try {
if (volume < items[i].details[j].volume)
{
findBigOrder = true;
bigOrderInfo.nBigOrderType = 0;
bigOrderInfo.isBigOrder = findBigOrder;
bigOrderInfo.code = data.code;
bigOrderInfo.name = data.name;
bigOrderInfo.orderId = items[i].details[j].orderId;
bigOrderInfo.price = items[i].price;
bigOrderInfo.volume = items[i].details[j].volume;
bigOrderInfo.level = i + 1;
bigOrderInfo.svrRecvTime = data.askTime;
bigOrderInfoList.append(bigOrderInfo);
}
}
catch (const char* msg) {
qDebug() << "err findMax";
}
}
}
}
items = data.bids;
for (int i = 0; i < items.size(); i++) {
// 不处理刚打开程序时,推送过来的摆盘数据
if (data.bidTime == NULL)
continue;
// 同一个价格挡位的订单中股票数量大于,阈值才有可能是大单
if (volume < items[i].volume) {
for (int j = 0; j< items[i].details.size(); j++)
{
try {
if (volume < items[i].details[j].volume)
{
findBigOrder = true;
bigOrderInfo.nBigOrderType = 1;
bigOrderInfo.isBigOrder = findBigOrder;
bigOrderInfo.code = data.code;
bigOrderInfo.name = data.name;
bigOrderInfo.orderId = items[i].details[j].orderId;
bigOrderInfo.price = items[i].price;
bigOrderInfo.volume = items[i].details[j].volume;
bigOrderInfo.svrRecvTime = data.bidTime;
bigOrderInfoList.append(bigOrderInfo);
}
}
catch (const char* msg) {
qDebug() << "err findMax";
}
}
}
}
return bigOrderInfoList;
}
//
//// 1.简单粗暴,直接通过数量阈值进行筛选,遍历全部价格档位
//// 大单检测接口,返回 QVector<BigOrderInfo>, 暂时找到一个就返回
//QVector<BigOrderInfo> QOrderProcessor::findMaxVolumeItem(const OrderBookData& data) const;
//{
// if (items.isEmpty())
// return{};
// bool findBigOrder = false;
// QVector<BigOrderInfo> bigOrderInfoList;
//
// float volume = m_replyCodeQuantity[data.code];
// const OrderBookEntry* maxItem;
// for (int i = 0; i < items.size(); i++) {
// // 同一个价格挡位的订单中股票数量大于,阈值才有可能是大单
// if (volume < items[i].volume) {
// for (int j = 0; j< items[i].orderCount; j++)
// {
// try {
// if (items[i].details.size() == 0) continue;
// if (volume < items[i].details[j].volume)
// {
// findBigOrder = true;
//
// bigOrderInfo.isBigOrder = findBigOrder;
// bigOrderInfo.code = data.code;
// bigOrderInfo.name = data.name;
// bigOrderInfo.orderId = items[i].details[j].orderId;
// bigOrderInfo.price = items[i].price;
// bigOrderInfo.volume = items[i].details[j].volume;
// bigOrderInfo.svrRecvTime = data.askTime;
//
// return bigOrderInfo;
// }
// }
// catch (const char* msg) {
// qDebug() << "err findMax";
// }
// }
// }
// }
// 大单检测,分为两步:
// 1、判断股票数量是否达到大单的阈值未达到时直接返回
// 2、判断订单详情是否达到大单阈值
// 下一步增加摆盘数据统计,大单占全部摆盘数量的比例,计算出来一个置信度
// 使用指针遍历避免拷贝
// 这里是找到当前摆盘数据中,每一档价位数量最大的
//const OrderBookEntry* maxItem = &items[0];
//for (int i = 1; i < items.size(); ++i) {
// if (items[i].volume > maxItem->volume) {
// maxItem = &items[i];
// }
//}
// 添加业务规则验证(如果需要)
// if (!isValidMaxVolumeItem(*maxItem, items))
// return {};
// return bigOrderInfoList;
//}
OrderBookEntry QOrderProcessor::findMinPriceItem(const QVector<OrderBookEntry>& items) const
{
if (items.isEmpty()) return{};
auto it = std::min_element(items.begin(), items.end(),
[](const OrderBookEntry& a, const OrderBookEntry& b) {
return a.price < b.price;
});
return it != items.end() ? *it : OrderBookEntry{};
}
QVector<BigOrderInfo> QOrderProcessor::findExtremeOrders(const OrderBookData& data) const
{
return findMaxVolumeItem(data);
}
/*
// 设计一个单独的大单检测引擎
// 包括:历史数据分析、订单分析、成交记录分析
*/
void QOrderProcessor::internalProcess(const OrderBookData& orderData)
{
if (!m_enabled || orderData.isEmpty()) {
return;
}
try {
const auto result = findExtremeOrders(orderData);
for (int i = 0; i < result.size(); i++)
{
if(result.at(i).isBigOrder)
emit maxOrderReady(result.at(i));
}
}
catch (const std::exception& e) {
emit errorOccurred(orderData.code, QString::fromUtf8(e.what()));
}
}
void QOrderProcessor::processOrderBook(const Qot_UpdateOrderBook::Response &stRsp)
{
QtConcurrent::run(&m_threadPool, [this, stRsp]() {
try {
OrderBookData orderBook;
parser.parse(stRsp.SerializeAsString().c_str(), stRsp.ByteSize(), orderBook);
internalProcess(orderBook);
}
catch (const std::exception& e) {
emit errorOccurred("UNKNOWN", QString::fromUtf8(e.what()));
}
});
}