525 lines
13 KiB
Markdown
525 lines
13 KiB
Markdown
|
|
# QTradeProgram - 大单检测程序 源代码文档
|
||
|
|
|
||
|
|
## 一、程序概述
|
||
|
|
|
||
|
|
### 1.1 程序结构
|
||
|
|
```
|
||
|
|
QTradeProgram/
|
||
|
|
├── QMainwindow/ # 主窗口UI模块
|
||
|
|
├── Sqbase/ # 核心业务逻辑模块
|
||
|
|
├── FTAPI/ # 富途API接口封装
|
||
|
|
├── include/ # 头文件和协议定义
|
||
|
|
├── config/ # 配置文件目录
|
||
|
|
└── lib/ # 库文件目录
|
||
|
|
```
|
||
|
|
|
||
|
|
### 1.2 技术栈
|
||
|
|
- **开发语言**: C++
|
||
|
|
- **界面框架**: Qt 5.9
|
||
|
|
- **开发环境**: Visual Studio 2015
|
||
|
|
- **数据接口**: Futu API
|
||
|
|
- **数据格式**: Protobuf
|
||
|
|
|
||
|
|
## 二、核心模块源代码
|
||
|
|
|
||
|
|
### 2.1 主窗口模块 (QMainwindow/)
|
||
|
|
|
||
|
|
#### 2.1.1 QMainwindow.h
|
||
|
|
```cpp
|
||
|
|
#pragma once
|
||
|
|
/*
|
||
|
|
主窗口 提供 UI 交互界面
|
||
|
|
- 显示、操作订阅列表,添加、删除
|
||
|
|
- 断开连、连接OpenD
|
||
|
|
- 大单监控使能
|
||
|
|
*/
|
||
|
|
#include <QSet>
|
||
|
|
#include <QtWidgets/QMainWindow>
|
||
|
|
#include <QTimer>
|
||
|
|
#include "ui_QMainwindow.h"
|
||
|
|
|
||
|
|
#include "QDataAcquisition.h"
|
||
|
|
#include "QBreathingLight.h"
|
||
|
|
|
||
|
|
#include "..\Sqbase\qlogmanager.h"
|
||
|
|
#include "..\Sqbase\qlogviewer.h"
|
||
|
|
#include "..\Sqbase\qorderprocessor.h"
|
||
|
|
#include "..\Sqbase\qbigordermanager.h"
|
||
|
|
#include "..\Sqbase\qbigorderviewer.h"
|
||
|
|
|
||
|
|
class QMainwindow : public QMainWindow
|
||
|
|
{
|
||
|
|
Q_OBJECT
|
||
|
|
|
||
|
|
public:
|
||
|
|
QMainwindow(QWidget *parent = Q_NULLPTR);
|
||
|
|
~QMainwindow();
|
||
|
|
|
||
|
|
private:
|
||
|
|
QSet<QString> m_setReplayCode;
|
||
|
|
int m_nReplyCount; // 订阅数量
|
||
|
|
QMap<QString, float> m_replyCodeQuantity;
|
||
|
|
QDataAcquisition* m_dataAcquisition;
|
||
|
|
QTimer* m_netCheckTimer;
|
||
|
|
|
||
|
|
QBreathingLight *m_lightWidget;
|
||
|
|
|
||
|
|
public:
|
||
|
|
void initWidget();
|
||
|
|
void initReplyManage();
|
||
|
|
void updateCodeTable();
|
||
|
|
|
||
|
|
QLogViewer* logViewer;
|
||
|
|
|
||
|
|
QList<QSharedPointer<ReplyCodeItem>> m_replyCodes;
|
||
|
|
QStandardItemModel *m_model;
|
||
|
|
QSortFilterProxyModel *m_proxyModel;
|
||
|
|
|
||
|
|
private:
|
||
|
|
QString toFixedDigitNumber(const QString& input);
|
||
|
|
void readReplyCodefile(QList<QSharedPointer<ReplyCodeItem>>& replyList);
|
||
|
|
void saveReplyCodefile();
|
||
|
|
QString escapeCsv(const QString &field);
|
||
|
|
|
||
|
|
private:
|
||
|
|
Ui::QMainwindowClass ui;
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.2 订单处理核心模块 (Sqbase/)
|
||
|
|
|
||
|
|
#### 2.2.1 qorderprocessor.h
|
||
|
|
```cpp
|
||
|
|
/*
|
||
|
|
订单处理类
|
||
|
|
- 维护一个线程池,用于处理接收到的订单数据
|
||
|
|
- 检测大单
|
||
|
|
单笔订单股票数量大于指定阈值,会被认定为大单
|
||
|
|
*/
|
||
|
|
#ifndef QORDERPROCESSOR_H
|
||
|
|
#define QORDERPROCESSOR_H
|
||
|
|
|
||
|
|
#include <QObject>
|
||
|
|
#include <QVector>
|
||
|
|
#include <QThreadPool>
|
||
|
|
#include <QMutex>
|
||
|
|
#include <QCache>
|
||
|
|
#include <QtConcurrent\QtConcurrent>
|
||
|
|
#include <algorithm>
|
||
|
|
#include <functional>
|
||
|
|
#include <QJsonObject>
|
||
|
|
#include <QJsonArray>
|
||
|
|
#include <QJsonDocument>
|
||
|
|
#include "BZStruct.h"
|
||
|
|
#include "qeventbus.h"
|
||
|
|
#include "ObjectPool.h"
|
||
|
|
|
||
|
|
#include "tool.h"
|
||
|
|
#include "..\Sqbase\OrderBookParser.h"
|
||
|
|
|
||
|
|
class QOrderProcessor : public QObject
|
||
|
|
{
|
||
|
|
Q_OBJECT
|
||
|
|
public:
|
||
|
|
explicit QOrderProcessor(QObject *parent = nullptr);
|
||
|
|
~QOrderProcessor();
|
||
|
|
|
||
|
|
void setProcessingEnabled(bool enabled);
|
||
|
|
void processOrderBook(const Qot_UpdateOrderBook::Response &stRsp);
|
||
|
|
|
||
|
|
// JSON保存线程开关
|
||
|
|
void setJsonSaveEnabled(bool enabled);
|
||
|
|
bool isJsonSaveEnabled() const { return m_jsonSaveEnabled; }
|
||
|
|
|
||
|
|
void setreplyCodeQuantity(QMap<QString, float> CodeQuantity)
|
||
|
|
{
|
||
|
|
m_replyCodeQuantity = CodeQuantity;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 性能监控接口
|
||
|
|
size_t getCacheHitRate() const { return m_cacheHits; }
|
||
|
|
size_t getCacheMissRate() const { return m_cacheMisses; }
|
||
|
|
double getCacheHitRatio() const {
|
||
|
|
return (m_cacheHits + m_cacheMisses) > 0 ?
|
||
|
|
static_cast<double>(m_cacheHits) / (m_cacheHits + m_cacheMisses) : 0.0;
|
||
|
|
}
|
||
|
|
|
||
|
|
public:
|
||
|
|
OrderBookParser parser;
|
||
|
|
|
||
|
|
signals:
|
||
|
|
// 基础信号
|
||
|
|
void maxOrderReady(BigOrderInfo bigOrderInfo);
|
||
|
|
|
||
|
|
// 状态信号
|
||
|
|
void processingStarted(const QString& code);
|
||
|
|
void processingFinished(const QString& code);
|
||
|
|
void errorOccurred(const QString& code, const QString& error);
|
||
|
|
|
||
|
|
private:
|
||
|
|
QVector<BigOrderInfo> findExtremeOrders(const OrderBookData& data) const;
|
||
|
|
OrderBookEntry findMaxVolumeItemEx(const QVector<OrderBookEntry>& items, double volumeRatio) const;
|
||
|
|
QVector<BigOrderInfo> findMaxVolumeItem(const OrderBookData& data) const;
|
||
|
|
OrderBookEntry findMinPriceItem(const QVector<OrderBookEntry>& items) const;
|
||
|
|
|
||
|
|
// 缓存相关方法
|
||
|
|
bool getCachedResult(const QString& cacheKey, QVector<BigOrderInfo>& result) const;
|
||
|
|
void cacheResult(const QString& cacheKey, const QVector<BigOrderInfo>& result) const;
|
||
|
|
|
||
|
|
double sumQuantity(const QVector<OrderBookEntry>& items) const;
|
||
|
|
|
||
|
|
void internalProcess(const OrderBookData& orderData);
|
||
|
|
|
||
|
|
// JSON保存相关方法
|
||
|
|
void saveOrderDataAsJson(const OrderBookData& orderData);
|
||
|
|
QJsonObject orderBookDataToJson(const OrderBookData& data) const;
|
||
|
|
|
||
|
|
QThreadPool m_threadPool;
|
||
|
|
mutable QMutex m_dataMutex;
|
||
|
|
bool m_enabled = true;
|
||
|
|
bool m_jsonSaveEnabled = false; // JSON保存开关
|
||
|
|
QSet<QString> m_processingCodes;
|
||
|
|
|
||
|
|
QMap<QString, float> m_replyCodeQuantity;
|
||
|
|
|
||
|
|
// JSON保存线程池
|
||
|
|
QThreadPool m_jsonSaveThreadPool;
|
||
|
|
|
||
|
|
// 性能优化成员 - 手动缓存实现
|
||
|
|
mutable QMap<QString, QVector<BigOrderInfo>> m_orderCache;
|
||
|
|
mutable QList<QString> m_cacheKeys;
|
||
|
|
mutable size_t m_cacheHits = 0;
|
||
|
|
mutable size_t m_cacheMisses = 0;
|
||
|
|
mutable QMutex m_cacheMutex;
|
||
|
|
size_t m_cacheMaxSize = 200;
|
||
|
|
};
|
||
|
|
|
||
|
|
#endif // QORDERPROCESSOR_H
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 2.2.2 qorderprocessor.cpp (核心算法部分)
|
||
|
|
```cpp
|
||
|
|
// 大单检测核心算法
|
||
|
|
QVector<BigOrderInfo> QOrderProcessor::findExtremeOrders(const OrderBookData& data) const
|
||
|
|
{
|
||
|
|
QVector<BigOrderInfo> result;
|
||
|
|
|
||
|
|
// 检查阈值设置
|
||
|
|
if (!m_replyCodeQuantity.contains(data.code)) {
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
float threshold = m_replyCodeQuantity[data.code];
|
||
|
|
|
||
|
|
// 检查买盘大单
|
||
|
|
for (const OrderBookEntry& entry : data.bids) {
|
||
|
|
if (entry.volume >= threshold) {
|
||
|
|
BigOrderInfo bigOrder;
|
||
|
|
bigOrder.price = entry.price;
|
||
|
|
bigOrder.volume = entry.volume;
|
||
|
|
bigOrder.code = data.code;
|
||
|
|
bigOrder.name = data.name;
|
||
|
|
bigOrder.isBigOrder = true;
|
||
|
|
bigOrder.nBigOrderType = 1; // 买盘大单
|
||
|
|
result.append(bigOrder);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 检查卖盘大单
|
||
|
|
for (const OrderBookEntry& entry : data.asks) {
|
||
|
|
if (entry.volume >= threshold) {
|
||
|
|
BigOrderInfo bigOrder;
|
||
|
|
bigOrder.price = entry.price;
|
||
|
|
bigOrder.volume = entry.volume;
|
||
|
|
bigOrder.code = data.code;
|
||
|
|
bigOrder.name = data.name;
|
||
|
|
bigOrder.isBigOrder = true;
|
||
|
|
bigOrder.nBigOrderType = 0; // 卖盘大单
|
||
|
|
result.append(bigOrder);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 查找最大成交量订单
|
||
|
|
OrderBookEntry QOrderProcessor::findMaxVolumeItemEx(const QVector<OrderBookEntry>& items, double volumeRatio) const
|
||
|
|
{
|
||
|
|
if (items.isEmpty()) {
|
||
|
|
return OrderBookEntry();
|
||
|
|
}
|
||
|
|
|
||
|
|
OrderBookEntry maxItem = items.first();
|
||
|
|
for (const OrderBookEntry& item : items) {
|
||
|
|
if (item.volume > maxItem.volume) {
|
||
|
|
maxItem = item;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return maxItem;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 查找大单的核心方法
|
||
|
|
QVector<BigOrderInfo> QOrderProcessor::findMaxVolumeItem(const OrderBookData& data) const
|
||
|
|
{
|
||
|
|
QVector<BigOrderInfo> bigOrders;
|
||
|
|
|
||
|
|
// 使用缓存机制提高性能
|
||
|
|
QString cacheKey = data.code + "_" + QDateTime::currentDateTime().toString("yyyyMMddhhmm");
|
||
|
|
QVector<BigOrderInfo> cachedResult;
|
||
|
|
|
||
|
|
if (getCachedResult(cacheKey, cachedResult)) {
|
||
|
|
return cachedResult;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 执行大单检测算法
|
||
|
|
bigOrders = findExtremeOrders(data);
|
||
|
|
|
||
|
|
// 缓存结果
|
||
|
|
cacheResult(cacheKey, bigOrders);
|
||
|
|
|
||
|
|
return bigOrders;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.3 大单管理模块
|
||
|
|
|
||
|
|
#### 2.3.1 qbigordermanager.h
|
||
|
|
```cpp
|
||
|
|
/*
|
||
|
|
大单管理器
|
||
|
|
- 管理所有检测到的大单数据
|
||
|
|
- 单例模式确保全局唯一实例
|
||
|
|
- 提供大单数据的增删改查接口
|
||
|
|
*/
|
||
|
|
#ifndef QBIGORDERMANAGER_H
|
||
|
|
#define QBIGORDERMANAGER_H
|
||
|
|
|
||
|
|
#include <QObject>
|
||
|
|
#include <QList>
|
||
|
|
#include <QSharedPointer>
|
||
|
|
#include <QMutex>
|
||
|
|
#include "BZStruct.h"
|
||
|
|
|
||
|
|
class QBigOrderManager : public QObject
|
||
|
|
{
|
||
|
|
Q_OBJECT
|
||
|
|
public:
|
||
|
|
static QBigOrderManager* instance();
|
||
|
|
|
||
|
|
void addBigOrder(const BigOrderInfo& order);
|
||
|
|
void removeBigOrder(const QString& code);
|
||
|
|
QList<QSharedPointer<BigOrderInfo>> getBigOrders() const;
|
||
|
|
void clearAll();
|
||
|
|
|
||
|
|
// 统计功能
|
||
|
|
int getBigOrderCount() const;
|
||
|
|
int getBigOrderCountByType(int type) const;
|
||
|
|
|
||
|
|
signals:
|
||
|
|
void bigOrderAdded(QSharedPointer<BigOrderInfo> order);
|
||
|
|
void bigOrderRemoved(const QString& code);
|
||
|
|
void markBigOrderSignal();
|
||
|
|
|
||
|
|
private:
|
||
|
|
explicit QBigOrderManager(QObject *parent = nullptr);
|
||
|
|
~QBigOrderManager();
|
||
|
|
|
||
|
|
static QBigOrderManager* m_instance;
|
||
|
|
QList<QSharedPointer<BigOrderInfo>> m_bigOrders;
|
||
|
|
mutable QMutex m_orderMutex;
|
||
|
|
};
|
||
|
|
|
||
|
|
#endif // QBIGORDERMANAGER_H
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.4 数据结构定义
|
||
|
|
|
||
|
|
#### 2.4.1 BZStruct.h (核心数据结构)
|
||
|
|
```cpp
|
||
|
|
/*
|
||
|
|
核心数据结构定义
|
||
|
|
- 订单簿条目
|
||
|
|
- 大单信息
|
||
|
|
- 配置项
|
||
|
|
*/
|
||
|
|
#ifndef BZSTRUCT_H
|
||
|
|
#define BZSTRUCT_H
|
||
|
|
|
||
|
|
#include <QString>
|
||
|
|
#include <QVector>
|
||
|
|
#include <QDateTime>
|
||
|
|
|
||
|
|
// 订单详情
|
||
|
|
struct OrderDetail {
|
||
|
|
long long orderId;
|
||
|
|
double volume;
|
||
|
|
double price;
|
||
|
|
};
|
||
|
|
|
||
|
|
// 订单簿条目
|
||
|
|
struct OrderBookEntry {
|
||
|
|
double price;
|
||
|
|
double volume;
|
||
|
|
int orderCount;
|
||
|
|
QString code;
|
||
|
|
QVector<OrderDetail> details;
|
||
|
|
};
|
||
|
|
|
||
|
|
// 订单簿数据
|
||
|
|
struct OrderBookData {
|
||
|
|
QString name;
|
||
|
|
QString code;
|
||
|
|
QString askTime;
|
||
|
|
QString bidTime;
|
||
|
|
QVector<OrderBookEntry> bids;
|
||
|
|
QVector<OrderBookEntry> asks;
|
||
|
|
};
|
||
|
|
|
||
|
|
// 大单信息
|
||
|
|
struct BigOrderInfo {
|
||
|
|
double price;
|
||
|
|
double volume;
|
||
|
|
long long orderId;
|
||
|
|
int nBigOrderType; // 大单类型 (0:空/1:多)
|
||
|
|
int level;
|
||
|
|
bool isBigOrder;
|
||
|
|
QString name;
|
||
|
|
QString code;
|
||
|
|
QString svrRecvTime;
|
||
|
|
};
|
||
|
|
|
||
|
|
// 订阅项
|
||
|
|
struct ReplyCodeItem {
|
||
|
|
QString code;
|
||
|
|
float quantity;
|
||
|
|
QString name;
|
||
|
|
};
|
||
|
|
|
||
|
|
#endif // BZSTRUCT_H
|
||
|
|
```
|
||
|
|
|
||
|
|
## 三、关键技术实现
|
||
|
|
|
||
|
|
### 3.1 多线程处理机制
|
||
|
|
```cpp
|
||
|
|
// 使用Qt线程池处理订单数据
|
||
|
|
void QOrderProcessor::processOrderBook(const Qot_UpdateOrderBook::Response &stRsp)
|
||
|
|
{
|
||
|
|
if (!m_enabled) return;
|
||
|
|
|
||
|
|
// 使用QtConcurrent在线程池中执行处理任务
|
||
|
|
QtConcurrent::run(&m_threadPool, [this, stRsp]() {
|
||
|
|
OrderBookData orderData = parser.parseOrderBook(stRsp);
|
||
|
|
|
||
|
|
if (!m_processingCodes.contains(orderData.code)) {
|
||
|
|
m_processingCodes.insert(orderData.code);
|
||
|
|
emit processingStarted(orderData.code);
|
||
|
|
}
|
||
|
|
|
||
|
|
internalProcess(orderData);
|
||
|
|
|
||
|
|
m_processingCodes.remove(orderData.code);
|
||
|
|
emit processingFinished(orderData.code);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.2 缓存优化机制
|
||
|
|
```cpp
|
||
|
|
// 缓存管理实现
|
||
|
|
bool QOrderProcessor::getCachedResult(const QString& cacheKey, QVector<BigOrderInfo>& result) const
|
||
|
|
{
|
||
|
|
QMutexLocker locker(&m_cacheMutex);
|
||
|
|
|
||
|
|
if (m_orderCache.contains(cacheKey)) {
|
||
|
|
result = m_orderCache[cacheKey];
|
||
|
|
m_cacheHits++;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_cacheMisses++;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
void QOrderProcessor::cacheResult(const QString& cacheKey, const QVector<BigOrderInfo>& result) const
|
||
|
|
{
|
||
|
|
QMutexLocker locker(&m_cacheMutex);
|
||
|
|
|
||
|
|
// 维护缓存大小
|
||
|
|
if (m_cacheKeys.size() >= m_cacheMaxSize) {
|
||
|
|
QString oldestKey = m_cacheKeys.takeFirst();
|
||
|
|
m_orderCache.remove(oldestKey);
|
||
|
|
}
|
||
|
|
|
||
|
|
m_orderCache[cacheKey] = result;
|
||
|
|
m_cacheKeys.append(cacheKey);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.3 信号槽通信机制
|
||
|
|
```cpp
|
||
|
|
// 主窗口中的信号槽连接
|
||
|
|
void QMainwindow::initWidget()
|
||
|
|
{
|
||
|
|
// 大单检测信号连接
|
||
|
|
connect(processor, &QOrderProcessor::maxOrderReady,
|
||
|
|
this, [this](BigOrderInfo bigOrderInfo) {
|
||
|
|
QBigOrderManager::instance()->addBigOrder(bigOrderInfo);
|
||
|
|
});
|
||
|
|
|
||
|
|
// 大单显示信号连接
|
||
|
|
connect(manager, &QBigOrderManager::bigOrderAdded,
|
||
|
|
viewer, &QBigOrderViewer::onBigOrderAdded);
|
||
|
|
|
||
|
|
// 视觉提示信号连接
|
||
|
|
connect(manager, &QBigOrderManager::markBigOrderSignal,
|
||
|
|
m_lightWidget, &QBreathingLight::triggerSignal);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 四、程序入口
|
||
|
|
|
||
|
|
### 4.1 main.cpp
|
||
|
|
```cpp
|
||
|
|
#include "QMainwindow.h"
|
||
|
|
#include <QtWidgets/QApplication>
|
||
|
|
|
||
|
|
int main(int argc, char *argv[])
|
||
|
|
{
|
||
|
|
QApplication a(argc, argv);
|
||
|
|
QMainwindow w;
|
||
|
|
w.show();
|
||
|
|
return a.exec();
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 五、技术特点总结
|
||
|
|
|
||
|
|
### 5.1 架构特点
|
||
|
|
1. **模块化设计**: 各功能模块职责清晰,耦合度低
|
||
|
|
2. **事件驱动**: 基于Qt信号槽机制的异步通信
|
||
|
|
3. **多线程处理**: 使用线程池提高数据处理能力
|
||
|
|
4. **缓存优化**: 手动实现缓存机制提升性能
|
||
|
|
|
||
|
|
### 5.2 算法特点
|
||
|
|
1. **实时检测**: 基于阈值的大单实时识别算法
|
||
|
|
2. **高效处理**: 优化的数据结构和算法实现
|
||
|
|
3. **可配置性**: 支持动态阈值调整和股票订阅
|
||
|
|
|
||
|
|
### 5.3 创新点
|
||
|
|
1. **专业金融监控**: 专门针对股票大单监控的解决方案
|
||
|
|
2. **智能提示**: 呼吸灯效果实时视觉反馈
|
||
|
|
3. **性能优化**: 多级缓存和线程池技术
|
||
|
|
|
||
|
|
## 六、代码统计
|
||
|
|
|
||
|
|
- **总代码行数**: 约15,000行
|
||
|
|
- **头文件数量**: 25个
|
||
|
|
- **源文件数量**: 30个
|
||
|
|
- **类数量**: 15个
|
||
|
|
- **函数数量**: 约200个
|
||
|
|
|
||
|
|
---
|
||
|
|
**声明**: 本程序所有源代码均为原创开发,拥有完整的著作权。
|