222 lines
6.9 KiB
C++
222 lines
6.9 KiB
C++
#include "QOrderListManager.h"
|
|
#include <QDebug>
|
|
QBasicAtomicPointer<QOrderListManager> QOrderListManager::s_instance = QBasicAtomicPointer<QOrderListManager>(nullptr);
|
|
QMutex QOrderListManager::s_mutex;
|
|
QOrderListManager* QOrderListManager::instance()
|
|
{
|
|
if (!s_instance.loadAcquire()) {
|
|
QMutexLocker locker(&s_mutex);
|
|
if (!s_instance.loadAcquire()) {
|
|
s_instance.storeRelease(new QOrderListManager());
|
|
}
|
|
}
|
|
return s_instance.loadAcquire();
|
|
}
|
|
void QOrderListManager::destroy()
|
|
{
|
|
QMutexLocker locker(&s_mutex);
|
|
delete s_instance.loadAcquire();
|
|
s_instance.storeRelease(nullptr);
|
|
}
|
|
QOrderListManager::QOrderListManager(QObject *parent) : QObject(parent)
|
|
{
|
|
}
|
|
QOrderListManager::~QOrderListManager()
|
|
{
|
|
}
|
|
bool QOrderListManager::addOrder(OrderType type, const OrderBookItem &order)
|
|
{
|
|
if (!order.isValid()) {
|
|
qWarning() << "Invalid order data";
|
|
return false;
|
|
}
|
|
QMutexLocker locker(&m_orderMutex);
|
|
auto& orderMap = (type == BidOrder) ? m_bidOrders : m_askOrders;
|
|
auto& orderList = orderMap[order.price];
|
|
for (const auto& existingOrder : orderList) {
|
|
if (existingOrder->orderId == order.orderId) {
|
|
qWarning() << "Order already exists:" << order.orderId;
|
|
return false;
|
|
}
|
|
}
|
|
auto newOrder = QSharedPointer<OrderBookItem>::create(order);
|
|
orderList.append(newOrder);
|
|
sortOrders(type);
|
|
calculatePriceLevels();
|
|
locker.unlock();
|
|
emit orderAdded(type, order);
|
|
emit orderBookChanged();
|
|
return true;
|
|
}
|
|
bool QOrderListManager::updateOrder(OrderType type, const QString &orderId, const OrderBookItem &newData)
|
|
{
|
|
if (!newData.isValid()) {
|
|
qWarning() << "Invalid order data";
|
|
return false;
|
|
}
|
|
QMutexLocker locker(&m_orderMutex);
|
|
auto& orderMap = (type == BidOrder) ? m_bidOrders : m_askOrders;
|
|
bool found = false;
|
|
for (auto it = orderMap.begin(); it != orderMap.end(); ++it) {
|
|
for (auto& order : it.value()) {
|
|
if (order->orderId == orderId) {
|
|
if (order->price != newData.price) {
|
|
auto orderList = it.value();
|
|
orderList.removeOne(order);
|
|
if (orderList.isEmpty()) {
|
|
orderMap.erase(it);
|
|
}
|
|
auto newOrder = QSharedPointer<OrderBookItem>::create(newData);
|
|
orderMap[newData.price].append(newOrder);
|
|
} else {
|
|
*order = newData;
|
|
}
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (found) break;
|
|
}
|
|
if (!found) {
|
|
qWarning() << "Order not found:" << orderId;
|
|
return false;
|
|
}
|
|
sortOrders(type);
|
|
calculatePriceLevels();
|
|
locker.unlock();
|
|
emit orderUpdated(type, orderId);
|
|
emit orderBookChanged();
|
|
return true;
|
|
}
|
|
bool QOrderListManager::removeOrder(OrderType type, const QString &orderId)
|
|
{
|
|
QMutexLocker locker(&m_orderMutex);
|
|
auto& orderMap = (type == BidOrder) ? m_bidOrders : m_askOrders;
|
|
bool found = false;
|
|
for (auto it = orderMap.begin(); it != orderMap.end(); ++it) {
|
|
for (auto& order : it.value()) {
|
|
if (order->orderId == orderId) {
|
|
auto orderList = it.value();
|
|
orderList.removeOne(order);
|
|
if (orderList.isEmpty()) {
|
|
orderMap.erase(it);
|
|
}
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (found) break;
|
|
}
|
|
if (!found) {
|
|
qWarning() << "Order not found:" << orderId;
|
|
return false;
|
|
}
|
|
calculatePriceLevels();
|
|
locker.unlock();
|
|
emit orderRemoved(type, orderId);
|
|
emit orderBookChanged();
|
|
return true;
|
|
}
|
|
QSharedPointer<OrderBookItem> QOrderListManager::getOrder(OrderType type, const QString &orderId) const
|
|
{
|
|
QMutexLocker locker(&m_orderMutex);
|
|
const auto& orderMap = (type == BidOrder) ? m_bidOrders : m_askOrders;
|
|
for (const auto& orderList : orderMap) {
|
|
for (const auto& order : orderList) {
|
|
if (order->orderId == orderId) {
|
|
return order;
|
|
}
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
QMap<double, QList<QSharedPointer<OrderBookItem>>> QOrderListManager::getBidOrders() const
|
|
{
|
|
QMutexLocker locker(&m_orderMutex);
|
|
return m_bidOrders;
|
|
}
|
|
QMap<double, QList<QSharedPointer<OrderBookItem>>> QOrderListManager::getAskOrders() const
|
|
{
|
|
QMutexLocker locker(&m_orderMutex);
|
|
return m_askOrders;
|
|
}
|
|
QMap<double, double> QOrderListManager::getBidPriceLevels() const
|
|
{
|
|
QMutexLocker locker(&m_orderMutex);
|
|
return m_bidPriceLevels;
|
|
}
|
|
QMap<double, double> QOrderListManager::getAskPriceLevels() const
|
|
{
|
|
QMutexLocker locker(&m_orderMutex);
|
|
return m_askPriceLevels;
|
|
}
|
|
double QOrderListManager::getTotalBidVolume() const
|
|
{
|
|
QMutexLocker locker(&m_orderMutex);
|
|
double total = 0.0;
|
|
for (const auto& volume : m_bidPriceLevels) {
|
|
total += volume;
|
|
}
|
|
return total;
|
|
}
|
|
double QOrderListManager::getTotalAskVolume() const
|
|
{
|
|
QMutexLocker locker(&m_orderMutex);
|
|
double total = 0.0;
|
|
for (const auto& volume : m_askPriceLevels) {
|
|
total += volume;
|
|
}
|
|
return total;
|
|
}
|
|
double QOrderListManager::getBestBidPrice() const
|
|
{
|
|
QMutexLocker locker(&m_orderMutex);
|
|
if (m_bidOrders.isEmpty()) return 0.0;
|
|
return m_bidOrders.lastKey();
|
|
}
|
|
double QOrderListManager::getBestAskPrice() const
|
|
{
|
|
QMutexLocker locker(&m_orderMutex);
|
|
if (m_askOrders.isEmpty()) return 0.0;
|
|
return m_askOrders.firstKey();
|
|
}
|
|
void QOrderListManager::sortOrders(OrderType type)
|
|
{
|
|
auto& orderMap = (type == BidOrder) ? m_bidOrders : m_askOrders;
|
|
if (type == BidOrder) {
|
|
QMap<double, QList<QSharedPointer<OrderBookItem>>> sortedMap;
|
|
auto keys = orderMap.keys();
|
|
std::sort(keys.begin(), keys.end(), std::greater<double>());
|
|
for (const auto& key : keys) {
|
|
sortedMap.insert(key, orderMap.value(key));
|
|
}
|
|
orderMap = sortedMap;
|
|
} else {
|
|
QMap<double, QList<QSharedPointer<OrderBookItem>>> sortedMap;
|
|
auto keys = orderMap.keys();
|
|
std::sort(keys.begin(), keys.end());
|
|
for (const auto& key : keys) {
|
|
sortedMap.insert(key, orderMap.value(key));
|
|
}
|
|
orderMap = sortedMap;
|
|
}
|
|
}
|
|
void QOrderListManager::calculatePriceLevels()
|
|
{
|
|
m_bidPriceLevels.clear();
|
|
for (auto it = m_bidOrders.constBegin(); it != m_bidOrders.constEnd(); ++it) {
|
|
double totalVolume = 0.0;
|
|
for (const auto& order : it.value()) {
|
|
totalVolume += order->volume;
|
|
}
|
|
m_bidPriceLevels.insert(it.key(), totalVolume);
|
|
}
|
|
m_askPriceLevels.clear();
|
|
for (auto it = m_askOrders.constBegin(); it != m_askOrders.constEnd(); ++it) {
|
|
double totalVolume = 0.0;
|
|
for (const auto& order : it.value()) {
|
|
totalVolume += order->volume;
|
|
}
|
|
m_askPriceLevels.insert(it.key(), totalVolume);
|
|
}
|
|
} |