#pragma once #include #include #include #include #include #include #include #include "tool.h" #include "BZStruct.h" class OrderBookParser { public: OrderBookParser() { m_orderCache.setMaxCost(100); } bool parse(const char* data, int size, OrderBookData& output) { google::protobuf::Arena arena; auto* response = new Qot_UpdateOrderBook::Response; if (!response->ParseFromArray(data, size)) { return false; } if (response->rettype() != 0) { arena.Reset(); return false; } if (!response->has_s2c()) { arena.Reset(); return true; } const auto& s2c = response->s2c(); output.clear(); output.name = QString(s2c.name().c_str()); output.code = QString(s2c.security().code().c_str()); output.askTime = QString(s2c.svrrecvtimeask().c_str()); output.bidTime = QString(s2c.svrrecvtimebid().c_str()); if (s2c.orderbookbidlist_size() > 0) { parseOrderBookList(s2c.orderbookbidlist(), output.bids); } if (s2c.orderbookasklist_size() > 0) { parseOrderBookList(s2c.orderbookasklist(), output.asks); } if (!validateOrderData(*response)) { arena.Reset(); return false; } compressOrderData(output); removeDuplicateOrders(output); arena.Reset(); return true; } bool validateOrderData(const Qot_UpdateOrderBook::Response &stRsp) { if (!stRsp.has_s2c()) { return false; } const auto& s2c = stRsp.s2c(); if (s2c.security().code().empty() || s2c.name().empty()) { return false; } if (s2c.svrrecvtimeask().empty() && s2c.svrrecvtimebid().empty()) { return false; } auto validatePriceVolume = [](const google::protobuf::RepeatedPtrField& list) { for (const auto& item : list) { if (item.price() <= 0 || item.volume() < 0) { return false; } for (const auto& detail : item.detaillist()) { if (detail.orderid() < 0 || detail.volume() < 0) { return false; } } } return true; }; if (!validatePriceVolume(s2c.orderbookbidlist()) || !validatePriceVolume(s2c.orderbookasklist())) { return false; } return true; } void removeDuplicateOrders(OrderBookData& data) { auto removeDuplicates = [](QVector& entries) { QSet seenPrices; QVector uniqueEntries; uniqueEntries.reserve(entries.size()); for (const auto& entry : entries) { QString priceKey = QString::number(entry.price, 'f', 4); if (!seenPrices.contains(priceKey)) { seenPrices.insert(priceKey); uniqueEntries.append(entry); } } entries = std::move(uniqueEntries); }; removeDuplicates(data.bids); removeDuplicates(data.asks); } void compressOrderData(OrderBookData& data) { data.name = data.name.simplified(); data.code = data.code.simplified(); data.askTime = data.askTime.simplified(); data.bidTime = data.bidTime.simplified(); auto compressEntries = [](QVector& entries) { QVector compressed; compressed.reserve(entries.size()); for (auto& entry : entries) { if (entry.isValid() && !entry.details.isEmpty()) { QVector validDetails; validDetails.reserve(entry.details.size()); for (const auto& detail : entry.details) { if (detail.volume > 0 && detail.orderId > 0) { validDetails.append(detail); } } if (!validDetails.isEmpty()) { entry.details = std::move(validDetails); compressed.append(entry); } } } entries = std::move(compressed); }; compressEntries(data.bids); compressEntries(data.asks); } private: QCache m_orderCache; void parseOrderBookList( const google::protobuf::RepeatedPtrField& pbList, QVector& output) { output.clear(); const int itemCount = pbList.size(); if (itemCount == 0) return; output.reserve(itemCount); int maxDetails = 0; for (int i = 0; i < itemCount; ++i) { maxDetails = std::max(maxDetails, pbList.Get(i).detaillist_size()); } for (int i = 0; i < itemCount; ++i) { const auto& pb_item = pbList.Get(i); const int detailCount = pb_item.detaillist_size(); QVector detailsBuffer; detailsBuffer.reserve(detailCount); try { for (int j = 0; j < detailCount; ++j) { const auto& pb_detail = pb_item.detaillist(j); OrderDetail detail; detail.orderId = pb_detail.orderid(); detail.volume = pb_detail.volume(); detailsBuffer.append(detail); } } catch (const std::exception& e) { detailsBuffer.clear(); } OrderBookEntry item; item.price = pb_item.price(); item.volume = pb_item.volume(); item.orderCount = pb_item.oredercount(); item.details = detailCount > 0 ? std::move(detailsBuffer) : QVector{}; output.append(item); } } };