Files
QTradeProgram/Sqbase/qhistoryorderdialog.cpp

269 lines
7.5 KiB
C++
Raw Normal View History

2025-08-15 15:56:40 +08:00
#pragma execution_character_set("utf-8")
#include "qhistoryorderdialog.h"
#include "qbigordermanager.h"
#include <QHeaderView>
#include <QFileDialog>
#include <QTextStream>
#include <QCoreApplication>
#include <QDebug>
QHistoryOrderDialog::QHistoryOrderDialog(QWidget *parent)
: QDialog(parent),
m_dateSelector(new QDateEdit(this)),
m_orderTypeFilter(new QComboBox(this)),
m_stockCodeFilter(new QLineEdit(this)),
m_tableView(new QTableView(this)),
m_exportButton(new QPushButton("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>", this)),
m_statsLabel(new QLabel(this)),
m_model(new QStandardItemModel(this)),
m_proxyModel(new QSortFilterProxyModel(this)),
m_typeDelegate(new OrderTypeDelegate(this)),
m_numberDelegate(new NumberFormatDelegate(this))
{
setWindowTitle("<EFBFBD><EFBFBD>ʷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѯ");
setMinimumSize(800, 600);
m_historyPath = QCoreApplication::applicationDirPath() + QString("/history");
initUI();
onDateChanged(QDate::currentDate());
}
void QHistoryOrderDialog::initUI()
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
QHBoxLayout *topLayout = new QHBoxLayout();
// <20><><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD>
m_dateSelector->setDate(QDate::currentDate());
m_dateSelector->setCalendarPopup(true);
topLayout->addWidget(new QLabel("ѡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:"));
topLayout->addWidget(m_dateSelector);
// <20><>Ʊ<EFBFBD><C6B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
m_stockCodeFilter->setPlaceholderText("<EFBFBD><EFBFBD>Ʊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
topLayout->addWidget(new QLabel("<EFBFBD><EFBFBD>Ʊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>:"));
topLayout->addWidget(m_stockCodeFilter);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹<EFBFBD><CDB9><EFBFBD>
m_orderTypeFilter->addItem("ȫ<EFBFBD><EFBFBD>", "");
m_orderTypeFilter->addItem("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "BID");
m_orderTypeFilter->addItem("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "ASK");
topLayout->addWidget(new QLabel("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:"));
topLayout->addWidget(m_orderTypeFilter);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ť
topLayout->addStretch();
topLayout->addWidget(m_exportButton);
mainLayout->addLayout(topLayout);
// ͳ<><CDB3><EFBFBD><EFBFBD>Ϣ
QHBoxLayout *statsLayout = new QHBoxLayout();
statsLayout->addWidget(m_statsLabel);
statsLayout->addStretch();
mainLayout->addLayout(statsLayout);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ
m_proxyModel->setSourceModel(m_model);
m_tableView->setItemDelegateForColumn(2, m_typeDelegate);
m_tableView->setItemDelegateForColumn(3, m_numberDelegate);
m_tableView->setModel(m_proxyModel);
m_tableView->setSortingEnabled(true);
m_tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
m_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
// <20><><EFBFBD>ñ<EFBFBD>ͷ
m_model->setHorizontalHeaderLabels(
QStringList()
<< "<EFBFBD><EFBFBD>Ʊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" << "<EFBFBD><EFBFBD>Ʊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" << "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
<< "<EFBFBD><EFBFBD>Ʊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" << "<EFBFBD><EFBFBD>Ʊ<EFBFBD>۸<EFBFBD>" << "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ" << "ʱ<EFBFBD><EFBFBD>"
);
mainLayout->addWidget(m_tableView);
const int timeColumnIndex = 6;
m_proxyModel->sort(timeColumnIndex, Qt::AscendingOrder);
// <20><><EFBFBD><EFBFBD><EFBFBD>ź<EFBFBD>
connect(m_dateSelector, &QDateEdit::dateChanged,
this, &QHistoryOrderDialog::onDateChanged);
connect(m_stockCodeFilter, &QLineEdit::textChanged,
this, &QHistoryOrderDialog::onFilterChanged);
connect(m_orderTypeFilter, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &QHistoryOrderDialog::onFilterChanged);
connect(m_exportButton, &QPushButton::clicked,
this, &QHistoryOrderDialog::onExportClicked);
}
void QHistoryOrderDialog::onDateChanged(const QDate &date)
{
loadOrdersForDate(date);
}
void QHistoryOrderDialog::loadOrdersForDate(const QDate &date)
{
auto orders = getHistoryOrders(date);
m_model->removeRows(0, m_model->rowCount());
for (const auto& order : orders) {
QList<QStandardItem*> rowItems;
rowItems << new QStandardItem(order->code);
rowItems << new QStandardItem(order->name);
rowItems << new QStandardItem(order->nBigOrderType == 0 ? "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" : "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
rowItems << new QStandardItem(QString::number(std::fabs(order->volume / 1000)) + "K");
rowItems << new QStandardItem(QString::number(order->price, 'f', 2));
rowItems << new QStandardItem(QString::number(order->level));
rowItems << new QStandardItem(order->svrRecvTime.mid(12));
m_model->appendRow(rowItems);
}
updateStatistics(orders);
}
void QHistoryOrderDialog::updateStatistics(const QList<QSharedPointer<class BigOrderInfo>>& orders)
{
int buyCount = 0, sellCount = 0;
double totalBuyAmount = 0, totalSellAmount = 0;
for (const auto& order : orders) {
double value = order->price * order->volume;
if (order->nBigOrderType) {
buyCount++;
totalBuyAmount += value;
}
else {
sellCount++;
totalSellAmount += value;
}
}
QString stats = QString("<EFBFBD>ܶ<EFBFBD><EFBFBD><EFBFBD>: %1 <20><> | <20><><EFBFBD><EFBFBD>: %2 <20><> (%3 <20><>) | <20><><EFBFBD><EFBFBD>: %4 <20><> (%5 <20><>)")
.arg(orders.size())
.arg(buyCount)
.arg(totalBuyAmount / 10000, 0, 'f', 1)
.arg(sellCount)
.arg(totalSellAmount / 10000, 0, 'f', 1);
m_statsLabel->setText(stats);
}
void QHistoryOrderDialog::onFilterChanged()
{
QString stockCode = m_stockCodeFilter->text().trimmed();
QString orderType = m_orderTypeFilter->currentData().toString();
// <20><><EFBFBD>ù<EFBFBD>Ʊ<EFBFBD><C6B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
m_proxyModel->setFilterKeyColumn(0);
m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_proxyModel->setFilterFixedString(stockCode);
// <20><><EFBFBD>ö<EFBFBD><C3B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹<EFBFBD><CDB9><EFBFBD>
if (!orderType.isEmpty()) {
m_proxyModel->setFilterKeyColumn(2);
m_proxyModel->setFilterFixedString(orderType == "ASK" ? "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" : "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
}
}
void QHistoryOrderDialog::onExportClicked()
{
QString fileName = QFileDialog::getSaveFileName(this, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "", "CSV<EFBFBD>ļ<EFBFBD> (*.csv)");
if (fileName.isEmpty()) return;
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return;
QTextStream out(&file);
out.setCodec("GBK");
// д<><D0B4><EFBFBD><EFBFBD>ͷ
for (int col = 0; col < m_model->columnCount(); ++col) {
out << m_model->headerData(col, Qt::Horizontal).toString();
if (col < m_model->columnCount() - 1) out << ",";
}
out << "\n";
// д<><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
for (int row = 0; row < m_proxyModel->rowCount(); ++row) {
for (int col = 0; col < m_proxyModel->columnCount(); ++col) {
out << m_proxyModel->index(row, col).data().toString();
if (col < m_proxyModel->columnCount() - 1) out << ",";
}
out << "\n";
}
file.close();
m_statsLabel->setText(QString("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: %1").arg(fileName));
}
QList<QSharedPointer<BigOrderInfo>> QHistoryOrderDialog::getHistoryOrders(const QDate& date) const
{
QMutexLocker locker(&m_cacheMutex);
// <20><><EFBFBD><EFBFBD><E9BBBA>
if (m_historyCache.contains(date)) {
return m_historyCache[date];
}
QString filePath = QString("%1/bigorders_%2.json")
.arg(m_historyPath)
.arg(date.toString("yyyyMMdd"));
if (!QFile::exists(filePath)) {
return QList<QSharedPointer<BigOrderInfo>>();
}
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Failed to open history file:" << filePath;
return QList<QSharedPointer<BigOrderInfo>>();
}
QList<QSharedPointer<BigOrderInfo>> orders;
QTextStream in(&file);
in.setCodec("UTF-8");
while (!in.atEnd()) {
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(in.readLine().toUtf8(), &error);
if (error.error == QJsonParseError::NoError && doc.isObject()) {
BigOrderInfo order = BigOrderInfo::fromJson(doc.object());
orders.append(QSharedPointer<BigOrderInfo>::create(order));
//if (order.isValid()) {
//}
}
}
file.close();
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
m_historyCache.insert(date, orders);
return orders;
}
QList<QDate> QHistoryOrderDialog::getAvailableDates() const
{
QList<QDate> dates;
QDir historyDir(m_historyPath);
QStringList files = historyDir.entryList(QStringList() << "bigorders_*.json", QDir::Files);
for (const QString& file : files) {
QString dateStr = file.mid(10, 8); // bigorders_20230101.json
QDate date = QDate::fromString(dateStr, "yyyyMMdd");
if (date.isValid()) {
dates.append(date);
}
}
std::sort(dates.begin(), dates.end());
return dates;
}