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>
|
2025-08-22 10:59:38 +08:00
|
|
|
|
#include <QDateTime>
|
2025-08-15 15:56:40 +08:00
|
|
|
|
#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))
|
2025-08-31 23:07:06 +08:00
|
|
|
|
|
2025-08-15 15:56:40 +08:00
|
|
|
|
{
|
|
|
|
|
|
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));
|
2025-08-22 10:59:38 +08:00
|
|
|
|
QString str = order->svrRecvTime.mid(11);
|
|
|
|
|
|
if (str == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
QDateTime dateTime = QDateTime::currentDateTime();
|
|
|
|
|
|
str = dateTime.toString("hh:mm:ss");
|
|
|
|
|
|
}
|
|
|
|
|
|
rowItems << new QStandardItem(str);
|
2025-08-15 15:56:40 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|