wumu
2025-01-08 6c68684bcdc55572de4084d7b4bc97ed20ffc68c
251008
17个文件已添加
1个文件已修改
1411 ■■■■■ 已修改文件
README.md 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
clientmainwindow.cpp 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
clientmainwindow.h 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
clientmainwindow.ui 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
getstocklist.cpp 635 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
getstocklist.h 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
getstocklist.ui 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
leadingcompany.cpp 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
leadingcompany.h 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
leadingcompany.ui 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main.cpp 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
showinfomessage.cpp 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
showinfomessage.h 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
showinfomessage.ui 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
stock_plan.pro 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
stockpolicy.cpp 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
stockpolicy.h 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
stockpolicy.ui 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md
@@ -1,4 +1,4 @@
## stock_plan
量化
股票相关的爬取、分析、策略等 2023-07-07
clientmainwindow.cpp
New file
@@ -0,0 +1,44 @@
#include "clientmainwindow.h"
#include "ui_clientmainwindow.h"
ClientMainWindow::ClientMainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::ClientMainWindow)
{
    ui->setupUi(this);
    // 启动界面初始化的函数
    initUi();
}
ClientMainWindow::~ClientMainWindow()
{
    delete ui;
}
void ClientMainWindow::initUi()
{
    ui->tabWidget->clear(); // 清除无用的前2个tab页面
    // 实例化获取股票列表的界面对象
    m_getStockList = new GetStockList(this);
    // 将股票界面对象放到主界面的tab选项卡里面来
    ui->tabWidget->addTab(m_getStockList,"获取信息");
    m_stockPolicy = new StockPolicy(this);
    ui->tabWidget->addTab(m_stockPolicy,"股票策略");
    m_leadingCom = new LeadingCompany(this);
    ui->tabWidget->addTab(m_leadingCom,"龙头公司");
    m_showInfoMess = new ShowInfoMessage(this);
    ui->tabWidget->addTab(m_showInfoMess,"信息提示");
    // 关联一下2个界面的信号和槽,用来传递图表所需的数据及展示
    connect(m_getStockList,SIGNAL(sendChartData(QLineSeries*)),m_stockPolicy,SLOT(showNewStockData(QLineSeries*)));
    connect(m_getStockList,SIGNAL(sendChartData(QSplineSeries*)),m_stockPolicy,SLOT(showNewStockData(QSplineSeries*)));
    connect(m_getStockList,SIGNAL(sendInfoMess(QString)),m_showInfoMess,SLOT(showInfo(QString)));
}
clientmainwindow.h
New file
@@ -0,0 +1,34 @@
#ifndef CLIENTMAINWINDOW_H
#define CLIENTMAINWINDOW_H
#include <QMainWindow>
#include "getstocklist.h"
#include "stockpolicy.h"
#include "leadingcompany.h"
#include "showinfomessage.h"
namespace Ui {
class ClientMainWindow;
}
class ClientMainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit ClientMainWindow(QWidget *parent = 0);
    ~ClientMainWindow();
    void initUi();
private:
    Ui::ClientMainWindow *ui;
    GetStockList *m_getStockList;
    StockPolicy *m_stockPolicy;
    LeadingCompany *m_leadingCom; // 龙头公司
    ShowInfoMessage *m_showInfoMess; // 显示信息提示
};
#endif // CLIENTMAINWINDOW_H
clientmainwindow.ui
New file
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>ClientMainWindow</class>
 <widget class="QMainWindow" name="ClientMainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>900</width>
    <height>591</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>ClientMainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <widget class="QTabWidget" name="tabWidget">
      <property name="currentIndex">
       <number>0</number>
      </property>
      <widget class="QWidget" name="tab">
       <attribute name="title">
        <string>Tab 1</string>
       </attribute>
      </widget>
      <widget class="QWidget" name="tab_2">
       <attribute name="title">
        <string>Tab 2</string>
       </attribute>
      </widget>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>900</width>
     <height>26</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>
getstocklist.cpp
New file
@@ -0,0 +1,635 @@
#include "getstocklist.h"
#include "ui_getstocklist.h"
#include <QDebug>
#include <QFile>
#include <QNetworkCookieJar>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QLibrary> // 用于加载dll动态库的类
GetStockList::GetStockList(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::GetStockList)
{
    ui->setupUi(this);
    ui->pushButton_get->hide();
    ui->statusbar->hide();
    // 方案2:
    // 如果https 访问的时候,还是爬取失败,可以代码加载动态库来支持
    // 前提条件是把2个dll动态库拷贝的生成目录中:libeay32.dll 和 ssleay32.dll
    // 拷贝到生成目录,就可以直接加载
    QLibrary lb("libeay32.dll");
    if(lb.load()){
        qDebug()<<"load libeay32.dll 成功";
    }
    QLibrary lb2("ssleay32.dll");
    if(lb2.load()){
        qDebug()<<"load ssleay32.dll 成功";
    }
    // 指定当前日期类型为 week
    m_dateType = "week";
    // 初始化回测数量为100
    m_maTestNum = 100;
    // 模型及表格视图
    m_model = new QStandardItemModel(this);
    m_model->setColumnCount(10); // 设置10列
    QStringList labels;
    labels<<"股票名字"<<"股票代号"<<"总市值(亿)"<<"流通市值(亿)"<<"涨跌幅(%)"<<"收盘价"<<"成交额(亿)"<<"成交量(手)"<<"换手率(%)"<<"市盈率";
    m_model->setHorizontalHeaderLabels(labels); // 设置模型的列标签名
    ui->tableView->setModel(m_model); // 将模型和视图关联
    ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); // 设置内容自适应,拉伸
    // 给表格视图添加右击自定义菜单
    ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu); // 设置上下文菜单策略为自定义菜单
    connect(ui->tableView,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(showMenu()));
    m_menu = new QMenu(this);
    QMenu *dateMenu = new QMenu("设置周期");
    QAction *weekAction = dateMenu->addAction("设置为周");
    QAction *monthAction = dateMenu->addAction("设置为月");
    QAction *yearAction = dateMenu->addAction("设置为年");
    m_menu->addMenu(dateMenu);
    connect(weekAction,&QAction::triggered,this,[&]{ m_dateType = "week";}); // 修改日期类型
    connect(monthAction,&QAction::triggered,this,[&]{ m_dateType = "month";});
    connect(yearAction,&QAction::triggered,this,[&]{ m_dateType = "year";});
    QMenu *testMenu = new QMenu("设置回测股票数量");
    QAction *pre100Action = testMenu->addAction("设置为前100");
    QAction *pre300Action = testMenu->addAction("设置为前300");
    QAction *pre500Action = testMenu->addAction("设置为前500");
    QAction *pre1000Action = testMenu->addAction("设置为前1000");
    QAction *pre5000Action = testMenu->addAction("设置为前5000");
    m_menu->addMenu(testMenu);
    connect(pre100Action,&QAction::triggered,this,[&]{ m_maTestNum = 100;}); // 修改回测数量类型
    connect(pre300Action,&QAction::triggered,this,[&]{ m_maTestNum = 300;});
    connect(pre500Action,&QAction::triggered,this,[&]{ m_maTestNum = 500;});
    connect(pre1000Action,&QAction::triggered,this,[&]{ m_maTestNum = 1000;});
    connect(pre5000Action,&QAction::triggered,this,[&]{ m_maTestNum = 5000;});
    QAction *policy = m_menu->addAction("策略分析");
    QAction *price =  m_menu->addAction("最新价格");
    QAction *maPolicy = m_menu->addAction("MA策略");
    QAction *macdPolicy = m_menu->addAction("MACD策略");
    QAction *maTest100 = m_menu->addAction("MA策略-回测");
    connect(policy,SIGNAL(triggered(bool)),this,SLOT(policySlot())); // 当点击菜单策略分析之后,就会出发槽 policySlot 函数
    connect(price,SIGNAL(triggered(bool)),this,SLOT(priceSlot()));
    connect(maPolicy,SIGNAL(triggered(bool)),this,SLOT(maPolicySlot())); // MA均线策略
    connect(macdPolicy,SIGNAL(triggered(bool)),this,SLOT(macdPolicySlot())); // MA均线策略
    connect(maTest100,SIGNAL(triggered(bool)),this,SLOT(maTest100Slot())); // MA回测前100名
    // 处理数据爬取的操作
    // 模拟浏览器的参数
    QString userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36";
    m_cookie = "__utma=1.731742638.1647403301.1699341909.1700229030.32; device_id=196eef62baf016c7d95a22752d9bdbab; smidV2=20240414233939e95389ecf7ecd2f4d08524ce770aacd500753aa68e9640320; s=c611de27gr; cookiesu=651726298794778; xq_a_token=220b0abef0fac476d076c9f7a3938b7edac35f48; xqat=220b0abef0fac476d076c9f7a3938b7edac35f48; xq_r_token=1d46f0ed628506486164e5055a4993f9b54b2f4c; xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOi0xLCJpc3MiOiJ1YyIsImV4cCI6MTcyOTIxMjc4NCwiY3RtIjoxNzI3NDkwOTU3MjA0LCJjaWQiOiJkOWQwbjRBWnVwIn0.C_GmKEhTaaioDMLWkgZyMXDl4duYEVmsdJHsTi7gbcNz0Tohc-uxHsaw0yBT5k-qmbrJ_RaLMCSxy06v14-R3dwL-MsiKRHxHa5qvQZN4BjEgvPRkqqvPgE_fkPLte8qQOEgd5iVkhr-4mjip0-9WCeXYiH7DygxFOBXGlgoPtpPzAtOTm5TWJmXh0ipDsIZxfNOl8jipXYaIdkv_kqLul5gqiBi5qqnwONDa24Zx-Kvpm8ySWiPFBLzZBqTuRBs4oKAMpSdOiYGLVL7dcSDDZyWqAexmrN4f19hkmd6gBHL4dCczRMDGYc1e98sQtlbZ5lgeEuuM24jjcuwCxsxXQ; u=651726298794778; Hm_lvt_1db88642e346389874251b5a1eded6e3=1727099939,1727251802,1727488707,1727491020; HMACCOUNT=1628106D67895387; acw_tc=2760828017275244258732552e9880f861be6db0c40facbdd5f223490decc2; acw_sc__v2=66f7ee8290dc3f63112948801ef331b8c97ccb35; Hm_lpvt_1db88642e346389874251b5a1eded6e3=1727524485; .thumbcache_f24b8bbe5a5934237bbc0eda20c1b6e7=t00N841S/BEpxTGOoJrbm0blWik12om0ew/whcq/V2DNtyEA8um7J+yzeGOli+6iP/TrvrH0YKH2kHlsmDb5EQ%3D%3D; ssxmod_itna=YqAOBKYve+x0ODfxBcDB4DKM7RtAA4454DkDIEC+GAqGNK3DZDiqAPGhDC8RzeL4Ko7+e2aeQvSeopd5pYDk0Ge5TB0PIjaIDB3DEx06TCCQxiiSDCeDIDWeDiDG4Gm4qGtDpxG=DjDytZ9TtDm4GWGqDmDGYBWqDgDYQDGwIXD7QDIqtW07tQDDNQKpAKDiYeHlL5uMRMtOrK7DtDjdTD/3+kZCbCcPwVFeFO=nPcDB6wxBjZRq00Un+g4mNqLYf4IDAxQuYKtgheYYoAfDhTKhhLSGx4tGY4+GDKSiMS2DDAIvdKeD; ssxmod_itna2=YqAOBKYve+x0ODfxBcDB4DKM7RtAA4454DkDIEC+GDA69mqD/YttDFhxMltFKApT7bCMH+bytp7GQQyCbBWukeAF3+jxeN2wLjbQAFcdwbeNeoohjQ4qtEnLg4TKyX2LqVL=CGaV=GqZZqbDby8DFnFbgWiZEH8zoBzBCbzqWeqwoPq7/TpL=gIRY8sVhEpnWWHQU8sz+S8=+8oRerHq0wtQnSzyQDK7Dmvr3a+VY7fezRmxKF=bDeqexYUbuuzw2eR3In9evW6tzHbQY6vp=AIOUc9l6vc0vOl9plD6D07zGGQ41uxpii2Y5s7KvYQDWGYExD7=DYKKeD==";
    QByteArray cookieByte = m_cookie.toUtf8();
    QList<QNetworkCookie> list;
    list.push_back(QNetworkCookie(cookieByte));
    QVariant var;
    var.setValue(list);
    // 设置要访问的网址
    m_request.setUrl(QUrl("https://xueqiu.com/?md5__1038=QqGxcDnDyiitnD05o4%2Br%3Di%3De0KDtYqCDRWOoD"));
    // 设置请求头,用户代理,用来模拟浏览器
    m_request.setHeader(QNetworkRequest::UserAgentHeader,userAgent);
    // 设置cookie
    //m_request.setHeader(QNetworkRequest::CookieHeader, var);
    // 查看manager都支持哪些协议
    qDebug()<<"支持的协议:"<<m_manager.supportedSchemes();
    // 关联信号槽,当请求管理对象完全打开网页之后,会将数据给槽函数处理
    connect(&m_manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(showAplyData(QNetworkReply*)));
    on_pushButton_get_clicked();
    // 表格列排序
    ui->tableView->setSortingEnabled(false);
    ui->tableView->horizontalHeader()->setSortIndicatorShown(false);
    connect(ui->tableView->horizontalHeader(),&QHeaderView::sortIndicatorChanged,this,[=](int index,Qt::SortOrder order){
        qDebug()<<"sort:"<<index<<order;
        m_model->sort(index,order);
        ui->tableView->horizontalHeader()->setSortIndicatorShown(true);
    });
    // 定时获取股票代号的定时器相关
    m_getCodeTimer = new QTimer(this);
    connect(m_getCodeTimer,SIGNAL(timeout()),this,SLOT(getCodeSlot()));
}
GetStockList::~GetStockList()
{
    delete ui;
}
/*
 * 要处理的大概格式如下
 *
 * {"data":{"count":5000,"list":[{"symbol":"SZ300817","net_profit_cagr":-17.50317062659299,"north_net_inflow":null,
 * "ps":4.4809,"type":11,"percent":20.03,"has_follow":false,"tick_size":0.01,"pb_ttm":3.2607,"float_shares":99366912,
 * "current":18.04,"amplitude":24.02,"pcf":21.3128,"current_year_percent":28.25,"float_market_capital":1.792579092E9,
 * "north_net_inflow_time":null,"market_capital":3.1504802E9,"dividend_yield":1.153,"lot_size":100,"roe_ttm":5.6761589850147,
 * "total_percent":78.15,"percent5m":0.0,"income_cagr":2.235799161377394,"amount":3.5973639118E8,"chg":3.01,
 * "issue_date_ts":1581955200000,"eps":0.32,"main_net_inflows":6078207.0,"volume":21355714,"volume_ratio":4.35,"pb":3.143,
 * "followers":6931,"turnover_rate":21.49,"first_percent":43.98,"name":"双飞股份","pe_ttm":56.123,"total_shares":174638592,
 * "limitup_days":1}]}}
 */
// 获取所有沪深股票的信息
void GetStockList::getStockAllCode(QByteArray &buffer)
{
    // 使用JSON进行数据处理
    QJsonDocument jd = QJsonDocument::fromJson(buffer);
    if(jd.isArray()){
        qDebug()<<"js array";
    }else if(jd.isObject()){
        qDebug()<<"js object";
        QJsonObject jobject = jd.object();
        QStringList jlist = jobject.keys();
        qDebug()<<"jlist:"<<jlist; // 输出一下一级键的情况
        // 通过键值对的方式提取数据
        int count = jobject["data"].toObject()["count"].toInt();
        qDebug()<<"count:"<<count;
        QJsonArray listData = jobject["data"].toObject()["list"].toArray();
        count = listData.size(); // 适应新版的处理
        for(int i=0;i<count;++i){
            QString symbol = listData.at(i).toObject().value("symbol").toString(); // 股票代号
            QString name = listData.at(i).toObject().value("name").toString();  // 股票名字
            double market_capital = listData.at(i).toObject().value("market_capital").toDouble()/100000000; // 总市值 单位 亿
            double float_market_capital = listData.at(i).toObject().value("float_market_capital").toDouble()/100000000; // 流通市值 单位 亿
            double percent = listData.at(i).toObject().value("percent").toDouble(); // 涨跌幅 百分比,大于0上涨,小于0下跌
            double current = listData.at(i).toObject().value("current").toDouble(); // 收盘价
            double amount = listData.at(i).toObject().value("amount").toDouble()/100000000; // 成交额 单位 亿
            double volume = listData.at(i).toObject().value("volume").toInt(); // 成交量 单位 手
            double turnover_rate = listData.at(i).toObject().value("turnover_rate").toDouble(); // 换手率 百分比
            double pe_ttm = listData.at(i).toObject().value("pe_ttm").toDouble(); // PE值 市盈率 百分比
            //qDebug()<<name<<symbol<<market_capital;
            m_codeNames[symbol] = name; // 添加或覆盖键值对,保存股票代号和股票名字到map中
            // 添加模型行的数据:股票名字、股票代号 总市值 流通市值 涨跌幅 收盘价 成交额 成交量 换手率 市盈率
            QList<QStandardItem*> rowItems;
            rowItems.append(new QStandardItem(name));
            rowItems.append(new QStandardItem(symbol));
            rowItems.append(new QStandardItem(QString::number(market_capital,'f',2)));
            rowItems.append(new QStandardItem(QString::number(float_market_capital)));
            QStandardItem *percentItem =  new QStandardItem(QString::number(percent));
            if(percent > 0){
                percentItem->setData(QColor("red"),Qt::DecorationRole); // 添加一个装饰的颜色为红色
                percentItem->setData(QColor("red"),Qt::TextColorRole);  // 将字体颜色设置为红色
                rowItems.at(0)->setData(QColor("red"),Qt::TextColorRole);  // 将股票名字设置为红色
             }
            else if(percent < 0){
                percentItem->setData(QColor("green"),Qt::BackgroundColorRole);
                rowItems.at(0)->setData(QColor("green"),Qt::TextColorRole);
            }
            rowItems.append(percentItem);
            rowItems.append(new QStandardItem(QString::number(current)));
            rowItems.append(new QStandardItem(QString::number(amount)));
            rowItems.append(new QStandardItem(QString::number(volume)));
            rowItems.append(new QStandardItem(QString::number(turnover_rate)));
            if(pe_ttm > 0){
                rowItems.append(new QStandardItem(QString::number(pe_ttm)));
            }
            else{
                rowItems.append(new QStandardItem("亏损"));
            }
            // 添加一行数据项到模型中
            m_model->appendRow(rowItems);
        }
    }
}
/*  要处理的单个股票的格式如下
{"data":{" ":"SH601127","column":["timestamp","volume","open","high","low","close","chg","percent","turnoverrate","amount","volume_post","amount_post"],
"item":[[1680192000000,592214010,37.57,41.56,35.63,37.85,0.2,0.53,50.63,2.3075281252E10,0,0.0],
[1682611200000,355174985,36.6,36.6,28.61,29.52,-8.33,-22.01,27.0,1.1568002446E10,0,0.0],
[1685462400000,345031667,29.51,30.1,25.27,25.78,-3.74,-12.67,23.04,9.442101926E9,0,0.0],
[1688054400000,1217980960,25.6,42.19,24.75,36.77,10.99,42.63,81.24,4.2515733378E10,0,0.0],
[1688572800000,427585117,37.5,47.3,37.06,46.62,9.85,26.79,28.37,1.8368604411E10,0,0.0]]},"error_code":0,"error_description":""}
*/
// 单个股票的 JSON格式处理
void GetStockList::getStockOne(QByteArray &buffer)
{
    QJsonDocument jd = QJsonDocument::fromJson(buffer);
    if(jd.isObject()){
        QJsonObject jObject = jd.object();
        QJsonArray jArr = jObject.value("data").toObject().value("item").toArray(); // 通过键值对取值
        int cnt = jArr.count();
        qDebug()<<"数组size:"<<cnt;
        QString symbol = jObject.value("data").toObject().value("symbol").toString();
        QString code = symbol; // 股票代号
        QLineSeries *series = new QLineSeries;  // QLineSeries 折线的类,QSplineSeries 为圆滑曲线类
        series->setName(symbol);  // 设置折线名字
        //series->setColor(QColor(255,0,0)); // 设置颜色 r,g,b 红绿蓝三原色,随意组合
        QSplineSeries *sp = new QSplineSeries;
        sp->setName(symbol);
        QSplineSeries *spVolume = new QSplineSeries;
        spVolume->setName(symbol.append("--volume"));
        QSplineSeries *spAmount = new QSplineSeries;
        spVolume->setName(symbol.append("--amount"));
        int ma10_20_flag = 0; // 标记MA金叉、死叉的情况 0:初始值,1:金叉,-1:死叉
        long long oldVolume = 0; // MACD: 老的成交量
        int macd_buy = 0; // 买入标志
        double buy_price = 0; // 买入价格
        double rate_all = 0; // 收益百分比
        for(int i=0;i<cnt;++i){
            qint64 timestamp = jArr.at(i).toArray().at(0).toVariant().toLongLong();
            double close = jArr.at(i).toArray().at(5).toVariant().toDouble();
            long long volume = jArr.at(i).toArray().at(1).toVariant().toLongLong()/100;
            long long amount = jArr.at(i).toArray().at(9).toVariant().toLongLong()/100000000;
            QString curDateTime = QDateTime::fromMSecsSinceEpoch(timestamp).toString("yyyy-MM-dd");
            //qDebug()<<curDateTime<<close<<volume<<amount;
            series->append(timestamp,close); // 折线数据添加
            sp->append(timestamp,close);  // 曲线数据添加
            spVolume->append(timestamp,volume);
            spAmount->append(timestamp,amount);
            if(m_menuIndex == 2){
                // MA  ma10交ma20 金叉,ma10交ma60 死叉
                double ma5 = jArr.at(i).toArray().at(12).toVariant().toDouble();
                double ma10 = jArr.at(i).toArray().at(13).toVariant().toDouble();
                double ma20 = jArr.at(i).toArray().at(14).toVariant().toDouble();
                double ma30 = jArr.at(i).toArray().at(15).toVariant().toDouble();
                //qDebug()<<"MA5-10-20-30"<<ma5<<ma10<<ma20<<ma30;
                if(i>0){
                    double ma5_old = jArr.at(i-1).toArray().at(12).toVariant().toDouble();
                    double ma10_old = jArr.at(i-1).toArray().at(13).toVariant().toDouble();
                    double ma20_old = jArr.at(i-1).toArray().at(14).toVariant().toDouble();
                    double ma30_old = jArr.at(i-1).toArray().at(15).toVariant().toDouble();
//                    if(ma5_old > ma20_old && ma5 <= ma20){
//                        // 死叉
//                        qDebug()<<"MA5-20死叉:"<<curDateTime<<" 价格:"<<close;
//                    }else if(ma5_old < ma20_old && ma5 >= ma20){
//                        // 金叉
//                        qDebug()<<"MA5-20金叉:"<<curDateTime<<" 价格:"<<close;
//                    }
                    if(ma10_old > ma20_old && ma10 <= ma20){
                        // 死叉
                        qDebug()<<"MA10-20死叉:"<<curDateTime<<" 价格:"<<close;
                        if(buy_price == 0) buy_price = close;
                        double tmp_rate = (close-buy_price)/buy_price;
                        rate_all += tmp_rate;
                        QString info = QString("<font size=8 color=green> %3 %6 MA10-20死叉:%1 价格:%2   盈利比:%4  总盈利:%5</font>").arg(curDateTime).arg(close).arg(code)
                                .arg(QString::number(tmp_rate*100)).arg(QString::number(rate_all*100)).arg(m_codeNames[code]);
                        emit sendInfoMess(info);
                        //buy_price = close; // 死叉买入的情况
                    }else if(ma10_old < ma20_old && ma10 >= ma20){
                        // 金叉
                        buy_price = close; // 金叉买入的情况
                        qDebug()<<"MA10-20金叉:"<<curDateTime<<" 价格:"<<close;
//                        if(buy_price == 0) buy_price = close;
//                        double tmp_rate = (close-buy_price)/buy_price;
//                        rate_all += tmp_rate;
                        QString info = QString("<font size=8 color=red> %3 %4 MA10-20金叉:%1 价格:%2 </font>").arg(curDateTime).arg(close).arg(code).arg(m_codeNames[code]);
                                //.arg(QString::number(tmp_rate*100)).arg(QString::number(rate_all*100));
                        emit sendInfoMess(info);
                    }
                }
            }else if(m_menuIndex == 3){
                // MACD策略 结合成交量来判断会更好:买入点成交量继续放大则持有,缩小则离场
                double dea = jArr.at(i).toArray().at(12).toVariant().toDouble();
                double dif = jArr.at(i).toArray().at(13).toVariant().toDouble();
                double macd = jArr.at(i).toArray().at(14).toVariant().toDouble();
                if(macd_buy == 1 && oldVolume > volume){
                    QString info = QString("<font size=8 color=green> %4 MACD 成交量初次见顶 离场1:%1 价格:%2 MACD=%3  </font>").arg(curDateTime).arg(close).arg(macd).arg(code);
                    emit sendInfoMess(info);
                    macd_buy = 0;
                    oldVolume = 0;
                }
                if(i > 0){
                    double dea_old = jArr.at(i-1).toArray().at(12).toVariant().toDouble();
                    double dif_old = jArr.at(i-1).toArray().at(13).toVariant().toDouble();
                    double macd_old = jArr.at(i-1).toArray().at(14).toVariant().toDouble();
                    if(dif_old > dea_old && dif <= dea){
                        // 死叉
                        qDebug()<<"MACD死叉:"<<curDateTime<<" 价格:"<<close <<"MACD="<<macd ;
                        QString info=QString("<font size=8 color=green> %4 MACD死叉:%1 价格:%2 MACD=%3  </font>").arg(curDateTime).arg(close).arg(macd).arg(code);
                        emit sendInfoMess(info);
                    }else if(dif_old < dea_old && dif >= dea){
                        // 金叉
                        qDebug()<<"MACD金叉:"<<curDateTime<<" 价格:"<<close <<"MACD="<<macd <<"建议记录当前金叉MACD的值,若后面有低于此值,关注离场提示";
                        QString info=QString("<font size=9 color=red> %4 MACD金叉:%1 价格:%2 MACD=%3 建议记录当前金叉MACD的值,若后面有低于此值,关注离场提示 </font>").arg(curDateTime).arg(close).arg(macd).arg(code);
                        emit sendInfoMess(info);
                        macd_buy = 1;
                        oldVolume = volume;
                    }
                }
            }
        }
        if(m_menuIndex == 0){
            // 策略分析  只能选一种线形数据
            //emit sendChartData(series); // 发送折线数据
            emit sendChartData(sp);   // 发送曲线数据 收盘价
            emit sendChartData(spVolume); // 发送交易量曲线
            emit sendChartData(spAmount); // 交易额曲线
        }else if(m_menuIndex == 1){
            // 最新价格
        }else if(m_menuIndex == 2){
            // MA策略
        }else if(m_menuIndex == 3){
            // MACD策略
        }
    }
}
/* 获取行业信息
 *
 * {"data":{"industries":[{"encode":"S1101","name":"种植业","pinyin":"zzy"},
 * {"encode":"S1102","name":"渔业","pinyin":"yy"},{"encode":"S1103","name":"林业","pinyin":"ly"},
 * {"encode":"S1104","name":"饲料","pinyin":"sl"},{"encode":"S1105","name":"农产品加工","pinyin":"ncpjg"},
 * {"encode":"S1107","name":"养殖业","pinyin":"yzy"},{"encode":"S1108","name":"动物保健","pinyin":"dwbj"},
 * {"encode":"S1109","name":"农业综合","pinyin":"nyzh"},{"encode":"S2202","name":"化学原料","pinyin":"hxyl"},
 * {"encode":"S2203","name":"化学制品","pinyin":"hxzp"},{"encode":"S2204","name":"化学纤维","pinyin":"hxxw"
 * */
void GetStockList::getIndustryInfo(QByteArray &buffer)
{
    QJsonDocument jd = QJsonDocument::fromJson(buffer);
    if(jd.isObject()){
        QJsonObject jObject = jd.object();
        QJsonArray jArr = jObject.value("data").toObject().value("industries").toArray(); // 通过键值对取值
        int cnt = jArr.count();
        for(int i=0;i<cnt;++i){
            QJsonObject tmpObj = jArr[i].toObject();
            QString encode = tmpObj.value("encode").toString();
            QString name = tmpObj.value("name").toString();
            qDebug()<<encode<<name;
            m_industryInfo[encode] = name; // 添加到行业map里面去保存
            // 接着遍历所有行业拥有的对应股票
            m_curIndustry = encode; // 设置当前行业
            QString url = QString("https://stock.xueqiu.com/v5/stock/screener/quote/list.json?page=1&size=100&order=desc&order_by=percent&market=CN&ind_code=%1").arg(encode);
            m_request.setUrl(url);
            m_manager.get(m_request);
        }
    }
}
/*
{"data":{"count":21,"list":[{"symbol":"SZ000995","net_profit_cagr":92.61556393554986,
"north_net_inflow":null,"ps":19.4318,"type":11,"percent":1.86,"has_follow":false,
"tick_size":0.01,"pb_ttm":20.688,"float_shares":177408000,"current":16.95,
"amplitude":8.65,"pcf":534.2042,"current_year_percent":2.73,"float_market_capital":3.0070656E9,
"north_net_inflow_time":null,"market_capital":3.0070656E9,"dividend_yield":null,"lot_size":100,
"roe_ttm":2.8913250918407045,"total_percent":90.46,"percent5m":0.53,"income_cagr":19.383233238212405,
"amount":5.4679898205E8,"chg":0.31,"issue_date_ts":965577600000,"eps":0.02,"main_net_inflows":-9917325.0,
"volume":32611719,"volume_ratio":1.31,"pb":20.688,"followers":46602,"turnover_rate":18.38,"mapping_quote_current":null,
"first_percent":99.74,"name":"皇台酒业","pe_ttm":731.576,"dual_counter_mapping_symbol":null,"total_shares":177408000,"limitup_days":0},
*/
void GetStockList::getStockByIndustry(QByteArray &buffer,QString industryCode)
{
    // 通过行业获取股票信息
    static int sAllCnt = 0;
    QJsonDocument jd = QJsonDocument::fromJson(buffer);
    if(jd.isObject()){
        QJsonObject jObject = jd.object();
        QJsonArray jArr = jObject.value("data").toObject().value("list").toArray(); // 通过键值对取值
        int allCnt = jObject.value("data").toObject().value("count").toInt();
        sAllCnt += allCnt;
        int cnt = jArr.count();
        qDebug()<<"行业:"<<industryCode<<m_industryInfo[industryCode]<<"allCnt:"<<allCnt<<"pageCnt:"<<cnt;
        for(int i=0;i<cnt;++i){
            QString symbol = jArr[i].toObject().value("symbol").toString();
            QString name = jArr[i].toObject().value("name").toString();
            m_codeAndIndustry[symbol].append(m_industryInfo[industryCode]); // 添加行业到对应map
            qDebug()<<"股票:"<<symbol<<name<<industryCode;
        }
    }
    qDebug()<<"行业统计到的股票sAllCnt"<<sAllCnt;
}
void GetStockList::on_pushButton_get_clicked()
{
    qDebug()<<"开始请求";
    m_manager.get(m_request);
    qDebug()<<"请求中...";
}
void GetStockList::showAplyData(QNetworkReply *reply)
{
    qDebug()<<"收到响应";
    // 将响应的数据,一把读取完,放到字节数组里面来处理
    QByteArray buffer = reply->readAll();
    // 将数据写到文件中,方便观察数据内容
    QFile file("data.txt");
    file.open(QIODevice::ReadWrite | QIODevice::Text);
    QTextStream out(&file);
    out << buffer << endl;
    file.close();
    // 下面使用JSON进行数据处理
    if(reply->url() == QUrl("https://xueqiu.com/")){
        qDebug()<<"发现首页url";
        qDebug()<<buffer;
    }else if(reply->url().toString().indexOf("https://stock.xueqiu.com/v5/stock/chart/kline.json") != -1){
        qDebug()<<"查看个股情况:";
        getStockOne(buffer);
    }else if(reply->url().toString().indexOf("https://stock.xueqiu.com/v5/stock/screener/quote/list.json?page=1&size=100&order=desc&order_by=percent&market=CN&ind_code") != -1){
        qDebug()<<"根据行业获取股票信息"<<reply->url();
        QString industryCode = reply->url().toString().split("=").back();
        qDebug()<<"行业信息:"<<industryCode;
        getStockByIndustry(buffer,industryCode);
    }else if(reply->url().toString().indexOf("https://stock.xueqiu.com/v5/stock/screener/quote/list.json") != -1){
        qDebug()<<"获取所有沪深股票 可以干活了";
        getStockAllCode(buffer);
    }else if(reply->url().toString().indexOf("https://stock.xueqiu.com/v5/stock/screener/industries.json") != -1){
        qDebug()<<"获取行业信息";
        getIndustryInfo(buffer);
    }
    reply->deleteLater();
}
void GetStockList::on_pushButton_get_2_clicked()
{
    m_model->setRowCount(0); // 清除当前模型中的内容
    // 最好输出一下所有股票及行业信息
    qDebug()<<"一把能看到的股票数量"<<m_codeAndIndustry.size();
    for(auto it = m_codeAndIndustry.begin();it != m_codeAndIndustry.end();++it){
        qDebug()<<it.key()<<"所属行业数量:"<<it.value().size();
        for(auto e:it.value()){
            qDebug()<<e;
        }
    }
//    // 设置要爬取的核心网址
//    m_request.setUrl(QUrl("https://stock.xueqiu.com/v5/stock/screener/quote/list.json?page=1&size=5000&order=desc&orderby=amount&order_by=amount&market=CN&type=sh_sz"));
//    // 执行get请求,去拿网址对应的数据
//    m_manager.get(m_request);
//    qDebug()<<"req ok";
    // 2024-9-21 修改新版,官方做了数量限制,可以单页100条,但是不能一把取所有了
    //m_request.setHeader(QNetworkRequest::CookieHeader,m_cookie);
    //m_request.setHeader(QNetworkRequest::SetCookieHeader,m_cookie);
    int allCnt = 6000;
    int singlePageCnt = 90; // 单页股票的股票数量
    int pages = allCnt/singlePageCnt;
    qDebug()<<"请求股票代号:"<<QTime::currentTime();
    for(int i=1;i<=pages;++i){
        QString url = QString("https://stock.xueqiu.com/v5/stock/screener/quote/list.json?page=%1&size=%2&order=desc&orderby=amount&order_by=amount&market=CN&type=sh_sz").arg(i).arg(singlePageCnt);
        m_request.setUrl(QUrl(url));
        m_manager.get(m_request);
    }
    qDebug()<<"OK--完成请求股票代号:"<<QTime::currentTime();
    // 使用定时器来定时获取
//    m_getCodeTimer->start(10);
}
void GetStockList::showMenu()
{
    qDebug()<<"右击菜单";
    m_menu->popup(QCursor::pos());  // 在鼠标光标的位置弹出菜单
}
void GetStockList::policySlot()
{
    qDebug()<<"策略查看";
    if(m_model->rowCount() == 0)return; // 防止异常
    int row = ui->tableView->currentIndex().row(); // 取出菜单所在的行号
    QString symbol = m_model->item(row,1)->text(); // 取当前行所在的股票代号
    qint64 begin = QDateTime::currentMSecsSinceEpoch(); // 取当前时间戳
    m_numsCnt = 30; // 这里是设置获取单个股票的数据量
    QString urlStr = QString("https://stock.xueqiu.com/v5/stock/chart/kline.json?symbol=%1&begin=%2&period=week&type=before&count=-%3&indicator=kline").arg(symbol).arg(begin).arg(m_numsCnt);
    qDebug()<<urlStr;
    qDebug()<<"当前股票:"<<symbol<<m_model->item(row,0)->text();
    // 下一步就是根据url请求到的数据,进行分析
    m_menuIndex = 0; // 第一个菜单
    m_request.setUrl(QUrl(urlStr)); // 设置新的网址
    m_manager.get(m_request);  // 打开网址,拿数据
}
void GetStockList::priceSlot()
{
    qDebug()<<"最新价格";
    if(m_model->rowCount() == 0)return;
    int row = ui->tableView->currentIndex().row();
    QString symbol = m_model->item(row,1)->text(); // 取当前行所在的股票代号
    qint64 begin = QDateTime::currentMSecsSinceEpoch(); // 取当前时间戳
    int numsCnt = 20;
    QString urlStr = QString("https://stock.xueqiu.com/v5/stock/chart/kline.json?symbol=%1&begin=%2&period=day&type=before&count=-%3&indicator=kline").arg(symbol).arg(begin).arg(numsCnt);
    qDebug()<<urlStr;
    // 下一步就是根据url请求到的数据,进行分析
    m_menuIndex = 1; // 第二个菜单项
    m_request.setUrl(QUrl(urlStr));
    m_manager.get(m_request);
}
void GetStockList::maPolicySlot()
{
    qDebug()<<"执行MA策略";
    emit sendInfoMess("<font size=12 color=pink>执行MA策略 </font>");
    int curRow = ui->tableView->currentIndex().row();
    QString symbol = m_model->item(curRow,1)->text();
    qint64 begin = QDateTime::currentMSecsSinceEpoch(); // 取当前时间戳
    int numsCnt = 300;
    QString urlStr = QString("https://stock.xueqiu.com/v5/stock/chart/kline.json?symbol=%1&begin=%2&period=%4&type=before&count=-%3&indicator=kline,ma").arg(symbol).arg(begin).arg(numsCnt).arg(m_dateType);
    qDebug()<<urlStr;
    qDebug()<<"当前股票:"<<symbol<<m_model->item(curRow,0)->text();
    // 下一步就是根据url请求到的数据,进行分析
    m_menuIndex = 2; // 第三个菜单项
    m_request.setUrl(QUrl(urlStr));
    m_manager.get(m_request);
}
void GetStockList::maTest100Slot()
{
    for(int i=0;i<m_model->rowCount() && i < m_maTestNum;++i){
        ui->tableView->setCurrentIndex(m_model->index(i,0)); // 设置当前表格索引,主要是为了设置行
        maPolicySlot(); // 调用MA策略去回测
    }
}
void GetStockList::macdPolicySlot()
{
    qDebug()<<"执行MACD策略";
    emit sendInfoMess("<font size=12 color=pink>执行MACD策略 </font>");
    int curRow = ui->tableView->currentIndex().row();
    QString symbol = m_model->item(curRow,1)->text();
    qint64 begin = QDateTime::currentMSecsSinceEpoch(); // 取当前时间戳
    int numsCnt = 300;
    QString urlStr = QString("https://stock.xueqiu.com/v5/stock/chart/kline.json?symbol=%1&begin=%2&period=week&type=before&count=-%3&indicator=kline,macd").arg(symbol).arg(begin).arg(numsCnt);
    qDebug()<<urlStr;
    qDebug()<<"当前股票:"<<symbol<<m_model->item(curRow,0)->text();
    // 下一步就是根据url请求到的数据,进行分析
    m_menuIndex = 3; // 第四个菜单项
    m_request.setUrl(QUrl(urlStr));
    m_manager.get(m_request);
}
void GetStockList::getCodeSlot()
{
    // 2024-9-21 修改新版,官方做了数量限制,可以单页100条,但是不能一把取所有了
    static int allCnt = 6000;
    static int pages = allCnt/100;
    static int i=1;
    QString url = QString("https://stock.xueqiu.com/v5/stock/screener/quote/list.json?page=%1&size=100&order=desc&orderby=amount&order_by=amount&market=CN&type=sh_sz").arg(i);
    m_request.setUrl(QUrl(url));
    m_manager.get(m_request);
    ++i;
    if(i > pages){
        i=1;
        m_getCodeTimer->stop(); // 停掉定时器
    }
}
void GetStockList::on_pushButton_industry_clicked()
{
    // 获取行业信息,能拿到 行业代码和名字,简写等
    QString url = "https://stock.xueqiu.com/v5/stock/screener/industries.json?category=cn";
    m_request.setUrl(QUrl(url));
    m_manager.get(m_request);
}
getstocklist.h
New file
@@ -0,0 +1,85 @@
#ifndef GETSTOCKLIST_H
#define GETSTOCKLIST_H
#include <QMainWindow>
#include <QNetworkAccessManager>
#include <QNetworkCookie>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QStandardItemModel>
#include <QMenu>
#include <QLineSeries>   // 折线类
#include <QSplineSeries> // 曲线类
#include <QTimer>
QT_CHARTS_USE_NAMESPACE  // 命名空间得使用起来,要不然类会拿不到
/*
 * 关于SSL的处理,由于要请求 https的链接,需要将编译器目录下的两个dll动态库拷贝到对应编译器的bin目录下
 * 将libeay32.dll 和 ssleay32.dll 两个文件复制到对应的区域
 * 例如从编译器的opt\bin原始目录:...\Qt5.9.4\Tools\mingw530_32\opt\bin 找个这2个dll
 * 拷贝到编译器的bin目录下: ...\Qt5.9.4\Tools\mingw530_32\bin
 */
namespace Ui {
class GetStockList;
}
class GetStockList : public QMainWindow
{
    Q_OBJECT
public:
    explicit GetStockList(QWidget *parent = 0);
    ~GetStockList();
    void getStockAllCode(QByteArray &buffer); // 获取所有沪深股票的信息
    void getStockOne(QByteArray &buffer); // 获取单只股票的处理
    void getIndustryInfo(QByteArray &buffer); // 获取行业信息
    void getStockByIndustry(QByteArray &buffer,QString industryCode); // 通过行业获取股票
signals:
    void sendChartData(QLineSeries*);  // 折线
    void sendChartData(QSplineSeries*);  // 曲线
    void sendInfoMess(QString); // 发送消息提示
private slots:
    void on_pushButton_get_clicked();
    void showAplyData(QNetworkReply *reply);  // 用来响应请求的回传数据的槽函数
    void on_pushButton_get_2_clicked();  // 获取沪深股市数据的按钮槽函数
    void showMenu();
    void policySlot();
    void priceSlot();
    void maPolicySlot(); // MA策略槽
    void maTest100Slot(); // MA策略回测前100名槽
    void macdPolicySlot(); // MACD策略槽
    void getCodeSlot(); // 获取股票代号的定时器的槽
    void on_pushButton_industry_clicked();
private:
    Ui::GetStockList *ui;
    // 这2个用于爬取数据的
    QNetworkRequest m_request; // 用于管理请求头的
    QString m_cookie; // 缓存
    QNetworkAccessManager m_manager; // 用于管理http请求及响应的
    // 下面这几个用于显式爬到的股票数据
    QStandardItemModel *m_model; // 标准项模型,用来存储数据的,将模型和视图进行了分离
    QMenu *m_menu; // 菜单指针,用来处理右击菜单的
    int m_numsCnt; // 单个股票的数据行数
    int m_menuIndex; // 针对单个股票需要判断是哪个操作,用来记录下标的
    QTimer *m_getCodeTimer; // 获取股票代号的定时器
    QMap<QString,QString> m_codeNames; // 股票代号和名字
    QMap<QString,QString> m_industryInfo; // 行业代码和行业名字
    QMap<QString,QVector<QString>> m_codeAndIndustry; // 股票代号及对应的行业代码
    QString m_curIndustry; // 当前行业
    QString m_dateType; // 日期类型:day week month year
    int m_maTestNum; // ma策略回测数量
};
#endif // GETSTOCKLIST_H
getstocklist.ui
New file
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>GetStockList</class>
 <widget class="QMainWindow" name="GetStockList">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
       <widget class="QPushButton" name="pushButton_get">
        <property name="text">
         <string>获取首页</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QPushButton" name="pushButton_industry">
        <property name="text">
         <string>获取行业对应股票</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QPushButton" name="pushButton_get_2">
        <property name="text">
         <string>获取沪深股市股票代号</string>
        </property>
       </widget>
      </item>
     </layout>
    </item>
    <item row="1" column="0">
     <widget class="QTableView" name="tableView"/>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>26</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>
leadingcompany.cpp
New file
@@ -0,0 +1,46 @@
#include "leadingcompany.h"
#include "ui_leadingcompany.h"
LeadingCompany::LeadingCompany(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::LeadingCompany)
{
    ui->setupUi(this);
    ui->menubar->hide();
    ui->statusbar->hide();
    m_industryLeaderModel = new QStandardItemModel(this);
    m_industryLeaderModel->setColumnCount(6);
    m_trendLeaderModel = new QStandardItemModel(this);
    m_trendLeaderModel->setColumnCount(7);
    ui->tableView_industry->setModel(m_industryLeaderModel);
    ui->tableView_trend->setModel(m_trendLeaderModel);
    QStringList industryLabels;
    industryLabels<<"名字"<<"代号"<<"行业"<<"等级"<<"市值"<<"收盘价";
    m_industryLeaderModel->setHorizontalHeaderLabels(industryLabels);
    QStringList trendLabels;
    trendLabels<<"名字"<<"代号"<<"趋势方向"<<"行业"<<"等级"<<"市值"<<"收盘价";
    m_trendLeaderModel->setHorizontalHeaderLabels(trendLabels);
}
LeadingCompany::~LeadingCompany()
{
    delete ui;
}
void LeadingCompany::on_pushButton_add_clicked()
{
    QString name = ui->lineEdit_stockName->text();
    QString code = ui->lineEdit_stockCode->text();
    QString type = ui->comboBox->currentText();
    // 添加到数据库
    // 添加到文本浏览器来提示消息
    ui->textBrowser->append(QString("%1 %2 %3").arg(type).arg(name).arg(code));
}
leadingcompany.h
New file
@@ -0,0 +1,29 @@
#ifndef LEADINGCOMPANY_H
#define LEADINGCOMPANY_H
#include <QMainWindow>
#include <QStandardItemModel>
namespace Ui {
class LeadingCompany;
}
class LeadingCompany : public QMainWindow
{
    Q_OBJECT
public:
    explicit LeadingCompany(QWidget *parent = 0);
    ~LeadingCompany();
private slots:
    void on_pushButton_add_clicked();
private:
    Ui::LeadingCompany *ui;
    QStandardItemModel *m_industryLeaderModel; // 行业龙头
    QStandardItemModel *m_trendLeaderModel; // 趋势龙头
};
#endif // LEADINGCOMPANY_H
leadingcompany.ui
New file
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>LeadingCompany</class>
 <widget class="QMainWindow" name="LeadingCompany">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>840</width>
    <height>668</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <widget class="QTabWidget" name="tabWidget">
      <property name="currentIndex">
       <number>2</number>
      </property>
      <widget class="QWidget" name="tab">
       <attribute name="title">
        <string>行业龙头</string>
       </attribute>
       <layout class="QGridLayout" name="gridLayout_2">
        <item row="0" column="0">
         <widget class="QTableView" name="tableView_industry"/>
        </item>
       </layout>
      </widget>
      <widget class="QWidget" name="tab_2">
       <attribute name="title">
        <string>趋势龙头</string>
       </attribute>
       <layout class="QGridLayout" name="gridLayout_3">
        <item row="0" column="0">
         <widget class="QTableView" name="tableView_trend"/>
        </item>
       </layout>
      </widget>
      <widget class="QWidget" name="tab_3">
       <attribute name="title">
        <string>添加龙头</string>
       </attribute>
       <layout class="QGridLayout" name="gridLayout_4">
        <item row="0" column="0">
         <layout class="QHBoxLayout" name="horizontalLayout">
          <item>
           <widget class="QLabel" name="label">
            <property name="text">
             <string>龙头类型</string>
            </property>
           </widget>
          </item>
          <item>
           <widget class="QComboBox" name="comboBox">
            <item>
             <property name="text">
              <string>行业龙头</string>
             </property>
            </item>
            <item>
             <property name="text">
              <string>趋势龙头</string>
             </property>
            </item>
           </widget>
          </item>
          <item>
           <widget class="QLineEdit" name="lineEdit_stockName">
            <property name="placeholderText">
             <string>输入股票名字</string>
            </property>
           </widget>
          </item>
          <item>
           <widget class="QLineEdit" name="lineEdit_stockCode">
            <property name="placeholderText">
             <string>输入股票代号</string>
            </property>
           </widget>
          </item>
          <item>
           <widget class="QPushButton" name="pushButton_add">
            <property name="text">
             <string>添加</string>
            </property>
           </widget>
          </item>
         </layout>
        </item>
        <item row="1" column="0">
         <widget class="QTextBrowser" name="textBrowser"/>
        </item>
       </layout>
      </widget>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>840</width>
     <height>26</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>
main.cpp
New file
@@ -0,0 +1,11 @@
#include "clientmainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ClientMainWindow w;
    w.show();
    return a.exec();
}
showinfomessage.cpp
New file
@@ -0,0 +1,19 @@
#include "showinfomessage.h"
#include "ui_showinfomessage.h"
ShowInfoMessage::ShowInfoMessage(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::ShowInfoMessage)
{
    ui->setupUi(this);
}
ShowInfoMessage::~ShowInfoMessage()
{
    delete ui;
}
void ShowInfoMessage::showInfo(QString info)
{
    ui->textBrowser->append(info);
}
showinfomessage.h
New file
@@ -0,0 +1,24 @@
#ifndef SHOWINFOMESSAGE_H
#define SHOWINFOMESSAGE_H
#include <QMainWindow>
namespace Ui {
class ShowInfoMessage;
}
class ShowInfoMessage : public QMainWindow
{
    Q_OBJECT
public:
    explicit ShowInfoMessage(QWidget *parent = 0);
    ~ShowInfoMessage();
public slots:
    void showInfo(QString info);
private:
    Ui::ShowInfoMessage *ui;
};
#endif // SHOWINFOMESSAGE_H
showinfomessage.ui
New file
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>ShowInfoMessage</class>
 <widget class="QMainWindow" name="ShowInfoMessage">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <widget class="QTextBrowser" name="textBrowser"/>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>26</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>
stock_plan.pro
New file
@@ -0,0 +1,46 @@
#-------------------------------------------------
#
# Project created by QtCreator 2023-07-06T21:17:32
#
#-------------------------------------------------
QT       += core gui network charts
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = stock_plan
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
        main.cpp \
        clientmainwindow.cpp \
    getstocklist.cpp \
    stockpolicy.cpp \
    leadingcompany.cpp \
    showinfomessage.cpp
HEADERS += \
        clientmainwindow.h \
    getstocklist.h \
    stockpolicy.h \
    leadingcompany.h \
    showinfomessage.h
FORMS += \
        clientmainwindow.ui \
    getstocklist.ui \
    stockpolicy.ui \
    leadingcompany.ui \
    showinfomessage.ui
stockpolicy.cpp
New file
@@ -0,0 +1,95 @@
#include "stockpolicy.h"
#include "ui_stockpolicy.h"
#include <QDebug>
#include <QLegendMarker>
StockPolicy::StockPolicy(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::StockPolicy)
{
    ui->setupUi(this);
    initUi();
}
StockPolicy::~StockPolicy()
{
    delete ui;
}
void StockPolicy::initUi()
{
    m_chart = new QChart;
    m_chart->setTitle("趋势查看");
    m_chart->setBackgroundBrush(QColor(255,255,255));  // 用于设置背景色的   QColor(10,10,10)  r,g,b 红绿蓝3原色
    QLineSeries *series = new QLineSeries; // 用于存放数据的系列,相当于存了XY对应数据的容器
    series->setName("示例图");
    series->append(1686240000000,17.63); // X Y的值
    series->append(1686844800000,19.31);
    series->append(1687276800000,30.11);
    series->append(1688054400000,19.31);
    series->append(1688659200000,50.81);
    m_chart->addSeries(series);
    m_dtAx = new QDateTimeAxis;  // X轴,时间轴
    m_dtAx->setFormat("yyyy-MM-dd"); // 设置时间格式
    m_dtAx->setTitleText("时间");
    m_dtAx->setTickCount(10); // 设置网格数
    m_chart->setAxisX(m_dtAx,series);  // 设置 X轴为时间轴、数据
    m_axisY = new QValueAxis;  // Y轴
    m_axisY->setTickCount(10); // 设置格数
    m_axisY->setRange(0,1500); // 设置Y值的范围
    m_chart->setAxisY(m_axisY,series);  // 设置 Y轴为数据轴、数据
    setLastMarkerShowAndAlpha(); // 设置当前最后一个标记曲线和标签的显示及透明度情况
    m_chartView = new QChartView(m_chart);
    // 框选放大,右键缩小
    m_chartView->setRubberBand(QChartView::HorizontalRubberBand); // 设置鼠标左击框选放大,右击缩小
    m_chartView->setRenderHint(QPainter::Antialiasing,true);
    this->setCentralWidget(m_chartView); // 将表视图放到中心部件来显示,可以做到自适应大小
}
// 设置当前最后一个标记曲线和标签的显示及透明度情况
void StockPolicy::setLastMarkerShowAndAlpha()
{
    QLegendMarker* marker = m_chart->legend()->markers().back();
    connect(marker,QOverload<>::of(&QLegendMarker::clicked),this,[=]{
        marker->series()->setVisible(!marker->series()->isVisible());  // 取反,可见时不可见,不可见时变可见
        marker->setVisible(true); // 把图例标题显示处理
        qreal alpha = 1.0; // 透明度,完全不透明
        if(!marker->series()->isVisible()) alpha = 0.5; // 不可见时透明度 50%
        // 设置透明度相关,主要是设置图例标签的透明度
        QBrush brush = marker->labelBrush();
        QColor color = brush.color();
        color.setAlphaF(alpha);
        brush.setColor(color);
        marker->setLabelBrush(brush);
    });
}
void StockPolicy::showNewStockData(QLineSeries *series)
{
    m_chart->addSeries(series);  // 添加数据到图表
    m_chart->setAxisX(m_dtAx,series);  // 设置 X轴为时间轴、数据
    m_chart->setAxisY(m_axisY,series);  // 设置 Y轴为数据轴、数据
    setLastMarkerShowAndAlpha(); // 设置当前最后一个标记曲线和标签的显示及透明度情况
}
void StockPolicy::showNewStockData(QSplineSeries *series)
{
    m_chart->addSeries(series);  // 添加数据到图表
    m_chart->setAxisX(m_dtAx,series);  // 设置 X轴为时间轴、数据
    m_chart->setAxisY(m_axisY,series);  // 设置 Y轴为数据轴、数据
    setLastMarkerShowAndAlpha(); // 设置当前最后一个标记曲线和标签的显示及透明度情况
}
stockpolicy.h
New file
@@ -0,0 +1,41 @@
#ifndef STOCKPOLICY_H
#define STOCKPOLICY_H
#include <QMainWindow>
#include <QChartView>
#include <QDateTimeAxis>
#include <QValueAxis>
#include <QChart>
#include <QGraphicsSimpleTextItem>
#include <QLineSeries>  // 折线
#include <QSplineSeries> // 曲线
QT_CHARTS_USE_NAMESPACE  // 命名空间得使用起来,要不然类会拿不到
namespace Ui {
class StockPolicy;
}
class StockPolicy : public QMainWindow
{
    Q_OBJECT
public:
    explicit StockPolicy(QWidget *parent = 0);
    ~StockPolicy();
    void initUi();
    void setLastMarkerShowAndAlpha(); // 设置当前最后一个标记的显示情况及透明度
public slots:
    void showNewStockData(QLineSeries *series); // 用于刷新折线表格数据的
    void showNewStockData(QSplineSeries *series); // 用于刷新曲线表格数据的
private:
    Ui::StockPolicy *ui;
    QChart *m_chart;
    QDateTimeAxis *m_dtAx;
    QValueAxis *m_axisY;
    QChartView *m_chartView;
};
#endif // STOCKPOLICY_H
stockpolicy.ui
New file
@@ -0,0 +1,24 @@
<ui version="4.0">
 <author/>
 <comment/>
 <exportmacro/>
 <class>StockPolicy</class>
 <widget name="StockPolicy" class="QMainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget name="menubar" class="QMenuBar"/>
  <widget name="centralwidget" class="QWidget"/>
  <widget name="statusbar" class="QStatusBar"/>
 </widget>
 <pixmapfunction/>
 <connections/>
</ui>