上证A股数据分析

13 篇文章 0 订阅

上证A股数据分析,通达信上证A股过滤未开板次新股、过滤科创板、过滤ST股票,得到1400支股票,导出所有数据,Excel整理代码、名称导入数据库。通过网易财经下载每日交易数据,参考 如何下载股票历史数据 - 知乎 https://zhuanlan.zhihu.com/p/65662875 。

首页

查询全部

查询个股

个股K线

行情分析

个股走势

条件筛选

涨跌停筛选

形态筛选

stock.py

#!/usr/bin/python3 
# coding: utf-8

from urllib import request
from urllib import error
from urllib.parse import quote
import os
import sys
import string
import time
import schedule
import pymysql
from DBUtils.PooledDB import PooledDB
import csv
import fcntl 

import socket
socket.setdefaulttimeout(20.0)


stock_lst = []

mysql_pool = PooledDB(pymysql, 1, host="127.0.0.1", user="", password="", database="stock", port=3306)

error_stock_code_lst = []
#error_stock_code_lst = ["603959", "603956", "603955", "603920", "603909", "603906", "603895"]

def get_stock_code():
    sql = "select stock_code, stock_name from t_stock_code_name;"
    try:
        mysql_conn = mysql_pool.connection()
        mysql_conn.ping(reconnect=True)
        with mysql_conn.cursor() as cursor:
            cursor.execute(sql)
            data_all = cursor.fetchall()
            global stock_lst 
            stock_lst = []
            for data in data_all:
                stock_lst.append("%s|%s" %(data[0], data[1]))
    except Exception as e:
        print("ERROR: %s\n" %(e))
    finally:
        mysql_conn.close()


def check_status(status):
    date = time.strftime("%Y-%m-%d", time.localtime())
    log_file_dir = "/home/pi/stock/%s%s-logs/" %(date.split("-")[0], date.split("-")[1])
    if not os.path.isdir(log_file_dir):
        os.makedirs(log_file_dir)
    log_file_name = "%slogs_%s.txt" %(log_file_dir, date.split("-")[2])
    date_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
    print("[%s] %s\n" %(date_time, status))
    with open(log_file_name, "a", encoding="utf-8") as f:
        fcntl.flock(f, fcntl.LOCK_EX)
        f.write("[%s] %s\n" %(date_time, status))
        f.write("\n\n")
        fcntl.flock(f, fcntl.LOCK_UN)


def insert_stock():
    error_lst = []
    total_g = 0
    for csv_file in os.listdir("."):
        if ".csv" in csv_file:
            code = csv_file.replace(".csv", "")
            if error_stock_code_lst:
                if code not in error_stock_code_lst:
                    continue 

            sql = "create table if not exists `t_%s` like `t_stock_template`;" %(code)
            try:
                mysql_conn = mysql_pool.connection()
                mysql_conn.ping(reconnect=True)
                with mysql_conn.cursor() as cursor:
                    cursor.execute(sql)
                mysql_conn.commit()
                print("create table `t_%s` OK" %(code))
            except Exception as e:
                mysql_conn.rollback()
                print("create table `t_%s` ERROR: %s" %(code, e))
                if code not in error_lst:
                    error_lst.append(code)
                continue 
            finally:
                mysql_conn.close()

            with open(csv_file, encoding="gbk") as f:
                reader = csv.reader(f)
                next(reader)
                total = 0
                code_g = ""
                name_g = ""
                for row in reader:
                    if not row:
                        continue 

                    total += 1
                    date = row[0]
                    code = row[1].replace("'", "")
                    name = row[2]
                    code_g = code 
                    name_g = name 
                    tclose = row[3]
                    high = row[4]
                    low = row[5]
                    topen = row[6]
                    lclose = row[7]
                    chg = row[8] if (row[8] != "None") else "0.0"
                    pchg = row[9] if (row[9] != "None") else "0.0"
                    turnover = row[10] if (row[10] != "None") else "0.0"
                    voturnover = row[11]
                    vaturnover = row[12]

                    sql = "insert ignore into `t_%s` values('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s');" %(code, code, date, topen, high, low, tclose, lclose, chg, pchg, voturnover, vaturnover, turnover)
                    try:
                        mysql_conn = mysql_pool.connection()
                        mysql_conn.ping(reconnect=True)
                        with mysql_conn.cursor() as cursor:
                            cursor.execute(sql)
                        mysql_conn.commit()
                        sys.stdout.write("insert %s %s %s\r" %(code, name, date))
                        sys.stdout.flush()
                    except Exception as e:
                        mysql_conn.rollback()
                        print("insert %s %s %s ERROR: %s" %(code, name, date, e))
                        if code not in error_lst:
                            error_lst.append(code)
                        break
                    finally:
                        mysql_conn.close()

                print("insert %s %s OK, %d rows" %(code_g, name_g, total))
                total_g += total

    if not error_lst:
        if error_stock_code_lst:
            check_status("No Error\n%s/%s" %(total_g, len(error_stock_code_lst)))
        else:
            check_status("No Error\n%s/%s" %(total_g, len(stock_lst)))
    else:
        if error_stock_code_lst:
            check_status("Error\n%s/%s\n%s" %(total_g, len(error_stock_code_lst), ", ".join(error_lst)))
        else:
            check_status("Error\n%s/%s\n[\"%s\"]" %(total_g, len(stock_lst), "\", \"".join(error_lst)))


def get_stock(start_date, end_date):
    get_stock_code()

    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36', 'Host': 'quotes.money.163.com', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': 1, 'DNT': 1, 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3', 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'}
    api_str = "http://quotes.money.163.com/service/chddata.html?code=0%s&start=%s&end=%s&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE;CHG;PCHG;TURNOVER;VOTURNOVER;VATURNOVER"
    total = len(stock_lst)
    i = 0
    error_lst = []
    for stock in stock_lst:
        i += 1
        code = stock.split("|")[0]
        name = stock.split("|")[1]

        if error_stock_code_lst:
            if code not in error_stock_code_lst:
                continue

        if os.path.exists("%s.csv" %(code)):
            os.remove("%s.csv" %(code))
            print("remove %s.csv" %(code))

        date_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        print("%s %s [%d/%d] %s" %(code, name, i, total, date_time))
        req = request.Request(url=quote(api_str %(code, start_date, end_date), safe=string.printable), headers=headers)
        try:
            with request.urlopen(req) as f:
                with open("%s.csv" %(code), "wb") as f2:
                    while True:
                        buff = f.read(1024 * 100)
                        if not buff:
                            break 
    
                        f2.write(buff)
        except Exception as e:
            print("ERROR: %s\n" %(e))
            if code not in error_lst:
                error_lst.append(code)
 
        time.sleep(1)

    if not error_lst:
        check_status("No Error: %s - %s" %(start_date, end_date))
    else:
        check_status("Error: %s - %s\n[\"%s\"]" %(start_date, end_date, "\", \"".join(error_lst)))

    insert_stock()


def get_stock_today():
    date_time = time.strftime("%Y%m%d", time.localtime())
    holiday_lst = ["20200625", "20200626"]
    if date_time not in holiday_lst:
        get_stock(date_time, date_time)


if __name__ == "__main__":
    background = True 
    #background = False 
    if background:
        time_str = "18:00"
        schedule.every().monday.at(time_str).do(get_stock_today)
        schedule.every().tuesday.at(time_str).do(get_stock_today)
        schedule.every().wednesday.at(time_str).do(get_stock_today)
        schedule.every().thursday.at(time_str).do(get_stock_today)
        schedule.every().friday.at(time_str).do(get_stock_today)

        print("Schedule Jobs: ")
        for job in schedule.jobs:
            print("%s()" %(str(job).split("()")[0]))

        while True:
            schedule.run_pending()
            time.sleep(1)
    else:
        #get_stock("20200709", "20200710")
        #insert_stock()
        get_stock_today()
 

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QTimer>
#include <QTableWidgetItem>
#include <QPainter>
#include <QProgressDialog>
#include <QScrollArea>
#include <QBarSet>
#include <QBarCategoryAxis>
#include <QValueAxis>
#include <QMenu>
#include <QtPrintSupport/QPrinter>
#include <QFileDialog>
#include <QTextDocument>
#include <QClipboard>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QFont font;
    font.setPixelSize(16);
    setFont(font);

    mTitle = QStringLiteral("上证A股数据分析");
    setWindowTitle(mTitle);

    mCategoriesPChgUp.append(QStringLiteral("涨停↑"));
    mCategoriesPChgUp.append(QStringLiteral("> 7%↑"));
    mCategoriesPChgUp.append(QStringLiteral("5-7%↑"));
    mCategoriesPChgUp.append(QStringLiteral("3-5%↑"));
    mCategoriesPChgUp.append(QStringLiteral("0-3%↑"));
    mCategoriesPChgUp.append(QStringLiteral("平盘"));

    mCategoriesPChgDown.append(QStringLiteral("0-3%↓"));
    mCategoriesPChgDown.append(QStringLiteral("3-5%↓"));
    mCategoriesPChgDown.append(QStringLiteral("5-7%↓"));
    mCategoriesPChgDown.append(QStringLiteral("> 7%↓"));
    mCategoriesPChgDown.append(QStringLiteral("跌停↓"));

    mCategoriesTurnover.append(QStringLiteral("0-3%"));
    mCategoriesTurnover.append(QStringLiteral("3-5%"));
    mCategoriesTurnover.append(QStringLiteral("5-10%"));
    mCategoriesTurnover.append(QStringLiteral("10-20%"));
    mCategoriesTurnover.append(QStringLiteral("20-30%"));
    mCategoriesTurnover.append(QStringLiteral("30-50%"));
    mCategoriesTurnover.append(QStringLiteral("> 50%"));

    mCategoriesTClose.append(QStringLiteral("0-10"));
    mCategoriesTClose.append(QStringLiteral("10-20"));
    mCategoriesTClose.append(QStringLiteral("20-50"));
    mCategoriesTClose.append(QStringLiteral("50-100"));
    mCategoriesTClose.append(QStringLiteral("100-200"));
    mCategoriesTClose.append(QStringLiteral("200-300"));
    mCategoriesTClose.append(QStringLiteral("300-500"));
    mCategoriesTClose.append(QStringLiteral("500-1000"));
    mCategoriesTClose.append(QStringLiteral("> 1000"));

    ui->dateEdit_start->setCalendarPopup(true);
    ui->dateEdit_end->setCalendarPopup(true);
    ui->dateEdit_start->setDate(QDate::currentDate());
    ui->dateEdit_end->setDate(QDate::currentDate());
    ui->dateEdit_start->setMinimumDate(QDate(2000, 1, 1));
    ui->dateEdit_end->setMinimumDate(QDate(2000, 1, 1));
    ui->dateEdit_start->setMaximumDate(QDate::currentDate());
    ui->dateEdit_end->setMaximumDate(QDate::currentDate());

    initTableWidget(ui->tableWidget);
    initTableWidget(ui->tableWidget_screening);

    ui->tableWidget_screening->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(ui->tableWidget_screening, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(screenMenuDisplayed(QPoint)));

    ui->kline_widget->installEventFilter(this);

    initAnalyseWidget();
    initTendencyChart();

    QTimer::singleShot(0, this, SLOT(initComboBox()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

bool MainWindow::informationMessageBox(const QString &title, const QString &text, bool isOnlyOk)
{
    QMessageBox msgBox(this);
    msgBox.setFont(this->font());
    msgBox.setIcon(QMessageBox::Information);
    msgBox.setWindowTitle(title);
    msgBox.setText(text);
    if (isOnlyOk)
    {
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setButtonText(QMessageBox::Ok, QStringLiteral("确定"));
    }
    else
    {
        msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
        msgBox.setButtonText(QMessageBox::Ok, QStringLiteral("确定"));
        msgBox.setButtonText(QMessageBox::Cancel, QStringLiteral("取消"));
    }

    return (msgBox.exec() == QMessageBox::Ok);
}

void MainWindow::getStockCodeName()
{
    if (!mStockCodeName.isEmpty())
    {
        return;
    }

    QString retStr = mDBHelper.getConnectDB();
    if (!retStr.isEmpty())
    {
        informationMessageBox(QStringLiteral("提示"), QStringLiteral("数据库连接失败:\n%1").arg(retStr));
        return;
    }

    QStringList columnLst;
    columnLst << "stock_code" << "stock_name";

    QString str = QStringLiteral("select columns from t_stock_code_name;");

    QList<QStringList> retLst = mDBHelper.getSqlSelect(str, columnLst);
    foreach (QStringList ret, retLst)
    {
        mStockCodeName.append(QStringLiteral("%1-%2").arg(ret[0]).arg(ret[1]));
    }
}

void MainWindow::stockDataTable(QTableWidget *tableWidget, QList<StockData> stockDataLst)
{
    int rowCount = tableWidget->rowCount();
    for (int i = rowCount; i > 0; --i)
    {
        tableWidget->removeRow(0);
    }

    foreach (StockData data, stockDataLst)
    {
        int rowCount = tableWidget->rowCount();
        tableWidget->insertRow(rowCount);

        QTableWidgetItem *itemCode = new QTableWidgetItem(QStringLiteral("%1")
                                                          .arg(data.Code));
        QTableWidgetItem *itemName = new QTableWidgetItem(QStringLiteral("%1")
                                                          .arg(data.Name));
        QTableWidgetItem *itemTopen = new QTableWidgetItem(QString::asprintf("%.2f", data.TOpen));
        QTableWidgetItem *itemHigh = new QTableWidgetItem(QString::asprintf("%.2f", data.High));
        QTableWidgetItem *itemLow = new QTableWidgetItem(QString::asprintf("%.2f", data.Low));
        QTableWidgetItem *itemTclose = new QTableWidgetItem(QString::asprintf("%.2f", data.TClose));
        QTableWidgetItem *itemLclose = new QTableWidgetItem(QString::asprintf("%.2f", data.LClose));
        QTableWidgetItem *itemChg = new QTableWidgetItem(QString::asprintf("%.2f", data.Chg));
        QTableWidgetItem *itemPchg = new QTableWidgetItem(QString::asprintf("%.2f", data.PChg));
        QTableWidgetItem *itemVoturnover = new QTableWidgetItem(QString::asprintf("%d", data.Voturnover));
        QTableWidgetItem *itemVaturnover = new QTableWidgetItem(QString::asprintf("%.0f", data.Vaturnover));
        QTableWidgetItem *itemTurnover = new QTableWidgetItem(QString::asprintf("%.2f", data.Turnover));
        QTableWidgetItem *itemDate = new QTableWidgetItem(QStringLiteral("%1")
                                                          .arg(data.Date));

        tableWidget->setItem(rowCount, 0, itemCode);
        tableWidget->setItem(rowCount, 1, itemName);
        tableWidget->setItem(rowCount, 2, itemDate);
        tableWidget->setItem(rowCount, 3, itemTopen);
        tableWidget->setItem(rowCount, 4, itemHigh);
        tableWidget->setItem(rowCount, 5, itemLow);
        tableWidget->setItem(rowCount, 6, itemTclose);
        tableWidget->setItem(rowCount, 7, itemLclose);
        tableWidget->setItem(rowCount, 8, itemChg);
        tableWidget->setItem(rowCount, 9, itemPchg);
        tableWidget->setItem(rowCount, 10, itemVoturnover);
        tableWidget->setItem(rowCount, 11, itemVaturnover);
        tableWidget->setItem(rowCount, 12, itemTurnover);

        for (int i = 0; i < tableWidget->columnCount(); ++i)
        {
            tableWidget->item(rowCount, i)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);

            double chg = data.Chg;
            if (chg < 0)
            {
                tableWidget->item(rowCount, i)->setTextColor(QColor("green"));
            }
            else if (chg > 0)
            {
                tableWidget->item(rowCount, i)->setTextColor(QColor("red"));
            }
        }
    }
}

bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == ui->kline_widget && event->type() == QEvent::Paint)
    {
        drawKLine();
        return true;
    }

    return QMainWindow::eventFilter(watched, event);
}

void MainWindow::drawKLine()
{
    if (ui->comboBox_code_name->currentText() == QStringLiteral("全部"))
    {
        return;
    }

    QPainter painter(ui->kline_widget);

    QPen pen;
    QBrush brush;
    brush.setStyle(Qt::SolidPattern);

    int size = mStockDataLst.size();
    double max = 0;
    double min = 0;
    for (int i = size - 1; i >= 0; --i)
    {
        StockData data = mStockDataLst.at(i);
        double high = data.High;
        double low = data.Low;

        if (i == size - 1)
        {
            max = high;
            min = low;
        }
        else
        {
            if (high > max)
            {
                max = high;
            }

            if (low < min)
            {
                min = low;
            }
        }
    }

    int width = this->rect().width() - 55;
    int height = (this->rect().height() - 75) / 2;

    pen.setColor(QColor("red"));
    painter.setPen(pen);
    painter.drawRect(0, 0, width, height);
    painter.drawRect(0, height, width, height);

    int klineSize = size;
    if ((size % 10) != 0)
    {
        klineSize = (int)(size / 10) * 10 + 10;
    }

    double rateSpace = 0.2;
    double klineWidthTotal = doubleEven(QString::asprintf("%.1f", (double)width / klineSize).toDouble());
    double klineWidth = doubleEven(QString::asprintf("%.1f", klineWidthTotal * (1 - (rateSpace / (1 + rateSpace)))).toDouble());

    int klineWidthMax = 50;
    klineWidth = klineWidth > klineWidthMax ? klineWidthMax : klineWidth;

    double klineHeight = 0;
    double topBottomMargin = 10;

    double offsetX = doubleEven(QString::asprintf("%.1f", klineWidth / 2 + topBottomMargin).toDouble());
    double offsetX2 = doubleEven(QString::asprintf("%.1f", klineWidth * (1 + rateSpace)).toDouble());

    double offsetY = doubleEven(QString::asprintf("%.1f", (double)(height - topBottomMargin * 2) / (max - min)).toDouble());

    double interval = doubleEven(QString::asprintf("%.1f", (double)(height - topBottomMargin * 2) / 5).toDouble());
    for (int i = 0; i <= 5; ++i)
    {
        pen.setColor(QColor("red"));
        pen.setStyle(Qt::DotLine);
        painter.setPen(pen);
        painter.drawLine(0, topBottomMargin + (interval * i), width, topBottomMargin + (interval * i));
    }

    pen.setStyle(Qt::SolidLine);

    QString codeName;

    bool isHigh = false;
    bool isLow = false;

    QString startDate;
    QString endDate;

    for (int i = size - 1; i >= 0; --i)
    {
        StockData data = mStockDataLst.at(i);

        if (i == size - 1)
        {
            startDate = data.Date;
        }

        if (i == 0)
        {
            endDate = data.Date;
        }

        if (codeName.isEmpty())
        {
            codeName = QStringLiteral("%1 %2").arg(data.Code).arg(data.Name);
        }

        double topen = data.TOpen;
        double high = data.High;
        double low = data.Low;
        double tclose = data.TClose;

        if (topen > tclose)
        {
            klineHeight = topen - tclose;

            pen.setColor(QColor("green"));
            brush.setColor(QColor("green"));
            painter.setPen(pen);
            painter.setBrush(brush);

            painter.drawLine(
                        offsetX,
                        doubleEven(QString::asprintf("%.1f", (max - high) * offsetY + topBottomMargin).toDouble()),
                        offsetX,
                        doubleEven(QString::asprintf("%.1f", (max - low) * offsetY + topBottomMargin).toDouble()));

            painter.drawRect(
                        doubleEven(QString::asprintf("%.1f", offsetX - (klineWidth / 2.0)).toDouble()),
                        doubleEven(QString::asprintf("%.1f", (max - topen) * offsetY + topBottomMargin).toDouble()),
                        klineWidth,
                        doubleEven(QString::asprintf("%.1f", klineHeight * offsetY).toDouble()));
        }
        else if (topen < tclose)
        {
            klineHeight = tclose - topen;

            pen.setColor(QColor("red"));
            brush.setColor(QColor("white"));
            painter.setPen(pen);
            painter.setBrush(brush);

            painter.drawLine(
                        offsetX,
                        doubleEven(QString::asprintf("%.1f", (max - high) * offsetY + topBottomMargin).toDouble()),
                        offsetX,
                        doubleEven(QString::asprintf("%.1f", (max - low) * offsetY + topBottomMargin).toDouble()));

            painter.drawRect(
                        doubleEven(QString::asprintf("%.1f", offsetX - (klineWidth / 2.0)).toDouble()),
                        doubleEven(QString::asprintf("%.1f", (max - tclose) * offsetY + topBottomMargin).toDouble()),
                        klineWidth,
                        doubleEven(QString::asprintf("%.1f", klineHeight * offsetY).toDouble()));
        }
        else if (topen == tclose)
        {
            klineHeight = tclose - topen;

            pen.setColor(QColor("black"));
            brush.setColor(QColor("black"));
            painter.setPen(pen);
            painter.setBrush(brush);

            painter.drawLine(
                        offsetX,
                        doubleEven(QString::asprintf("%.1f", (max - high) * offsetY + topBottomMargin).toDouble()),
                        offsetX,
                        doubleEven(QString::asprintf("%.1f", (max - low) * offsetY + topBottomMargin).toDouble()));

            painter.drawRect(
                        doubleEven(QString::asprintf("%.1f", offsetX - (klineWidth / 2.0)).toDouble()),
                        doubleEven(QString::asprintf("%.1f", (max - tclose) * offsetY + topBottomMargin).toDouble()),
                        klineWidth,
                        doubleEven(QString::asprintf("%.1f", klineHeight * offsetY).toDouble()));
        }

        if ((high == max) && !isHigh)
        {
            pen.setColor(QColor("black"));
            painter.setPen(pen);
            painter.drawText(offsetX, painter.fontMetrics().height() * 1.5, QStringLiteral("↖%1").arg(QString::asprintf("%.2f", max)));
            isHigh = true;
        }

        if ((low == min) && !isLow)
        {
            pen.setColor(QColor("black"));
            painter.setPen(pen);
            painter.drawText(offsetX, height, QStringLiteral("←%1").arg(QString::asprintf("%.2f", min)));
            isLow = true;
        }

        offsetX += offsetX2;
    }

    double priceAvg = QString::asprintf("%.02f", (max - min) / 5).toDouble();
    for (int i = 0; i <= 5; ++i)
    {
        QString str;
        if (i == 0)
        {
            str = QStringLiteral("%1").arg(QString::asprintf("%.02f", max));
        }
        else
        {
            str = QStringLiteral("%1").arg(QString::asprintf("%.02f", min + priceAvg * (5 - i)));
        }

        pen.setColor(QColor("black"));
        painter.setPen(pen);
        painter.drawText(width - 10 - painter.fontMetrics().width(str), topBottomMargin + (interval * i) + painter.fontMetrics().height() / 2, str);
    }

    int maxVoturnover = 0;
    int minVoturnover = 0;
    for (int i = size - 1; i >= 0; --i)
    {
        StockData data = mStockDataLst.at(i);
        int voturnover = data.Voturnover;

        if (i == size - 1)
        {
            maxVoturnover = voturnover;
            minVoturnover = voturnover;
        }
        else
        {
            if (voturnover > maxVoturnover)
            {
                maxVoturnover = voturnover;
            }

            if (voturnover < minVoturnover)
            {
                minVoturnover = voturnover;
            }
        }
    }

    int tmp = maxVoturnover;
    int maxBit = 0;
    while (tmp >= 10)
    {
        tmp /= 10;
        maxBit += 1;
    }

    int multiple = 0;
    int maxVoturnover2 = 0;

    if (maxBit < 3)
    {
        maxBit = 3;
    }

    switch (maxBit - 3)
    {
    case 0:
        multiple = 0;
        maxVoturnover2 = (maxVoturnover / 100 + 1) * 100;
        break;
    case 1:
        multiple = 10;
        maxVoturnover2 = (maxVoturnover / 1000 + 1) * 1000;
        break;
    case 2:
        multiple = 100;
        maxVoturnover2 = (maxVoturnover / 10000 + 1) * 10000;
        break;
    default:
        multiple = 1000;
        maxVoturnover2 = (maxVoturnover / 100000 + 1) * 100000;
        break;
    }

    offsetX = doubleEven(QString::asprintf("%.1f", klineWidth / 2 + topBottomMargin).toDouble());

    int tickCount = 10;
    int tickVoturnover = maxVoturnover2 / tickCount;
    double offsetYVoturnover = doubleEven(QString::asprintf("%.1f", (double)(height - topBottomMargin) / tickCount).toDouble());

    for (int i = 1; i <= tickCount; ++i)
    {
        pen.setColor(QColor("red"));
        pen.setStyle(Qt::DotLine);
        painter.setPen(pen);
        painter.drawLine(0, height * 2 - (offsetYVoturnover * i), width, height * 2 - (offsetYVoturnover * i));
    }

    pen.setStyle(Qt::SolidLine);

    for (int i = size - 1; i >= 0; --i)
    {
        StockData data = mStockDataLst.at(i);

        double topen = data.TOpen;
        double tclose = data.TClose;
        int voturnover = data.Voturnover;

        if (topen > tclose)
        {
            pen.setColor(QColor("green"));
            brush.setColor(QColor("green"));
            painter.setPen(pen);
            painter.setBrush(brush);
        }
        else if (topen <= tclose)
        {
            pen.setColor(QColor("red"));
            brush.setColor(QColor("white"));
            painter.setPen(pen);
            painter.setBrush(brush);
        }

        painter.drawRect(
                    doubleEven(QString::asprintf("%.1f", offsetX - (klineWidth / 2.0)).toDouble()),
                    doubleEven(QString::asprintf("%.1f", height * 2 - (double)voturnover / tickVoturnover * offsetYVoturnover).toDouble()),
                    klineWidth,
                    doubleEven(QString::asprintf("%.1f", (double)voturnover / tickVoturnover * offsetYVoturnover).toDouble()));

        offsetX += offsetX2;
    }

    pen.setColor(QColor("black"));
    painter.setPen(pen);

    for (int i = 1; i <= tickCount; ++i)
    {
        QString str;

        if (multiple != 0)
        {
            str = QStringLiteral("%1").arg(tickVoturnover * i / multiple);
        }
        else
        {
            str = QStringLiteral("%1").arg(tickVoturnover * i);
        }

        painter.drawText(width - 10 - painter.fontMetrics().width(str), height * 2 - (offsetYVoturnover * i) + painter.fontMetrics().height() / 2, str);
    }

    if (multiple != 0)
    {
        QString str = QStringLiteral("X%1").arg(multiple);
        painter.drawText(width - painter.fontMetrics().width(str), height * 2, str);
    }

    QFont font;
    font.setPixelSize(20);
    painter.setFont(font);
    QString str = QStringLiteral("%1 %2 %3").arg(codeName).arg(startDate).arg(endDate);
    painter.drawText((width - painter.fontMetrics().width(str)) / 2, 30, str);
}

void MainWindow::getAllStockByDate(QString date)
{
    switch (QDate::fromString(date, "yyyy-MM-dd").dayOfWeek())
    {
    case Qt::Saturday:
    case Qt::Sunday:
        return;
    }

    if (mAllStockMap.contains(date))
    {
        return;
    }

    QString retStr = mDBHelper.getConnectDB();
    if (!retStr.isEmpty())
    {
        informationMessageBox(QStringLiteral("提示"), QStringLiteral("数据库连接失败:\n%1").arg(retStr));
        return;
    }

    QProgressDialog progress(this);
    progress.setFont(this->font());
    progress.setWindowTitle(mTitle);
    progress.setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint) & (~Qt::WindowMinMaxButtonsHint) & (~Qt::WindowCloseButtonHint));
    progress.setLabelText(QStringLiteral("正在查询"));
    progress.setRange(0, mStockCodeName.size());
    progress.setModal(true);
    progress.setCancelButtonText(QStringLiteral("取消"));
    progress.setMinimumDuration(0);
    connect(&progress, SIGNAL(canceled()), this, SLOT(progressCanceled()));
    int count = 1;

    QList<StockData> stockDataLst;

    foreach (QString codeName, mStockCodeName)
    {
        qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

        QString code = codeName.split("-")[0];
        QString name = codeName.split("-")[1];

        QStringList columnLst;
        columnLst << "topen" << "high" << "low" << "tclose" << "lclose" << "chg" << "pchg" << "voturnover" << "vaturnover" << "turnover" << "date_day";

        QString str = QStringLiteral("select columns from t_%1 where date_day = '%2' limit 1;").arg(code).arg(date);

        QList<QStringList> retLst = mDBHelper.getSqlSelect(str, columnLst);
        stockDataLst.append(sqlRetToStockData(code, name, retLst));

        progress.setValue(count++);
    }

    mAllStockMap.insert(date, stockDataLst);
}

void MainWindow::getStockByDate(QString code, QString name, QString dateDay)
{
    QString retStr = mDBHelper.getConnectDB();
    if (!retStr.isEmpty())
    {
        informationMessageBox(QStringLiteral("提示"), QStringLiteral("数据库连接失败:\n%1").arg(retStr));
        return;
    }

    mStockDataLst.clear();

    QStringList columnLst;
    columnLst << "topen" << "high" << "low" << "tclose" << "lclose" << "chg" << "pchg" << "voturnover" << "vaturnover" << "turnover" << "date_day";

    QString str = QStringLiteral("select columns from t_%1 where date_day in (%2) order by date_day desc;").arg(code).arg(dateDay);

    QList<QStringList> retLst = mDBHelper.getSqlSelect(str, columnLst);
    mStockDataLst = sqlRetToStockData(code, name, retLst);
}

QList<StockData> MainWindow::sqlRetToStockData(QString code, QString name, QList<QStringList> retLst)
{
    QList<StockData> stockDataLst;

    foreach (QStringList ret, retLst)
    {
        StockData data;
        data.Code = code;
        data.Name = name;
        data.TOpen = QString::asprintf("%.2f", ret[0].toDouble()).toDouble();
        data.High = QString::asprintf("%.2f", ret[1].toDouble()).toDouble();
        data.Low = QString::asprintf("%.2f", ret[2].toDouble()).toDouble();
        data.TClose = QString::asprintf("%.2f", ret[3].toDouble()).toDouble();
        data.LClose = QString::asprintf("%.2f", ret[4].toDouble()).toDouble();
        data.Chg = QString::asprintf("%.2f", ret[5].toDouble()).toDouble();
        data.PChg = QString::asprintf("%.2f", ret[6].toDouble()).toDouble();
        data.Voturnover = QString::asprintf("%d", ret[7].toInt() / 100).toInt();
        data.Vaturnover = QString::asprintf("%.0f", ret[8].toDouble() / 10000).toDouble();
        data.Turnover = QString::asprintf("%.2f", ret[9].toDouble()).toDouble();

        QString date = ret[10];
        QString week;
        switch (QDate::fromString(date, "yyyy-MM-dd").dayOfWeek())
        {
        case Qt::Monday:
            week = QStringLiteral("一");
            break;
        case Qt::Tuesday:
            week = QStringLiteral("二");
            break;
        case Qt::Wednesday:
            week = QStringLiteral("三");
            break;
        case Qt::Thursday:
            week = QStringLiteral("四");
            break;
        case Qt::Friday:
            week = QStringLiteral("五");
            break;
        }

        data.Date = QStringLiteral("%1/%2").arg(date.replace("-", "/")).arg(week);

        if (data.Voturnover != 0)
        {
            stockDataLst.append(data);
        }
    }

    return stockDataLst;
}

double MainWindow::doubleEven(double num)
{
    double tmp = num - (int)num;
    if (doubleEqual(tmp, 0.1) || doubleEqual(tmp, 0.3) || doubleEqual(tmp, 0.5) || doubleEqual(tmp, 0.7) || doubleEqual(tmp, 0.9))
    {
        num -= 0.1;
    }

    return num;
}

void MainWindow::initAnalyseWidget()
{
    ui->scrollArea_analyse->setBackgroundRole(QPalette::Light);
    ui->scrollArea_analyse->setFrameShape(QFrame::NoFrame);
    ui->scrollArea_analyse->setWidgetResizable(true);

    QWidget *widget = new QWidget(ui->scrollArea_analyse);
    QVBoxLayout *layout = new QVBoxLayout(widget);

    mLimitUpDownLabel = new QLabel(ui->scrollArea_analyse);
    layout->addWidget(mLimitUpDownLabel);

    mChartPChgLeft = new QChart;
    mChartViewPChgLeft = new QChartView(mChartPChgLeft);
    mSeriesPChgLeft = new QBarSeries(mChartViewPChgLeft);

    mChartPChgRight = new QChart;
    mChartViewPChgRight = new QChartView(mChartPChgRight);
    mSeriesPChgRight = new QBarSeries(mChartViewPChgRight);

    initChart(mChartPChgLeft, mChartViewPChgLeft, mSeriesPChgLeft);
    initChart(mChartPChgRight, mChartViewPChgRight, mSeriesPChgRight);

    QHBoxLayout *pchgLayout = new QHBoxLayout;
    pchgLayout->addWidget(mChartViewPChgLeft);
    pchgLayout->addWidget(mChartViewPChgRight);

    layout->addLayout(pchgLayout);

    mVaturnoverLabel = new QLabel(ui->scrollArea_analyse);
    layout->addWidget(mVaturnoverLabel);

    mChartVaturnover = new QChart;
    mChartViewVaturnover = new QChartView(mChartVaturnover);
    mSeriesVaturnover = new QBarSeries(mChartViewVaturnover);

    initChart(mChartVaturnover, mChartViewVaturnover, mSeriesVaturnover);

    layout->addWidget(mChartViewVaturnover);

    mTurnoverLabel = new QLabel(ui->scrollArea_analyse);
    layout->addWidget(mTurnoverLabel);

    mChartTurnover = new QChart;
    mChartViewTurnover = new QChartView(mChartTurnover);
    mSeriesTurnover = new QBarSeries(mChartViewTurnover);

    initChart(mChartTurnover, mChartViewTurnover, mSeriesTurnover);

    layout->addWidget(mChartViewTurnover);

    mTCloseLabel = new QLabel(ui->scrollArea_analyse);
    layout->addWidget(mTCloseLabel);

    mChartTClose = new QChart;
    mChartViewTClose = new QChartView(mChartTClose);
    mSeriesTClose = new QBarSeries(mChartViewTClose);

    initChart(mChartTClose, mChartViewTClose, mSeriesTClose);

    layout->addWidget(mChartViewTClose);

    mVoturnoverLabel = new QLabel(ui->scrollArea_analyse);
    layout->addWidget(mVoturnoverLabel);

    mChartVoturnover = new QChart;
    mChartViewVoturnover = new QChartView(mChartVoturnover);
    mSeriesVoturnover = new QBarSeries(mChartViewVoturnover);

    initChart(mChartVoturnover, mChartViewVoturnover, mSeriesVoturnover);

    layout->addWidget(mChartViewVoturnover);

    mChgLabel = new QLabel(ui->scrollArea_analyse);
    layout->addWidget(mChgLabel);

    mChartChg = new QChart;
    mChartViewChg = new QChartView(mChartChg);
    mSeriesChg = new QBarSeries(mChartViewChg);

    initChart(mChartChg, mChartViewChg, mSeriesChg);

    mChartChgPie = new QChart;
    mChartViewChgPie = new QChartView(mChartChgPie);
    mSeriesChgPie = new QPieSeries(mChartViewChgPie);

    mChartChgPie->setTitleFont(this->font());
    mChartChgPie->legend()->setFont(this->font());
    mChartChgPie->setAnimationOptions(QChart::SeriesAnimations);
    mChartChgPie->setMargins(QMargins(0, 0, 0, 0));

    mChartViewChgPie->setRenderHint(QPainter::Antialiasing);
    mChartViewChgPie->setBackgroundRole(QPalette::Light);

    layout->addWidget(mChartViewChgPie);
    layout->addWidget(mChartViewChg);

    layout->addStretch();

    widget->setLayout(layout);
    ui->scrollArea_analyse->setWidget(widget);
}

void MainWindow::initChart(QChart *chart, QChartView *chartView, QBarSeries *series)
{
    chart->setTitleFont(this->font());
    chart->setAnimationOptions(QChart::SeriesAnimations);
    chart->legend()->hide();
    chart->setMargins(QMargins(0, 0, 0, 0));

    chartView->setRenderHint(QPainter::Antialiasing);
    chartView->setBackgroundRole(QPalette::Light);

    series->setLabelsPosition(QAbstractBarSeries::LabelsCenter);
    series->setLabelsVisible(true);
}

void MainWindow::setChart(QList<int> dataLst, QStringList categories, QBarSet *set, QChart *chart, QBarSeries *series, QColor color)
{
    set->setLabelColor(Qt::black);
    set->setLabelFont(this->font());
    set->setColor(color);

    for (int i = 0; i < dataLst.size(); ++i)
    {
        set->append(dataLst.at(i));
    }

    series->clear();
    series->append(set);

    if (!chart->series().isEmpty())
    {
        chart->removeSeries(series);
    }
    chart->addSeries(series);
    chart->createDefaultAxes();

    QBarCategoryAxis *axisX = new QBarCategoryAxis;
    axisX->append(categories);
    axisX->setGridLineVisible(false);
    axisX->setLabelsFont(this->font());
    chart->setAxisX(axisX, series);

    chart->axisY()->setVisible(false);
}

void MainWindow::initTableWidget(QTableWidget *tableWidget)
{
    QStringList headers;
    headers << QStringLiteral("代码") << QStringLiteral("名称") << QStringLiteral("日期") << QStringLiteral("开盘") << QStringLiteral("最高") << QStringLiteral("最低") << QStringLiteral("收盘") << QStringLiteral("前收盘") << QStringLiteral("涨跌额") << QStringLiteral("涨跌幅(%)") << QStringLiteral("成交量(手)") << QStringLiteral("成交额(万)") << QStringLiteral("换手率(%)");

    tableWidget->setColumnCount(headers.size());
    tableWidget->setHorizontalHeaderLabels(headers);

    for (int i = 0; i < headers.size(); ++i)
    {
        tableWidget->horizontalHeaderItem(i)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    }

    connect(tableWidget, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(getStockTendency(QModelIndex)));

    tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
    tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
    tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
    //tableWidget->verticalHeader()->setVisible(false);
    tableWidget->horizontalHeader()->setHighlightSections(false);
    tableWidget->setFrameShape(QFrame::NoFrame);
    tableWidget->setShowGrid(false);
    tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    tableWidget->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
    tableWidget->setItemDelegate(new NoFocusDelegate());
}

QList<StockData> MainWindow::sortStockDataLst(QList<StockData> stockDataLst, QString key, QString order)
{
    QList<StockData> retLst;

    if (key == "PChg")
    {
        if (order == "desc")
        {
            for (int i = 0; i < stockDataLst.size(); ++i)
            {
                StockData data = stockDataLst.at(i);
                double pchg = data.PChg;

                if (i == 0)
                {
                    retLst.append(data);
                }
                else
                {
                    bool ok = true;
                    for (int j = 0; j < retLst.size(); ++j)
                    {
                        StockData data2 = retLst.at(j);
                        double pchg2 = data2.PChg;

                        if (pchg > pchg2)
                        {
                            retLst.insert(j, data);
                            ok = false;
                            break;
                        }
                    }

                    if (ok)
                    {
                        retLst.append(data);
                    }
                }
            }
        }
        else if (order == "asc")
        {
            for (int i = 0; i < stockDataLst.size(); ++i)
            {
                StockData data = stockDataLst.at(i);
                double pchg = data.PChg;

                if (i == 0)
                {
                    retLst.append(data);
                }
                else
                {
                    bool ok = true;
                    for (int j = 0; j < retLst.size(); ++j)
                    {
                        StockData data2 = retLst.at(j);
                        double pchg2 = data2.PChg;

                        if (pchg < pchg2)
                        {
                            retLst.insert(j, data);
                            ok = false;
                            break;
                        }
                    }

                    if (ok)
                    {
                        retLst.append(data);
                    }
                }
            }
        }
    }
    else if (key == "Chg")
    {
        if (order == "desc")
        {
            for (int i = 0; i < stockDataLst.size(); ++i)
            {
                StockData data = stockDataLst.at(i);
                double chg = data.Chg;

                if (i == 0)
                {
                    retLst.append(data);
                }
                else
                {
                    bool ok = true;
                    for (int j = 0; j < retLst.size(); ++j)
                    {
                        StockData data2 = retLst.at(j);
                        double chg2 = data2.Chg;

                        if (chg > chg2)
                        {
                            retLst.insert(j, data);
                            ok = false;
                            break;
                        }
                    }

                    if (ok)
                    {
                        retLst.append(data);
                    }
                }
            }
        }
        else if (order == "asc")
        {
            for (int i = 0; i < stockDataLst.size(); ++i)
            {
                StockData data = stockDataLst.at(i);
                double chg = data.Chg;

                if (i == 0)
                {
                    retLst.append(data);
                }
                else
                {
                    bool ok = true;
                    for (int j = 0; j < retLst.size(); ++j)
                    {
                        StockData data2 = retLst.at(j);
                        double chg2 = data2.Chg;

                        if (chg < chg2)
                        {
                            retLst.insert(j, data);
                            ok = false;
                            break;
                        }
                    }

                    if (ok)
                    {
                        retLst.append(data);
                    }
                }
            }
        }
    }
    else if (key == "TClose")
    {
        if (order == "desc")
        {
            for (int i = 0; i < stockDataLst.size(); ++i)
            {
                StockData data = stockDataLst.at(i);
                double tclose = data.TClose;

                if (i == 0)
                {
                    retLst.append(data);
                }
                else
                {
                    bool ok = true;
                    for (int j = 0; j < retLst.size(); ++j)
                    {
                        StockData data2 = retLst.at(j);
                        double tclose2 = data2.TClose;

                        if (tclose > tclose2)
                        {
                            retLst.insert(j, data);
                            ok = false;
                            break;
                        }
                    }

                    if (ok)
                    {
                        retLst.append(data);
                    }
                }
            }
        }
        else if (order == "asc")
        {
            for (int i = 0; i < stockDataLst.size(); ++i)
            {
                StockData data = stockDataLst.at(i);
                double tclose = data.TClose;

                if (i == 0)
                {
                    retLst.append(data);
                }
                else
                {
                    bool ok = true;
                    for (int j = 0; j < retLst.size(); ++j)
                    {
                        StockData data2 = retLst.at(j);
                        double tclose2 = data2.TClose;

                        if (tclose < tclose2)
                        {
                            retLst.insert(j, data);
                            ok = false;
                            break;
                        }
                    }

                    if (ok)
                    {
                        retLst.append(data);
                    }
                }
            }
        }
    }
    else if (key == "Voturnover")
    {
        if (order == "desc")
        {
            for (int i = 0; i < stockDataLst.size(); ++i)
            {
                StockData data = stockDataLst.at(i);
                double voturnover = data.Voturnover;

                if (i == 0)
                {
                    retLst.append(data);
                }
                else
                {
                    bool ok = true;
                    for (int j = 0; j < retLst.size(); ++j)
                    {
                        StockData data2 = retLst.at(j);
                        double voturnover2 = data2.Voturnover;

                        if (voturnover > voturnover2)
                        {
                            retLst.insert(j, data);
                            ok = false;
                            break;
                        }
                    }

                    if (ok)
                    {
                        retLst.append(data);
                    }
                }
            }
        }
        else if (order == "asc")
        {
            for (int i = 0; i < stockDataLst.size(); ++i)
            {
                StockData data = stockDataLst.at(i);
                double voturnover = data.Voturnover;

                if (i == 0)
                {
                    retLst.append(data);
                }
                else
                {
                    bool ok = true;
                    for (int j = 0; j < retLst.size(); ++j)
                    {
                        StockData data2 = retLst.at(j);
                        double voturnover2 = data2.Voturnover;

                        if (voturnover < voturnover2)
                        {
                            retLst.insert(j, data);
                            ok = false;
                            break;
                        }
                    }

                    if (ok)
                    {
                        retLst.append(data);
                    }
                }
            }
        }
    }
    else if (key == "Vaturnover")
    {
        if (order == "desc")
        {
            for (int i = 0; i < stockDataLst.size(); ++i)
            {
                StockData data = stockDataLst.at(i);
                double vaturnover = data.Vaturnover;

                if (i == 0)
                {
                    retLst.append(data);
                }
                else
                {
                    bool ok = true;
                    for (int j = 0; j < retLst.size(); ++j)
                    {
                        StockData data2 = retLst.at(j);
                        double vaturnover2 = data2.Vaturnover;

                        if (vaturnover > vaturnover2)
                        {
                            retLst.insert(j, data);
                            ok = false;
                            break;
                        }
                    }

                    if (ok)
                    {
                        retLst.append(data);
                    }
                }
            }
        }
        else if (order == "asc")
        {
            for (int i = 0; i < stockDataLst.size(); ++i)
            {
                StockData data = stockDataLst.at(i);
                double vaturnover = data.Vaturnover;

                if (i == 0)
                {
                    retLst.append(data);
                }
                else
                {
                    bool ok = true;
                    for (int j = 0; j < retLst.size(); ++j)
                    {
                        StockData data2 = retLst.at(j);
                        double vaturnover2 = data2.Vaturnover;

                        if (vaturnover < vaturnover2)
                        {
                            retLst.insert(j, data);
                            ok = false;
                            break;
                        }
                    }

                    if (ok)
                    {
                        retLst.append(data);
                    }
                }
            }
        }
    }
    else if (key == "Turnover")
    {
        if (order == "desc")
        {
            for (int i = 0; i < stockDataLst.size(); ++i)
            {
                StockData data = stockDataLst.at(i);
                double turnover = data.Turnover;

                if (i == 0)
                {
                    retLst.append(data);
                }
                else
                {
                    bool ok = true;
                    for (int j = 0; j < retLst.size(); ++j)
                    {
                        StockData data2 = retLst.at(j);
                        double turnover2 = data2.Turnover;

                        if (turnover > turnover2)
                        {
                            retLst.insert(j, data);
                            ok = false;
                            break;
                        }
                    }

                    if (ok)
                    {
                        retLst.append(data);
                    }
                }
            }
        }
        else if (order == "asc")
        {
            for (int i = 0; i < stockDataLst.size(); ++i)
            {
                StockData data = stockDataLst.at(i);
                double turnover = data.Turnover;

                if (i == 0)
                {
                    retLst.append(data);
                }
                else
                {
                    bool ok = true;
                    for (int j = 0; j < retLst.size(); ++j)
                    {
                        StockData data2 = retLst.at(j);
                        double turnover2 = data2.Turnover;

                        if (turnover < turnover2)
                        {
                            retLst.insert(j, data);
                            ok = false;
                            break;
                        }
                    }

                    if (ok)
                    {
                        retLst.append(data);
                    }
                }
            }
        }
    }

    return retLst;
}

void MainWindow::initTendencyChart()
{
    mTendencyTCloseChart = new QChart;
    mTendencyTCloseView = new QChartView(mTendencyTCloseChart);
    mTendencyTCloseSeries = new QLineSeries;
    setTendencyChart(mTendencyTCloseChart, mTendencyTCloseView, mTendencyTCloseSeries, QStringLiteral("收盘价"), QStringLiteral("价格走势"));

    mTendencyPChgChart = new QChart;
    mTendencyPChgView = new QChartView(mTendencyPChgChart);
    mTendencyPChgSeries = new QLineSeries;
    setTendencyChart(mTendencyPChgChart, mTendencyPChgView, mTendencyPChgSeries, QStringLiteral("涨跌幅"), QStringLiteral("涨跌幅走势"));

    mTendencyVoturnoverChart = new QChart;
    mTendencyVoturnoverView = new QChartView(mTendencyVoturnoverChart);
    mTendencyVoturnoverSeries = new QLineSeries;
    setTendencyChart(mTendencyVoturnoverChart, mTendencyVoturnoverView, mTendencyVoturnoverSeries, QStringLiteral("成交量"), QStringLiteral("成交量走势"));

    mTendencyTurnoverChart = new QChart;
    mTendencyTurnoverView = new QChartView(mTendencyTurnoverChart);
    mTendencyTurnoverSeries = new QLineSeries;
    setTendencyChart(mTendencyTurnoverChart, mTendencyTurnoverView, mTendencyTurnoverSeries, QStringLiteral("换手率"), QStringLiteral("换手率走势"));

    ui->gridLayout_tendency->addWidget(mTendencyTCloseView, 0, 0);
    ui->gridLayout_tendency->addWidget(mTendencyPChgView, 0, 1);
    ui->gridLayout_tendency->addWidget(mTendencyVoturnoverView, 1, 0);
    ui->gridLayout_tendency->addWidget(mTendencyTurnoverView, 1, 1);
}

void MainWindow::setTendencyChart(QChart *chart, QChartView *chartView, QLineSeries *lineSeries, QString lineSeriesName, QString chartTitle)
{
    chart->setTitleFont(this->font());
    chart->setMargins(QMargins(0, 0, 0, 0));
    chart->setAnimationOptions(QChart::SeriesAnimations);

    chartView->setRenderHint(QPainter::Antialiasing);
    chartView->setBackgroundRole(QPalette::Light);

    lineSeries->setName(lineSeriesName);

    chart->addSeries(lineSeries);
    chart->setTitle(chartTitle);
    chart->legend()->setVisible(false);
}

QList<StockData> MainWindow::selectStockDataPrev(QString code, QString name, QString curDay, int limit)
{
    QList<StockData> dataLst;

    QString retStr = mDBHelper.getConnectDB();
    if (!retStr.isEmpty())
    {
        informationMessageBox(QStringLiteral("提示"), QStringLiteral("数据库连接失败:\n%1").arg(retStr));
        return dataLst;
    }

    QStringList columnLst;
    columnLst << "topen" << "high" << "low" << "tclose" << "lclose" << "chg" << "pchg" << "voturnover" << "vaturnover" << "turnover" << "date_day";

    QString sql = QStringLiteral("select columns from t_%1 where date_day < '%2' and voturnover != '0' order by date_day desc limit %3;").arg(code).arg(curDay).arg(limit);

    QList<QStringList> retLst = mDBHelper.getSqlSelect(sql, columnLst);
    dataLst = sqlRetToStockData(code, name, retLst);

    return dataLst;
}

bool MainWindow::doubleEqual(double num, double num2)
{
    if (((num - num2) > -0.000001) && ((num - num2) < 0.000001))
    {
        return true;
    }

    return false;
}

void MainWindow::initComboBox()
{
    getStockCodeName();

    ui->comboBox_code_name->setEditable(true);
    ui->comboBox_code_name->setSizeAdjustPolicy(QComboBox::AdjustToContents);
    ui->comboBox_code_name->insertItem(0, QStringLiteral("全部"));
    ui->comboBox_code_name->insertItems(1, mStockCodeName);

    QStringList keyLst;
    keyLst << QStringLiteral("涨跌幅") << QStringLiteral("收盘价") << QStringLiteral("涨跌额") << QStringLiteral("成交量") << QStringLiteral("成交额") << QStringLiteral("换手率");
    ui->comboBox_query_key->setSizeAdjustPolicy(QComboBox::AdjustToContents);
    ui->comboBox_query_key->insertItems(0, keyLst);

    QStringList orderLst;
    orderLst << QStringLiteral("降序") << QStringLiteral("升序");
    ui->comboBox_query_order->setSizeAdjustPolicy(QComboBox::AdjustToContents);
    ui->comboBox_query_order->insertItems(0, orderLst);

    QStringList tendencyFreqLst;
    tendencyFreqLst << QStringLiteral("5日") << QStringLiteral("10日") << QStringLiteral("20日") << QStringLiteral("30日") << QStringLiteral("60日");
    ui->comboBox_tendency_freq->setSizeAdjustPolicy(QComboBox::AdjustToContents);
    ui->comboBox_tendency_freq->insertItems(0, tendencyFreqLst);
    connect(ui->comboBox_tendency_freq, SIGNAL(currentIndexChanged(QString)), this, SLOT(showStockTendency(QString)));

    ui->comboBox_tclose->setSizeAdjustPolicy(QComboBox::AdjustToContents);
    ui->comboBox_tclose->insertItem(0, QStringLiteral("无"));
    ui->comboBox_tclose->insertItems(1, mCategoriesTClose);

    QStringList pchgLst = mCategoriesPChgUp;
    pchgLst.append(mCategoriesPChgDown);
    ui->comboBox_pchg->setSizeAdjustPolicy(QComboBox::AdjustToContents);
    ui->comboBox_pchg->insertItem(0, QStringLiteral("无"));
    ui->comboBox_pchg->insertItems(1, pchgLst);

    ui->comboBox_turnover->setSizeAdjustPolicy(QComboBox::AdjustToContents);
    ui->comboBox_turnover->insertItem(0, QStringLiteral("无"));
    ui->comboBox_turnover->insertItems(1, mCategoriesTurnover);

    QStringList klineformLst;
    klineformLst << QStringLiteral("一字涨停") << QStringLiteral("跳空涨停") << QStringLiteral("放量涨停") << QStringLiteral("缩量涨停") << QStringLiteral("放量>=6%") << QStringLiteral("缩量>=6%") << QStringLiteral("MA240以上") << QStringLiteral("MA240") << QStringLiteral("MA240以下") << QStringLiteral("成交量放大") << QStringLiteral("换手率增加") << QStringLiteral("带量突破") << QStringLiteral("上升趋势") << QStringLiteral("均线多头");
    klineformLst << "----------";
    ui->comboBox_klineform->setSizeAdjustPolicy(QComboBox::AdjustToContents);
    ui->comboBox_klineform->insertItems(0, klineformLst);
}

void MainWindow::on_pushButton_query_clicked()
{
    if (ui->dateEdit_start->date() > ui->dateEdit_end->date())
    {
        return;
    }

    QDate startDate = ui->dateEdit_start->date();
    QDate endDate = ui->dateEdit_end->date();
    QString dateDay;
    while (startDate <= endDate)
    {
        dateDay.append(QStringLiteral("'%1', ").arg(startDate.toString("yyyy-MM-dd")));
        startDate = startDate.addDays(1);
    }
    dateDay.remove(dateDay.lastIndexOf(", "), 2);

    QString queryKey = ui->comboBox_query_key->currentText();
    if (queryKey == QStringLiteral("涨跌幅"))
    {
        queryKey = "PChg";
    }
    else if (queryKey == QStringLiteral("收盘价"))
    {
        queryKey = "TClose";
    }
    else if (queryKey == QStringLiteral("涨跌额"))
    {
        queryKey = "Chg";
    }
    else if (queryKey == QStringLiteral("成交量"))
    {
        queryKey = "Voturnover";
    }
    else if (queryKey == QStringLiteral("成交额"))
    {
        queryKey = "Vaturnover";
    }
    else if (queryKey == QStringLiteral("换手率"))
    {
        queryKey = "Turnover";
    }

    QString queryOrder = ui->comboBox_query_order->currentText();
    if (queryOrder == QStringLiteral("降序"))
    {
        queryOrder = "desc";
    }
    else if (queryOrder == QStringLiteral("升序"))
    {
        queryOrder = "asc";
    }

    QString stock = ui->comboBox_code_name->currentText();
    if (stock == QStringLiteral("全部"))
    {
        getAllStockByDate(endDate.toString("yyyy-MM-dd"));
        QList<StockData> dataLst = mAllStockMap.value(endDate.toString("yyyy-MM-dd"));
        QList<StockData> sortLst = sortStockDataLst(dataLst, queryKey, queryOrder);
        stockDataTable(ui->tableWidget, sortLst);
    }
    else if (stock.contains("-"))
    {
        QString code = stock.split("-")[0];
        QString name = stock.split("-")[1];

        getStockByDate(code, name, dateDay);
        stockDataTable(ui->tableWidget, mStockDataLst);
    }

    ui->tabWidget->setCurrentWidget(ui->table);
}

void MainWindow::progressCanceled()
{
    // dummy
}

NoFocusDelegate::NoFocusDelegate()
{

}

NoFocusDelegate::~NoFocusDelegate()
{

}

void NoFocusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyleOptionViewItem itemOption(option);
    if (itemOption.state & QStyle::State_HasFocus)
    {
        itemOption.state = itemOption.state ^ QStyle::State_HasFocus;
    }
    QStyledItemDelegate::paint(painter, itemOption, index);
}

void MainWindow::on_pushButton_analyse_clicked()
{
    QString date = ui->dateEdit_end->date().toString("yyyy-MM-dd");
    getAllStockByDate(date);
    QList<StockData> dataLst = mAllStockMap.value(date);

    int upCount = 0;
    int limitUpCount = 0;
    int up7Count = 0;
    int up5Count = 0;
    int up3Count = 0;
    int up0Count = 0;

    int downCount = 0;
    int down0Count = 0;
    int down3Count = 0;
    int down5Count = 0;
    int down7Count = 0;
    int limitDownCount = 0;

    int flatCount = 0;

    double totalVaturnover = 0;
    double limitUpDownVaturnover = 0;

    for (int i = 0; i < dataLst.size(); ++i)
    {
        StockData data = dataLst.at(i);
        totalVaturnover += data.Vaturnover;

        double pchg = data.PChg;

        if (pchg > 0.0)
        {
            upCount++;
        }

        if (pchg < 0.0)
        {
            downCount++;
        }

        if (pchg >= 9.90)
        {
            limitUpCount++;
            limitUpDownVaturnover += data.Vaturnover;
        }

        if (pchg <= -9.90)
        {
            limitDownCount++;
            limitUpDownVaturnover += data.Vaturnover;
        }

        if (pchg == 0.0)
        {
            flatCount++;
        }

        if (pchg > 7.0)
        {
            up7Count++;
        }

        if (pchg > 5.0 && pchg <= 7.0)
        {
            up5Count++;
        }

        if (pchg > 3.0 && pchg <= 5.0)
        {
            up3Count++;
        }

        if (pchg > 0.0 && pchg <= 3.0)
        {
            up0Count++;
        }

        if (pchg < 0.0 && pchg >= -3.0)
        {
            down0Count++;
        }

        if (pchg < -3.0 && pchg >= -5.0)
        {
            down3Count++;
        }

        if (pchg < -5.0 && pchg >= -7.0)
        {
            down5Count++;
        }

        if (pchg < -7.0)
        {
            down7Count++;
        }
    }

    mLimitUpDownLabel->setText(QStringLiteral("<h3 style=\"text-align:center; color:red; \">%1分析</h3><p><strong>一、涨跌幅分析<strong></p><p>1)涨停:%2,跌停:%3</p><p>上涨:%4,下跌:%5,平盘:%6</p><p>2)涨跌幅统计</p>")
                               .arg(date).arg(limitUpCount)
                               .arg(limitDownCount).arg(upCount)
                               .arg(downCount).arg(flatCount));

    QList<int> pchgLeftLst;
    pchgLeftLst.append(limitUpCount);
    pchgLeftLst.append(up7Count - limitUpCount);
    pchgLeftLst.append(up5Count);
    pchgLeftLst.append(up3Count);
    pchgLeftLst.append(up0Count);
    pchgLeftLst.append(flatCount);

    QBarSet *setPChgLeft = new QBarSet(QStringLiteral("涨幅统计左"));
    setChart(pchgLeftLst, mCategoriesPChgUp, setPChgLeft, mChartPChgLeft, mSeriesPChgLeft);

    QList<int> pchgRightLst;
    pchgRightLst.append(down0Count);
    pchgRightLst.append(down3Count);
    pchgRightLst.append(down5Count);
    pchgRightLst.append(down7Count - limitDownCount);
    pchgRightLst.append(limitDownCount);

    QBarSet *setPChgRight = new QBarSet(QStringLiteral("涨幅统计右"));
    setChart(pchgRightLst, mCategoriesPChgDown, setPChgRight, mChartPChgRight, mSeriesPChgRight, Qt::green);

    totalVaturnover = QString::asprintf("%.2f", totalVaturnover / 10000).toDouble();
    limitUpDownVaturnover = QString::asprintf("%.2f", limitUpDownVaturnover / 10000).toDouble();
    double rate = QString::asprintf("%.2f", limitUpDownVaturnover / totalVaturnover).toDouble() * 100;

    mVaturnoverLabel->setText(QStringLiteral("<p><strong>二、成交额分析<strong></p><p>1)总成交额:%1亿,涨跌停成交额:%2亿(%3%)</p><p>2)成交额统计</p>")
                              .arg(totalVaturnover).arg(limitUpDownVaturnover).arg(rate));

    int vaturnover5p = 0;
    int vaturnover1 = 0;
    int vaturnover5 = 0;
    int vaturnover10 = 0;
    int vaturnover20 = 0;
    int vaturnover30 = 0;
    int vaturnover50 = 0;
    int vaturnover100 = 0;
    int vaturnover1000 = 0;

    for (int i = 0; i < dataLst.size(); ++i)
    {
        StockData data = dataLst.at(i);
        double vaturnover = data.Vaturnover;

        if (vaturnover <= 5000)
        {
            vaturnover5p++;
        }
        else if (vaturnover > 5000 && vaturnover <= 10000)
        {
            vaturnover1++;
        }
        else if (vaturnover > 10000 && vaturnover <= 50000)
        {
            vaturnover5++;
        }
        else if (vaturnover > 50000 && vaturnover <= 100000)
        {
            vaturnover10++;
        }
        else if (vaturnover > 100000 && vaturnover <= 200000)
        {
            vaturnover20++;
        }
        else if (vaturnover > 200000 && vaturnover <= 300000)
        {
            vaturnover30++;
        }
        else if (vaturnover > 300000 && vaturnover <= 500000)
        {
            vaturnover50++;
        }
        else if (vaturnover > 500000 && vaturnover <= 1000000)
        {
            vaturnover100++;
        }
        else if (vaturnover > 1000000)
        {
            vaturnover1000++;
        }
    }

    QList<int> vaturnoverLst;
    vaturnoverLst.append(vaturnover5p);
    vaturnoverLst.append(vaturnover1);
    vaturnoverLst.append(vaturnover5);
    vaturnoverLst.append(vaturnover10);
    vaturnoverLst.append(vaturnover20);
    vaturnoverLst.append(vaturnover30);
    vaturnoverLst.append(vaturnover50);
    vaturnoverLst.append(vaturnover100);
    vaturnoverLst.append(vaturnover1000);

    QStringList categoriesVaturnover;
    categoriesVaturnover.append(QStringLiteral("0-5000万"));
    categoriesVaturnover.append(QStringLiteral("5000万-1亿"));
    categoriesVaturnover.append(QStringLiteral("1亿-5亿"));
    categoriesVaturnover.append(QStringLiteral("5亿-10亿"));
    categoriesVaturnover.append(QStringLiteral("10亿-20亿"));
    categoriesVaturnover.append(QStringLiteral("20亿-30亿"));
    categoriesVaturnover.append(QStringLiteral("30亿-50亿"));
    categoriesVaturnover.append(QStringLiteral("50亿-100亿"));
    categoriesVaturnover.append(QStringLiteral("> 100亿"));

    QBarSet *setVaturnover = new QBarSet(QStringLiteral("成交额统计"));
    setChart(vaturnoverLst, categoriesVaturnover, setVaturnover, mChartVaturnover, mSeriesVaturnover);

    mTurnoverLabel->setText(QStringLiteral("<p><strong>三、换手率分析<strong></p>"));

    int turnover0 = 0;
    int turnover3 = 0;
    int turnover5 = 0;
    int turnover10 = 0;
    int turnover20 = 0;
    int turnover30 = 0;
    int turnover50 = 0;

    for (int i = 0; i < dataLst.size(); ++i)
    {
        StockData data = dataLst.at(i);
        double turnover = data.Turnover;

        if (turnover <= 3)
        {
            turnover0++;
        }
        else if (turnover > 3 && turnover <= 5)
        {
            turnover3++;
        }
        else if (turnover > 5 && turnover <= 10)
        {
            turnover5++;
        }
        else if (turnover > 10 && turnover <= 20)
        {
            turnover10++;
        }
        else if (turnover > 20 && turnover <= 30)
        {
            turnover20++;
        }
        else if (turnover > 30 && turnover <= 50)
        {
            turnover30++;
        }
        else if (turnover > 50)
        {
            turnover50++;
        }
    }

    QList<int> turnoverLst;
    turnoverLst.append(turnover0);
    turnoverLst.append(turnover3);
    turnoverLst.append(turnover5);
    turnoverLst.append(turnover10);
    turnoverLst.append(turnover20);
    turnoverLst.append(turnover30);
    turnoverLst.append(turnover50);

    QBarSet *setTurnover = new QBarSet(QStringLiteral("换手率统计"));
    setChart(turnoverLst, mCategoriesTurnover, setTurnover, mChartTurnover, mSeriesTurnover);

    mTCloseLabel->setText(QStringLiteral("<p><strong>四、价格分析<strong></p>"));

    int tclose10 = 0;
    int tclose20 = 0;
    int tclose50 = 0;
    int tclose100 = 0;
    int tclose200 = 0;
    int tclose300 = 0;
    int tclose500 = 0;
    int tclose1000 = 0;
    int tclose2000 = 0;

    for (int i = 0; i < dataLst.size(); ++i)
    {
        StockData data = dataLst.at(i);
        double tclose = data.TClose;

        if (tclose <= 10)
        {
            tclose10++;
        }
        else if (tclose > 10 && tclose <= 20)
        {
            tclose20++;
        }
        else if (tclose > 20 && tclose <= 50)
        {
            tclose50++;
        }
        else if (tclose > 50 && tclose <= 100)
        {
            tclose100++;
        }
        else if (tclose > 100 && tclose <= 200)
        {
            tclose200++;
        }
        else if (tclose > 200 && tclose <= 300)
        {
            tclose300++;
        }
        else if (tclose > 300 && tclose <= 500)
        {
            tclose500++;
        }
        else if (tclose > 500 && tclose <= 1000)
        {
            tclose1000++;
        }
        else if (tclose > 1000)
        {
            tclose2000++;
        }
    }

    QList<int> tcloseLst;
    tcloseLst.append(tclose10);
    tcloseLst.append(tclose20);
    tcloseLst.append(tclose50);
    tcloseLst.append(tclose100);
    tcloseLst.append(tclose200);
    tcloseLst.append(tclose300);
    tcloseLst.append(tclose500);
    tcloseLst.append(tclose1000);
    tcloseLst.append(tclose2000);

    QBarSet *setTClose = new QBarSet(QStringLiteral("价格统计"));
    setChart(tcloseLst, mCategoriesTClose, setTClose, mChartTClose, mSeriesTClose);

    mVoturnoverLabel->setText(QStringLiteral("<p><strong>五、成交量分析(万手)<strong></p>"));

    int voturnover1 = 0;
    int voturnover10 = 0;
    int voturnover20 = 0;
    int voturnover50 = 0;
    int voturnover100 = 0;
    int voturnover200 = 0;
    int voturnover300 = 0;
    int voturnover400 = 0;
    int voturnover500 = 0;
    int voturnover600 = 0;
    int voturnover700 = 0;
    int voturnover800 = 0;
    int voturnover900 = 0;
    int voturnover1000 = 0;
    int voturnover2000 = 0;

    for (int i = 0; i < dataLst.size(); ++i)
    {
        StockData data = dataLst.at(i);
        double voturnover = data.Voturnover;

        if (voturnover <= 10000)
        {
            voturnover1++;
        }
        else if (voturnover > 10000 && voturnover <= 100000)
        {
            voturnover10++;
        }
        else if (voturnover > 100000 && voturnover <= 200000)
        {
            voturnover20++;
        }
        else if (voturnover > 200000 && voturnover <= 500000)
        {
            voturnover50++;
        }
        else if (voturnover > 500000 && voturnover <= 1000000)
        {
            voturnover100++;
        }
        else if (voturnover > 1000000 && voturnover <= 2000000)
        {
            voturnover200++;
        }
        else if (voturnover > 2000000 && voturnover <= 3000000)
        {
            voturnover300++;
        }
        else if (voturnover > 3000000 && voturnover <= 4000000)
        {
            voturnover400++;
        }
        else if (voturnover > 4000000 && voturnover <= 5000000)
        {
            voturnover500++;
        }
        else if (voturnover > 5000000 && voturnover <= 6000000)
        {
            voturnover600++;
        }
        else if (voturnover > 6000000 && voturnover <= 7000000)
        {
            voturnover700++;
        }
        else if (voturnover > 7000000 && voturnover <= 8000000)
        {
            voturnover800++;
        }
        else if (voturnover > 8000000 && voturnover <= 9000000)
        {
            voturnover900++;
        }
        else if (voturnover > 9000000 && voturnover <= 10000000)
        {
            voturnover1000++;
        }
        else if (voturnover > 10000000)
        {
            voturnover2000++;
        }
    }

    QList<int> voturnoverLst;
    voturnoverLst.append(voturnover1);
    voturnoverLst.append(voturnover10);
    voturnoverLst.append(voturnover20);
    voturnoverLst.append(voturnover50);
    voturnoverLst.append(voturnover100);
    voturnoverLst.append(voturnover200);
    voturnoverLst.append(voturnover300);
    voturnoverLst.append(voturnover400);
    voturnoverLst.append(voturnover500);
    voturnoverLst.append(voturnover600);
    voturnoverLst.append(voturnover700);
    voturnoverLst.append(voturnover800);
    voturnoverLst.append(voturnover900);
    voturnoverLst.append(voturnover1000);
    voturnoverLst.append(voturnover2000);

    QStringList categoriesVoturnover;
    categoriesVoturnover.append(QStringLiteral("0-1"));
    categoriesVoturnover.append(QStringLiteral("1-10"));
    categoriesVoturnover.append(QStringLiteral("10-20"));
    categoriesVoturnover.append(QStringLiteral("20-50"));
    categoriesVoturnover.append(QStringLiteral("50-100"));
    categoriesVoturnover.append(QStringLiteral("100-200"));
    categoriesVoturnover.append(QStringLiteral("200-300"));
    categoriesVoturnover.append(QStringLiteral("300-400"));
    categoriesVoturnover.append(QStringLiteral("400-500"));
    categoriesVoturnover.append(QStringLiteral("500-600"));
    categoriesVoturnover.append(QStringLiteral("600-700"));
    categoriesVoturnover.append(QStringLiteral("700-800"));
    categoriesVoturnover.append(QStringLiteral("800-900"));
    categoriesVoturnover.append(QStringLiteral("900-1000"));
    categoriesVoturnover.append(QStringLiteral("> 1000"));

    QBarSet *setVoturnover = new QBarSet(QStringLiteral("成交量统计"));
    setChart(voturnoverLst, categoriesVoturnover, setVoturnover, mChartVoturnover, mSeriesVoturnover);

    mChgLabel->setText(QStringLiteral("<p><strong>六、涨跌额分析<strong></p>"));

    int chg0p01 = 0;
    int chg0p1 = 0;
    int chg0p2 = 0;
    int chg0p3 = 0;
    int chg0p4 = 0;
    int chg0p5 = 0;
    int chg0p6 = 0;
    int chg0p7 = 0;
    int chg0p8 = 0;
    int chg0p9 = 0;
    int chg1 = 0;
    int chg1p2 = 0;
    int chg1p4 = 0;
    int chg1p6 = 0;
    int chg1p8 = 0;
    int chg2 = 0;
    int chg3 = 0;
    int chg4 = 0;
    int chg5 = 0;
    int chg10 = 0;
    int chg20 = 0;

    for (int i = 0; i < dataLst.size(); ++i)
    {
        StockData data = dataLst.at(i);
        double chg = data.Chg;

        if (chg >= 0.01 && chg < 0.1)
        {
            chg0p01++;
        }
        else if (chg >= 0.1 && chg < 0.2)
        {
            chg0p1++;
        }
        else if (chg >= 0.2 && chg < 0.3)
        {
            chg0p2++;
        }
        else if (chg >= 0.3 && chg < 0.4)
        {
            chg0p3++;
        }
        else if (chg >= 0.4 && chg < 0.5)
        {
            chg0p4++;
        }
        else if (chg >= 0.5 && chg < 0.6)
        {
            chg0p5++;
        }
        else if (chg >= 0.6 && chg < 0.7)
        {
            chg0p6++;
        }
        else if (chg >= 0.7 && chg < 0.8)
        {
            chg0p7++;
        }
        else if (chg >= 0.8 && chg < 0.9)
        {
            chg0p8++;
        }
        else if (chg >= 0.9 && chg < 1.0)
        {
            chg0p9++;
        }
        else if (chg >= 1.0 && chg < 1.2)
        {
            chg1++;
        }
        else if (chg >= 1.2 && chg < 1.4)
        {
            chg1p2++;
        }
        else if (chg >= 1.4 && chg < 1.6)
        {
            chg1p4++;
        }
        else if (chg >= 1.6 && chg < 1.8)
        {
            chg1p6++;
        }
        else if (chg >= 1.8 && chg < 2.0)
        {
            chg1p8++;
        }
        else if (chg >= 2.0 && chg < 3.0)
        {
            chg2++;
        }
        else if (chg >= 3.0 && chg < 4.0)
        {
            chg3++;
        }
        else if (chg >= 4.0 && chg < 5.0)
        {
            chg4++;
        }
        else if (chg >= 5.0 && chg < 10.0)
        {
            chg5++;
        }
        else if (chg >= 10.0 && chg < 20.0)
        {
            chg10++;
        }
        else if (chg >= 20.0)
        {
            chg20++;
        }
    }

    QList<int> chgLst;
    chgLst.append(chg0p01);
    chgLst.append(chg0p1);
    chgLst.append(chg0p2);
    chgLst.append(chg0p3);
    chgLst.append(chg0p4);
    chgLst.append(chg0p5);
    chgLst.append(chg0p6);
    chgLst.append(chg0p7);
    chgLst.append(chg0p8);
    chgLst.append(chg0p9);
    chgLst.append(chg1);
    chgLst.append(chg1p2);
    chgLst.append(chg1p4);
    chgLst.append(chg1p6);
    chgLst.append(chg1p8);
    chgLst.append(chg2);
    chgLst.append(chg3);
    chgLst.append(chg4);
    chgLst.append(chg5);
    chgLst.append(chg10);
    chgLst.append(chg20);

    QStringList categoriesChg;
    categoriesChg.append(QStringLiteral("0.1"));
    categoriesChg.append(QStringLiteral("0.2"));
    categoriesChg.append(QStringLiteral("0.3"));
    categoriesChg.append(QStringLiteral("0.4"));
    categoriesChg.append(QStringLiteral("0.5"));
    categoriesChg.append(QStringLiteral("0.6"));
    categoriesChg.append(QStringLiteral("0.7"));
    categoriesChg.append(QStringLiteral("0.8"));
    categoriesChg.append(QStringLiteral("0.9"));
    categoriesChg.append(QStringLiteral("1.0"));
    categoriesChg.append(QStringLiteral("1.2"));
    categoriesChg.append(QStringLiteral("1.4"));
    categoriesChg.append(QStringLiteral("1.6"));
    categoriesChg.append(QStringLiteral("1.8"));
    categoriesChg.append(QStringLiteral("2.0"));
    categoriesChg.append(QStringLiteral("3.0"));
    categoriesChg.append(QStringLiteral("4.0"));
    categoriesChg.append(QStringLiteral("5.0"));
    categoriesChg.append(QStringLiteral("10.0"));
    categoriesChg.append(QStringLiteral("20.0"));
    categoriesChg.append(QStringLiteral("> 20.0"));

    int chg0p2_0p5 = chg0p2 + chg0p3 + chg0p4;
    int chg0p5_1 = chg0p5 + chg0p6 + chg0p7 + chg0p8 + chg0p9;
    int chg1_2 = chg1 + chg1p2 + chg1p4 + chg1p6 + chg1p8;
    int chg2_5 = chg2 + chg3 + chg4;
    int chg5_20 = chg5 + chg10 + chg20;

    double percent = QString::asprintf("%.2f", (double)(chg0p01 + chg0p1 + chg0p2_0p5 + chg0p5_1 + chg1_2 + chg2_5 + chg5_20) / dataLst.size()).toDouble();

    mChartChgPie->setTitle(QStringLiteral("赚钱效应 %1%").arg(percent * 100));

    mSeriesChgPie->clear();
    mSeriesChgPie->append("0.1", chg0p01);
    mSeriesChgPie->append("0.2", chg0p1);
    mSeriesChgPie->append("0.5", chg0p2_0p5);
    mSeriesChgPie->append("1", chg0p5_1);
    mSeriesChgPie->append("2", chg1_2);
    mSeriesChgPie->append("5", chg2_5);
    mSeriesChgPie->append("20", chg5_20);

    if (!mChartChgPie->series().isEmpty())
    {
        mChartChgPie->removeSeries(mSeriesChgPie);
    }
    mChartChgPie->addSeries(mSeriesChgPie);

    mSeriesChgPie->setPieSize(1);
    mSeriesChgPie->setLabelsPosition(QPieSlice::LabelInsideHorizontal);
    mSeriesChgPie->setLabelsVisible(true);

    QBarSet *setChg = new QBarSet(QStringLiteral("涨跌额统计"));
    setChart(chgLst, categoriesChg, setChg, mChartChg, mSeriesChg);

    ui->tabWidget->setCurrentWidget(ui->statistics);
}

void MainWindow::screenMenuDisplayed(const QPoint &pos)
{
    QTableWidgetItem *item = ui->tableWidget_screening->itemAt(pos);
    if (item != nullptr)
    {
        QMenu *menu = new QMenu(ui->tableWidget_screening);

        QAction *saveAsTDX = new QAction(QStringLiteral("导出通达信"), ui->tableWidget_screening);
        connect(saveAsTDX, SIGNAL(triggered(bool)), this, SLOT(saveAsTDX()));

        QAction *saveAsClipboard = new QAction(QStringLiteral("导出剪贴板"), ui->tableWidget_screening);
        connect(saveAsClipboard, SIGNAL(triggered(bool)), this, SLOT(saveAsClipboard()));

        QAction *FL69 = new QAction(QStringLiteral("放量>=6%"), ui->tableWidget_screening);
        connect(FL69, SIGNAL(triggered(bool)), this, SLOT(FL69()));

        QAction *SL69 = new QAction(QStringLiteral("缩量>=6%"), ui->tableWidget_screening);
        connect(SL69, SIGNAL(triggered(bool)), this, SLOT(SL69()));

        QAction *MA240UP = new QAction(QStringLiteral("MA240以上"), ui->tableWidget_screening);
        connect(MA240UP, SIGNAL(triggered(bool)), this, SLOT(MA240UP()));

        QAction *MA240 = new QAction(QStringLiteral("MA240"), ui->tableWidget_screening);
        connect(MA240, SIGNAL(triggered(bool)), this, SLOT(MA240()));

        QAction *MA240DOWN = new QAction(QStringLiteral("MA240以下"), ui->tableWidget_screening);
        connect(MA240DOWN, SIGNAL(triggered(bool)), this, SLOT(MA240DOWN()));

        QAction *CJLFD = new QAction(QStringLiteral("成交量放大"), ui->tableWidget_screening);
        connect(CJLFD, SIGNAL(triggered(bool)), this, SLOT(CJLFD()));

        QAction *HSLZJ = new QAction(QStringLiteral("换手率增加"), ui->tableWidget_screening);
        connect(HSLZJ, SIGNAL(triggered(bool)), this, SLOT(HSLZJ()));

        QAction *DLTP = new QAction(QStringLiteral("带量突破"), ui->tableWidget_screening);
        connect(DLTP, SIGNAL(triggered(bool)), this, SLOT(DLTP()));

        QAction *SSQS = new QAction(QStringLiteral("上升趋势"), ui->tableWidget_screening);
        connect(SSQS, SIGNAL(triggered(bool)), this, SLOT(SSQS()));

        QAction *MA5_10_20 = new QAction(QStringLiteral("均线多头"), ui->tableWidget_screening);
        connect(MA5_10_20, SIGNAL(triggered(bool)), this, SLOT(MA5_10_20()));

        menu->addAction(saveAsTDX);
        menu->addAction(saveAsClipboard);

        menu->addSeparator();
        menu->addAction(FL69);
        menu->addAction(SL69);
        menu->addAction(MA240UP);
        menu->addAction(MA240);
        menu->addAction(MA240DOWN);

        menu->addSeparator();
        menu->addAction(CJLFD);
        menu->addAction(HSLZJ);
        menu->addAction(DLTP);
        menu->addAction(SSQS);
        menu->addAction(MA5_10_20);

        menu->exec(QCursor::pos());

        delete saveAsTDX;
        delete saveAsClipboard;
        delete FL69;
        delete SL69;
        delete MA240UP;
        delete MA240;
        delete MA240DOWN;
        delete CJLFD;
        delete HSLZJ;
        delete DLTP;
        delete SSQS;
        delete MA5_10_20;
        delete menu;
    }
}

void MainWindow::saveAsTDX()
{
    int rowCount = ui->tableWidget_screening->rowCount();

    if (rowCount == 0)
    {
        return;
    }

    QStringList codeLst;
    for (int row = 0; row < rowCount; ++row)
    {
        codeLst.append(ui->tableWidget_screening->item(row, 0)->text());
    }

    QFile file(QStringLiteral("%1.txt")
               .arg(QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss")));
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        return;
    }

    QTextStream out(&file);
    out.setCodec("UTF-8");

    foreach (QString code, codeLst)
    {
        out << code << endl;
    }

    file.close();
}

void MainWindow::saveAsClipboard()
{
    int rowCount = ui->tableWidget_screening->rowCount();

    if (rowCount == 0)
    {
        return;
    }

    QString code;
    for (int row = 0; row < rowCount; ++row)
    {
        code.append(ui->tableWidget_screening->item(row, 0)->text() + "\r\n");
    }

    QClipboard *clipboard = QApplication::clipboard();
    clipboard->setText(code);
}

void MainWindow::FL69()
{
    QList<StockData> retLst;
    QList<StockData> prevLst;

    for (int i = 0; i < mScreeningStockDataLst.size(); ++i)
    {
        StockData data = mScreeningStockDataLst.at(i);
        double pchg = data.PChg;
        int voturnover = data.Voturnover;

        QStringList dateLst = data.Date.split("/");
        QString date = QStringLiteral("%1-%2-%3").arg(dateLst[0]).arg(dateLst[1]).arg(dateLst[2]);

        if (pchg >= 6.0 && pchg < 9.90)
        {
            prevLst = selectStockDataPrev(data.Code, data.Name, date);
            int voturnover2 = prevLst.first().Voturnover;

            if (voturnover >= (voturnover2 * 1.5))
            {
                retLst.append(data);
            }
        }
    }

    QList<StockData> sortLst = sortStockDataLst(retLst);
    mScreeningStockDataLst = sortLst;
    stockDataTable(ui->tableWidget_screening, sortLst);
}

void MainWindow::SL69()
{
    QList<StockData> retLst;
    QList<StockData> prevLst;

    for (int i = 0; i < mScreeningStockDataLst.size(); ++i)
    {
        StockData data = mScreeningStockDataLst.at(i);
        double pchg = data.PChg;
        int voturnover = data.Voturnover;

        QStringList dateLst = data.Date.split("/");
        QString date = QStringLiteral("%1-%2-%3").arg(dateLst[0]).arg(dateLst[1]).arg(dateLst[2]);

        if (pchg >= 6.0 && pchg < 9.90)
        {
            prevLst = selectStockDataPrev(data.Code, data.Name, date);
            int voturnover2 = prevLst.first().Voturnover;

            if ((voturnover <= (voturnover2 * 0.5)) || (voturnover <= voturnover2))
            {
                retLst.append(data);
            }
        }
    }

    QList<StockData> sortLst = sortStockDataLst(retLst);
    mScreeningStockDataLst = sortLst;
    stockDataTable(ui->tableWidget_screening, sortLst);
}

void MainWindow::MA240UP()
{
    QList<StockData> retLst;
    QList<StockData> prevLst;

    for (int i = 0; i < mScreeningStockDataLst.size(); ++i)
    {
        StockData data = mScreeningStockDataLst.at(i);
        double low = data.Low;
        double tclose240 = data.TClose;

        QStringList dateLst = data.Date.split("/");
        QString date = QStringLiteral("%1-%2-%3").arg(dateLst[0]).arg(dateLst[1]).arg(dateLst[2]);

        prevLst = selectStockDataPrev(data.Code, data.Name, date, 239);
        foreach (StockData data, prevLst)
        {
            tclose240 += data.TClose;
        }

        double ma240 = QString::asprintf("%.2f", tclose240 / 240).toDouble();

        if (low > ma240)
        {
            retLst.append(data);
        }
    }

    QList<StockData> sortLst = sortStockDataLst(retLst);
    mScreeningStockDataLst = sortLst;
    stockDataTable(ui->tableWidget_screening, sortLst);
}

void MainWindow::MA240()
{
    QList<StockData> retLst;
    QList<StockData> prevLst;

    for (int i = 0; i < mScreeningStockDataLst.size(); ++i)
    {
        StockData data = mScreeningStockDataLst.at(i);
        double high = data.High;
        double low = data.Low;
        double tclose240 = data.TClose;

        QStringList dateLst = data.Date.split("/");
        QString date = QStringLiteral("%1-%2-%3").arg(dateLst[0]).arg(dateLst[1]).arg(dateLst[2]);

        prevLst = selectStockDataPrev(data.Code, data.Name, date, 239);
        foreach (StockData data, prevLst)
        {
            tclose240 += data.TClose;
        }

        double ma240 = QString::asprintf("%.2f", tclose240 / 240).toDouble();

        if ((ma240 >= low) && (ma240 <= high))
        {
            retLst.append(data);
        }
    }

    QList<StockData> sortLst = sortStockDataLst(retLst);
    mScreeningStockDataLst = sortLst;
    stockDataTable(ui->tableWidget_screening, sortLst);
}

void MainWindow::MA240DOWN()
{
    QList<StockData> retLst;
    QList<StockData> prevLst;

    for (int i = 0; i < mScreeningStockDataLst.size(); ++i)
    {
        StockData data = mScreeningStockDataLst.at(i);
        double high = data.High;
        double tclose240 = data.TClose;

        QStringList dateLst = data.Date.split("/");
        QString date = QStringLiteral("%1-%2-%3").arg(dateLst[0]).arg(dateLst[1]).arg(dateLst[2]);

        prevLst = selectStockDataPrev(data.Code, data.Name, date, 239);
        foreach (StockData data, prevLst)
        {
            tclose240 += data.TClose;
        }

        double ma240 = QString::asprintf("%.2f", tclose240 / 240).toDouble();

        if (high < ma240)
        {
            retLst.append(data);
        }
    }

    QList<StockData> sortLst = sortStockDataLst(retLst);
    mScreeningStockDataLst = sortLst;
    stockDataTable(ui->tableWidget_screening, sortLst);
}

void MainWindow::CJLFD()
{
    QList<StockData> retLst;
    QList<StockData> prevLst;

    for (int i = 0; i < mScreeningStockDataLst.size(); ++i)
    {
        StockData data = mScreeningStockDataLst.at(i);
        int voturnover = data.Voturnover;

        QStringList dateLst = data.Date.split("/");
        QString date = QStringLiteral("%1-%2-%3").arg(dateLst[0]).arg(dateLst[1]).arg(dateLst[2]);

        prevLst = selectStockDataPrev(data.Code, data.Name, date);
        int voturnover2 = prevLst.first().Voturnover;

        if (voturnover >= (voturnover2 * 1.5))
        {
            retLst.append(data);
        }
    }

    QList<StockData> sortLst = sortStockDataLst(retLst);
    mScreeningStockDataLst = sortLst;
    stockDataTable(ui->tableWidget_screening, sortLst);
}

void MainWindow::HSLZJ()
{
    QList<StockData> retLst;
    QList<StockData> prevLst;

    for (int i = 0; i < mScreeningStockDataLst.size(); ++i)
    {
        StockData data = mScreeningStockDataLst.at(i);
        double turnover = data.Turnover;

        QStringList dateLst = data.Date.split("/");
        QString date = QStringLiteral("%1-%2-%3").arg(dateLst[0]).arg(dateLst[1]).arg(dateLst[2]);

        if (turnover >= 3.0)
        {
            prevLst = selectStockDataPrev(data.Code, data.Name, date);
            double turnover2 = prevLst.first().Turnover;

            if (turnover >= (turnover2 * 2))
            {
                retLst.append(data);
            }
        }
    }

    QList<StockData> sortLst = sortStockDataLst(retLst);
    mScreeningStockDataLst = sortLst;
    stockDataTable(ui->tableWidget_screening, sortLst);
}

void MainWindow::DLTP()
{
    QList<StockData> retLst;
    QList<StockData> prevLst;

    for (int i = 0; i < mScreeningStockDataLst.size(); ++i)
    {
        StockData data = mScreeningStockDataLst.at(i);
        double pchg = data.PChg;
        double turnover = data.Turnover;

        QStringList dateLst = data.Date.split("/");
        QString date = QStringLiteral("%1-%2-%3").arg(dateLst[0]).arg(dateLst[1]).arg(dateLst[2]);

        if ((turnover >= 3.0) && (pchg >= 6.0))
        {
            prevLst = selectStockDataPrev(data.Code, data.Name, date);
            double pchg2 = prevLst.first().PChg;

            if (pchg2 <= 2.0)
            {
                retLst.append(data);
            }
        }
    }

    QList<StockData> sortLst = sortStockDataLst(retLst);
    mScreeningStockDataLst = sortLst;
    stockDataTable(ui->tableWidget_screening, sortLst);
}

void MainWindow::SSQS()
{
    QList<StockData> retLst;
    QList<StockData> prevLst;

    for (int i = 0; i < mScreeningStockDataLst.size(); ++i)
    {
        StockData data = mScreeningStockDataLst.at(i);
        double tclose = data.TClose;

        QStringList dateLst = data.Date.split("/");
        QString date = QStringLiteral("%1-%2-%3").arg(dateLst[0]).arg(dateLst[1]).arg(dateLst[2]);

        if (data.isYangXian())
        {
            prevLst = selectStockDataPrev(data.Code, data.Name, date, 4);
            if (prevLst.size() == 4)
            {
                StockData data1 = prevLst.at(0);
                StockData data2 = prevLst.at(1);
                StockData data3 = prevLst.at(2);
                StockData data4 = prevLst.at(3);

                double tclose1 = data1.TClose;
                double tclose2 = data2.TClose;
                double tclose3 = data3.TClose;
                double tclose4 = data4.TClose;

                if (data1.isYangXian() && data2.isYangXian() && data3.isYangXian() && data4.isYangXian())
                {
                    if ((tclose > tclose1) && (tclose1 > tclose2) && (tclose2 > tclose3) && (tclose3 > tclose4))
                    {
                        retLst.append(data);
                    }
                }
            }
        }
    }

    QList<StockData> sortLst = sortStockDataLst(retLst);
    mScreeningStockDataLst = sortLst;
    stockDataTable(ui->tableWidget_screening, sortLst);
}

void MainWindow::MA5_10_20()
{
    QList<StockData> retLst;
    QList<StockData> prevLst;

    for (int i = 0; i < mScreeningStockDataLst.size(); ++i)
    {
        StockData data = mScreeningStockDataLst.at(i);
        double tclose = data.TClose;
        double tclose5 = tclose;
        double tclose10 = tclose;
        double tclose20 = tclose;

        QStringList dateLst = data.Date.split("/");
        QString date = QStringLiteral("%1-%2-%3").arg(dateLst[0]).arg(dateLst[1]).arg(dateLst[2]);

        prevLst = selectStockDataPrev(data.Code, data.Name, date, 19);
        for (int i = 0; i < prevLst.size(); ++i)
        {
            double tclose = prevLst.at(i).TClose;

            if (i <= 3)
            {
                tclose5 += tclose;
            }

            if (i <= 8)
            {
                tclose10 += tclose;
            }

            if (i <= 18)
            {
                tclose20 += tclose;
            }
        }

        double ma5 = QString::asprintf("%.2f", tclose5 / 5).toDouble();
        double ma10 = QString::asprintf("%.2f", tclose10 / 10).toDouble();
        double ma20 = QString::asprintf("%.2f", tclose20 / 20).toDouble();

        if ((ma5 >= ma10) && (ma5 >= ma20) && (ma10 >= ma20))
        {
            retLst.append(data);
        }
    }

    QList<StockData> sortLst = sortStockDataLst(retLst);
    mScreeningStockDataLst = sortLst;
    stockDataTable(ui->tableWidget_screening, sortLst);
}

void MainWindow::on_pushButton_screening_clicked()
{
    QString tcloseStr = ui->comboBox_tclose->currentText();
    QString pchgStr = ui->comboBox_pchg->currentText();
    QString turnoverStr = ui->comboBox_turnover->currentText();

    if ((tcloseStr == QStringLiteral("无")) && (pchgStr == QStringLiteral("无")) && (turnoverStr == QStringLiteral("无")))
    {
        return;
    }

    QList<StockData> retLst;

    QString date = ui->dateEdit_end->date().toString("yyyy-MM-dd");
    getAllStockByDate(date);
    QList<StockData> dataLst = mAllStockMap.value(date);

    dataLst = sortStockDataLst(dataLst, "TClose");

    QList<StockData> tcloseLst;
    bool isTClose = true;
    for (int i = 0; i < dataLst.size(); ++i)
    {
        if (tcloseStr == QStringLiteral("无"))
        {
            isTClose = false;
            break;
        }

        StockData data = dataLst.at(i);
        double tclose = data.TClose;

        if (tcloseStr == QStringLiteral("0-10"))
        {
            if (tclose <= 10)
            {
                tcloseLst.append(data);
            }
        }
        else if (tcloseStr == QStringLiteral("10-20"))
        {
            if (tclose > 10 && tclose <= 20)
            {
                tcloseLst.append(data);
            }
        }
        else if (tcloseStr == QStringLiteral("20-50"))
        {
            if (tclose > 20 && tclose <= 50)
            {
                tcloseLst.append(data);
            }
        }
        else if (tcloseStr == QStringLiteral("50-100"))
        {
            if (tclose > 50 && tclose <= 100)
            {
                tcloseLst.append(data);
            }
        }
        else if (tcloseStr == QStringLiteral("100-200"))
        {
            if (tclose > 100 && tclose <= 200)
            {
                tcloseLst.append(data);
            }
        }
        else if (tcloseStr == QStringLiteral("200-300"))
        {
            if (tclose > 200 && tclose <= 300)
            {
                tcloseLst.append(data);
            }
        }
        else if (tcloseStr == QStringLiteral("300-500"))
        {
            if (tclose > 300 && tclose <= 500)
            {
                tcloseLst.append(data);
            }
        }
        else if (tcloseStr == QStringLiteral("500-1000"))
        {
            if (tclose > 500 && tclose <= 1000)
            {
                tcloseLst.append(data);
            }
        }
        else if (tcloseStr == QStringLiteral("> 1000"))
        {
            if (tclose > 1000)
            {
                tcloseLst.append(data);
            }
        }
    }

    dataLst = sortStockDataLst(dataLst, "PChg");

    QList<StockData> pchgLst;
    bool isPChg = true;
    for (int i = 0; i < dataLst.size(); ++i)
    {
        if (pchgStr == QStringLiteral("无"))
        {
            isPChg = false;
            break;
        }

        StockData data = dataLst.at(i);
        double pchg = data.PChg;

        if (pchgStr == QStringLiteral("涨停↑"))
        {
            if (pchg >= 9.90)
            {
                pchgLst.append(data);
            }
        }
        else if (pchgStr == QStringLiteral("> 7%↑"))
        {
            if (pchg > 7.0 && pchg < 9.90)
            {
                pchgLst.append(data);
            }
        }
        else if (pchgStr == QStringLiteral("5-7%↑"))
        {
            if (pchg > 5.0 && pchg <= 7.0)
            {
                pchgLst.append(data);
            }
        }
        else if (pchgStr == QStringLiteral("3-5%↑"))
        {
            if (pchg > 3.0 && pchg <= 5.0)
            {
                pchgLst.append(data);
            }
        }
        else if (pchgStr == QStringLiteral("0-3%↑"))
        {
            if (pchg > 0.0 && pchg <= 3.0)
            {
                pchgLst.append(data);
            }
        }
        else if (pchgStr == QStringLiteral("平盘"))
        {
            if (pchg == 0.0)
            {
                pchgLst.append(data);
            }
        }
        else if (pchgStr == QStringLiteral("0-3%↓"))
        {
            if (pchg < 0.0 && pchg >= -3.0)
            {
                pchgLst.append(data);
            }
        }
        else if (pchgStr == QStringLiteral("3-5%↓"))
        {
            if (pchg < -3.0 && pchg >= -5.0)
            {
                pchgLst.append(data);
            }
        }
        else if (pchgStr == QStringLiteral("5-7%↓"))
        {
            if (pchg < -5.0 && pchg >= -7.0)
            {
                pchgLst.append(data);
            }
        }
        else if (pchgStr == QStringLiteral("> 7%↓"))
        {
            if (pchg < -7.0 && pchg > -9.90)
            {
                pchgLst.append(data);
            }
        }
        else if (pchgStr == QStringLiteral("跌停↓"))
        {
            if (pchg <= -9.90)
            {
                pchgLst.append(data);
            }
        }
    }

    if (isTClose && isPChg)
    {
        int min = qMin(tcloseLst.size(), pchgLst.size());

        if (min == 0)
        {
            if (tcloseLst.isEmpty())
            {
                stockDataTable(ui->tableWidget_screening, tcloseLst);
            }
            else
            {
                stockDataTable(ui->tableWidget_screening, pchgLst);
            }

            return;
        }

        if (min == tcloseLst.size())
        {
            foreach (StockData data, tcloseLst)
            {
                if (pchgLst.contains(data))
                {
                    retLst.append(data);
                }
            }
        }
        else
        {
            foreach (StockData data, pchgLst)
            {
                if (tcloseLst.contains(data))
                {
                    retLst.append(data);
                }
            }
        }
    }
    else
    {
        if (isTClose)
        {
            retLst = tcloseLst;
        }

        if (isPChg)
        {
            retLst = pchgLst;
        }
    }

    dataLst = sortStockDataLst(dataLst, "Turnover");

    QList<StockData> turnoverLst;
    bool isTurnover = true;
    for (int i = 0; i < dataLst.size(); ++i)
    {
        if (turnoverStr == QStringLiteral("无"))
        {
            isTurnover = false;
            break;
        }

        StockData data = dataLst.at(i);
        double turnover = data.Turnover;

        if (turnoverStr == QStringLiteral("0-3%"))
        {
            if (turnover <= 3)
            {
                turnoverLst.append(data);
            }
        }
        else if (turnoverStr == QStringLiteral("3-5%"))
        {
            if (turnover > 3 && turnover <= 5)
            {
                turnoverLst.append(data);
            }
        }
        else if (turnoverStr == QStringLiteral("5-10%"))
        {
            if (turnover > 5 && turnover <= 10)
            {
                turnoverLst.append(data);
            }
        }
        else if (turnoverStr == QStringLiteral("10-20%"))
        {
            if (turnover > 10 && turnover <= 20)
            {
                turnoverLst.append(data);
            }
        }
        else if (turnoverStr == QStringLiteral("20-30%"))
        {
            if (turnover > 20 && turnover <= 30)
            {
                turnoverLst.append(data);
            }
        }
        else if (turnoverStr == QStringLiteral("30-50%"))
        {
            if (turnover > 30 && turnover <= 50)
            {
                turnoverLst.append(data);
            }
        }
        else if (turnoverStr == QStringLiteral("> 50%"))
        {
            if (turnover > 50)
            {
                turnoverLst.append(data);
            }
        }
    }

    QList<StockData> retLst2;
    if (isTClose || isPChg)
    {
        if (isTurnover)
        {
            int min = qMin(retLst.size(), turnoverLst.size());

            if (min == 0)
            {
                if (retLst.isEmpty())
                {
                    stockDataTable(ui->tableWidget_screening, retLst);
                }
                else
                {
                    stockDataTable(ui->tableWidget_screening, turnoverLst);
                }

                return;
            }

            if (min == retLst.size())
            {
                foreach (StockData data, retLst)
                {
                    if (turnoverLst.contains(data))
                    {
                        retLst2.append(data);
                    }
                }
            }
            else
            {
                foreach (StockData data, turnoverLst)
                {
                    if (retLst.contains(data))
                    {
                        retLst2.append(data);
                    }
                }
            }

            QList<StockData> sortLst = sortStockDataLst(retLst2);
            mScreeningStockDataLst = sortLst;
            stockDataTable(ui->tableWidget_screening, sortLst);
        }
        else
        {
            if (isTClose && isPChg)
            {
                QList<StockData> sortLst = sortStockDataLst(retLst);
                mScreeningStockDataLst = sortLst;
                stockDataTable(ui->tableWidget_screening, sortLst);
            }
            else
            {
                mScreeningStockDataLst = retLst;
                stockDataTable(ui->tableWidget_screening, retLst);
            }
        }
    }
    else
    {
        mScreeningStockDataLst = turnoverLst;
        stockDataTable(ui->tableWidget_screening, turnoverLst);
    }
}

void MainWindow::on_pushButton_limitupdown_screening_clicked()
{
    QString date = ui->dateEdit_end->date().toString("yyyy-MM-dd");
    getAllStockByDate(date);
    QList<StockData> dataLst = mAllStockMap.value(date);

    QList<StockData> retLst;
    for (int i = 0; i < dataLst.size(); ++i)
    {
        StockData data = dataLst.at(i);
        double pchg = data.PChg;

        if ((pchg >= 9.90) || (pchg <= -9.90))
        {
            retLst.append(data);
        }
    }

    QList<StockData> sortLst = sortStockDataLst(retLst);
    mScreeningStockDataLst = sortLst;
    stockDataTable(ui->tableWidget_screening, sortLst);
}

void MainWindow::getStockTendency(QModelIndex index)
{
    Q_UNUSED(index);
    QTableWidget *tableWidget = qobject_cast<QTableWidget *>(sender());
    int row = tableWidget->currentRow();

    mStockTendencyCode = tableWidget->item(row, 0)->text();
    mStockTendencyName = tableWidget->item(row, 1)->text();

    ui->label_tendency->setText(QStringLiteral("%1 %2").arg(mStockTendencyCode).arg(mStockTendencyName));
    ui->comboBox_tendency_freq->setCurrentText(QStringLiteral("5日"));
    showStockTendency(QStringLiteral("5日"));

    ui->tabWidget->setCurrentWidget(ui->tendency);
}

void MainWindow::showStockTendency(QString str)
{
    if (mStockTendencyCode.isEmpty() || mStockTendencyName.isEmpty())
    {
        return;
    }

    QString retStr = mDBHelper.getConnectDB();
    if (!retStr.isEmpty())
    {
        informationMessageBox(QStringLiteral("提示"), QStringLiteral("数据库连接失败:\n%1").arg(retStr));
        return;
    }

    int limit = 5;
    if (str == QStringLiteral("5日"))
    {
        limit = 5;
    }
    else if (str == QStringLiteral("10日"))
    {
        limit = 10;
    }
    else if (str == QStringLiteral("20日"))
    {
        limit = 20;
    }
    else if (str == QStringLiteral("30日"))
    {
        limit = 30;
    }
    else if (str == QStringLiteral("60日"))
    {
        limit = 60;
    }

    QStringList columnLst;
    columnLst << "topen" << "high" << "low" << "tclose" << "lclose" << "chg" << "pchg" << "voturnover" << "vaturnover" << "turnover" << "date_day";

    QString sql = QStringLiteral("select columns from t_%1 where voturnover != '0' order by date_day desc limit %2;").arg(mStockTendencyCode).arg(limit);

    QList<QStringList> retLst = mDBHelper.getSqlSelect(sql, columnLst);
    QList<StockData> dataLst = sqlRetToStockData(mStockTendencyCode, mStockTendencyName, retLst);

    int count = 1;
    QVector<QPointF> points;
    QList<double> tmpLst;
    int size = dataLst.size();

    for (int i = size - 1; i >= 0; --i)
    {
        tmpLst.append(dataLst.at(i).TClose);
        points.append(QPointF(count++, dataLst.at(i).TClose));
    }

    mTendencyTCloseSeries->replace(points);

    QValueAxis *axisXTClose = new QValueAxis;
    axisXTClose->setRange(1, size);
    axisXTClose->setLabelFormat("%d");
    axisXTClose->setLabelsFont(this->font());
    axisXTClose->setVisible(false);

    qSort(tmpLst.begin(), tmpLst.end());
    QValueAxis *axisYTClose = new QValueAxis;
    axisYTClose->setRange(tmpLst.first(), tmpLst.last());
    axisYTClose->setLabelFormat("%.2f");
    axisYTClose->setLabelsFont(this->font());

    mTendencyTCloseChart->setAxisX(axisXTClose, mTendencyTCloseSeries);
    mTendencyTCloseChart->setAxisY(axisYTClose, mTendencyTCloseSeries);

    count = 1;
    points.clear();
    for (int i = size - 1; i >= 0; --i)
    {
        points.append(QPointF(count++, dataLst.at(i).PChg));
    }

    mTendencyPChgSeries->replace(points);

    QValueAxis *axisXPChg = new QValueAxis;
    axisXPChg->setRange(1, size);
    axisXPChg->setLabelFormat("%d");
    axisXPChg->setLabelsFont(this->font());
    axisXPChg->setVisible(false);

    QValueAxis *axisYPChg = new QValueAxis;
    axisYPChg->setRange(-10, 10);
    axisYPChg->setLabelFormat("%.2f");
    axisYPChg->setLabelsFont(this->font());

    mTendencyPChgChart->setAxisX(axisXPChg, mTendencyPChgSeries);
    mTendencyPChgChart->setAxisY(axisYPChg, mTendencyPChgSeries);

    count = 1;
    points.clear();
    tmpLst.clear();
    for (int i = size - 1; i >= 0; --i)
    {
        tmpLst.append(dataLst.at(i).Voturnover);
        points.append(QPointF(count++, dataLst.at(i).Voturnover));
    }

    mTendencyVoturnoverSeries->replace(points);

    QValueAxis *axisXVoturnover = new QValueAxis;
    axisXVoturnover->setRange(1, size);
    axisXVoturnover->setLabelFormat("%d");
    axisXVoturnover->setLabelsFont(this->font());
    axisXVoturnover->setVisible(false);

    qSort(tmpLst.begin(), tmpLst.end());
    QValueAxis *axisYVoturnover = new QValueAxis;
    axisYVoturnover->setRange(tmpLst.first(), tmpLst.last());
    axisYVoturnover->setLabelFormat("%d");
    axisYVoturnover->setLabelsFont(this->font());

    mTendencyVoturnoverChart->setAxisX(axisXVoturnover, mTendencyVoturnoverSeries);
    mTendencyVoturnoverChart->setAxisY(axisYVoturnover, mTendencyVoturnoverSeries);

    count = 1;
    points.clear();
    tmpLst.clear();
    for (int i = size - 1; i >= 0; --i)
    {
        tmpLst.append(dataLst.at(i).Turnover);
        points.append(QPointF(count++, dataLst.at(i).Turnover));
    }

    mTendencyTurnoverSeries->replace(points);

    QValueAxis *axisXTurnover = new QValueAxis;
    axisXTurnover->setRange(1, size);
    axisXTurnover->setLabelFormat("%d");
    axisXTurnover->setLabelsFont(this->font());
    axisXTurnover->setVisible(false);

    qSort(tmpLst.begin(), tmpLst.end());
    QValueAxis *axisYTurnover = new QValueAxis;
    axisYTurnover->setRange(tmpLst.first(), tmpLst.last());
    axisYTurnover->setLabelFormat("%.2f");
    axisYTurnover->setLabelsFont(this->font());

    mTendencyTurnoverChart->setAxisX(axisXTurnover, mTendencyTurnoverSeries);
    mTendencyTurnoverChart->setAxisY(axisYTurnover, mTendencyTurnoverSeries);
}

void MainWindow::on_pushButton_klineform_clicked()
{
    QString klineForm = ui->comboBox_klineform->currentText();

    if (klineForm == "----------")
    {
        return;
    }

    QString date = ui->dateEdit_end->date().toString("yyyy-MM-dd");
    getAllStockByDate(date);
    QList<StockData> dataLst = mAllStockMap.value(date);

    QList<StockData> retLst;

    if (klineForm == QStringLiteral("一字涨停"))
    {
        for (int i = 0; i < dataLst.size(); ++i)
        {
            StockData data = dataLst.at(i);
            double pchg = data.PChg;
            double high = data.High;
            double low = data.Low;

            if ((pchg >= 9.90) && (high == low))
            {
                retLst.append(data);
            }
        }
    }
    else if (klineForm == QStringLiteral("跳空涨停"))
    {
        if (mTKZTMap.contains(date))
        {
            retLst = mTKZTMap.value(date);
        }
        else
        {
            ui->pushButton_klineform->setEnabled(false);
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

            QList<StockData> prevLst;
            for (int i = 0; i < dataLst.size(); ++i)
            {
                StockData data = dataLst.at(i);
                double pchg = data.PChg;
                double low = data.Low;

                if (pchg >= 9.90)
                {
                    prevLst = selectStockDataPrev(data.Code, data.Name, date);
                    double high = prevLst.first().High;

                    if (low > high)
                    {
                        retLst.append(data);
                    }
                }
            }

            mTKZTMap.insert(date, retLst);

            ui->pushButton_klineform->setEnabled(true);
        }
    }
    else if (klineForm == QStringLiteral("放量涨停"))
    {
        if (mFLZTMap.contains(date))
        {
            retLst = mFLZTMap.value(date);
        }
        else
        {
            ui->pushButton_klineform->setEnabled(false);
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

            QList<StockData> prevLst;
            for (int i = 0; i < dataLst.size(); ++i)
            {
                StockData data = dataLst.at(i);
                double pchg = data.PChg;
                int voturnover = data.Voturnover;

                if (pchg >= 9.90)
                {
                    prevLst = selectStockDataPrev(data.Code, data.Name, date);
                    int voturnover2 = prevLst.first().Voturnover;

                    if (voturnover >= (voturnover2 * 1.5))
                    {
                        retLst.append(data);
                    }
                }
            }

            mFLZTMap.insert(date, retLst);

            ui->pushButton_klineform->setEnabled(true);
        }
    }
    else if (klineForm == QStringLiteral("缩量涨停"))
    {
        if (mSLZTMap.contains(date))
        {
            retLst = mSLZTMap.value(date);
        }
        else
        {
            ui->pushButton_klineform->setEnabled(false);
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

            QList<StockData> prevLst;
            for (int i = 0; i < dataLst.size(); ++i)
            {
                StockData data = dataLst.at(i);
                double pchg = data.PChg;
                int voturnover = data.Voturnover;

                if (pchg >= 9.90)
                {
                    prevLst = selectStockDataPrev(data.Code, data.Name, date);
                    int voturnover2 = prevLst.first().Voturnover;

                    if ((voturnover <= (voturnover2 * 0.5)) || (voturnover <= voturnover2))
                    {
                        retLst.append(data);
                    }
                }
            }

            mSLZTMap.insert(date, retLst);

            ui->pushButton_klineform->setEnabled(true);
        }
    }
    else if (klineForm == QStringLiteral("放量>=6%"))
    {
        if (mFL69Map.contains(date))
        {
            retLst = mFL69Map.value(date);
        }
        else
        {
            ui->pushButton_klineform->setEnabled(false);
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

            QList<StockData> prevLst;
            for (int i = 0; i < dataLst.size(); ++i)
            {
                StockData data = dataLst.at(i);
                double pchg = data.PChg;
                int voturnover = data.Voturnover;

                if (pchg >= 6.0 && pchg < 9.90)
                {
                    prevLst = selectStockDataPrev(data.Code, data.Name, date);
                    int voturnover2 = prevLst.first().Voturnover;

                    if (voturnover >= (voturnover2 * 1.5))
                    {
                        retLst.append(data);
                    }
                }
            }

            mFL69Map.insert(date, retLst);

            ui->pushButton_klineform->setEnabled(true);
        }
    }
    else if (klineForm == QStringLiteral("缩量>=6%"))
    {
        if (mSL69Map.contains(date))
        {
            retLst = mSL69Map.value(date);
        }
        else
        {
            ui->pushButton_klineform->setEnabled(false);
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

            QList<StockData> prevLst;
            for (int i = 0; i < dataLst.size(); ++i)
            {
                StockData data = dataLst.at(i);
                double pchg = data.PChg;
                int voturnover = data.Voturnover;

                if (pchg >= 6.0 && pchg < 9.90)
                {
                    prevLst = selectStockDataPrev(data.Code, data.Name, date);
                    int voturnover2 = prevLst.first().Voturnover;

                    if ((voturnover <= (voturnover2 * 0.5)) || (voturnover <= voturnover2))
                    {
                        retLst.append(data);
                    }
                }
            }

            mSL69Map.insert(date, retLst);

            ui->pushButton_klineform->setEnabled(true);
        }
    }
    else if (klineForm == QStringLiteral("MA240以上"))
    {
        if (mMA240UpMap.contains(date))
        {
            retLst = mMA240UpMap.value(date);
        }
        else
        {
            ui->pushButton_klineform->setEnabled(false);
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

            QList<StockData> prevLst;
            for (int i = 0; i < dataLst.size(); ++i)
            {
                StockData data = dataLst.at(i);
                double low = data.Low;
                double tclose240 = data.TClose;

                prevLst = selectStockDataPrev(data.Code, data.Name, date, 239);
                foreach (StockData data, prevLst)
                {
                    tclose240 += data.TClose;
                }

                double ma240 = QString::asprintf("%.2f", tclose240 / 240).toDouble();

                if (low > ma240)
                {
                    retLst.append(data);
                }
            }

            mMA240UpMap.insert(date, retLst);

            ui->pushButton_klineform->setEnabled(true);
        }
    }
    else if (klineForm == QStringLiteral("MA240"))
    {
        if (mMA240Map.contains(date))
        {
            retLst = mMA240Map.value(date);
        }
        else
        {
            ui->pushButton_klineform->setEnabled(false);
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

            QList<StockData> prevLst;
            for (int i = 0; i < dataLst.size(); ++i)
            {
                StockData data = dataLst.at(i);
                double high = data.High;
                double low = data.Low;
                double tclose240 = data.TClose;

                prevLst = selectStockDataPrev(data.Code, data.Name, date, 239);
                foreach (StockData data, prevLst)
                {
                    tclose240 += data.TClose;
                }

                double ma240 = QString::asprintf("%.2f", tclose240 / 240).toDouble();

                if ((ma240 >= low) && (ma240 <= high))
                {
                    retLst.append(data);
                }
            }

            mMA240Map.insert(date, retLst);

            ui->pushButton_klineform->setEnabled(true);
        }
    }
    else if (klineForm == QStringLiteral("MA240以下"))
    {
        if (mMA240DownMap.contains(date))
        {
            retLst = mMA240DownMap.value(date);
        }
        else
        {
            ui->pushButton_klineform->setEnabled(false);
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

            QList<StockData> prevLst;
            for (int i = 0; i < dataLst.size(); ++i)
            {
                StockData data = dataLst.at(i);
                double high = data.High;
                double tclose240 = data.TClose;

                prevLst = selectStockDataPrev(data.Code, data.Name, date, 239);
                foreach (StockData data, prevLst)
                {
                    tclose240 += data.TClose;
                }

                double ma240 = QString::asprintf("%.2f", tclose240 / 240).toDouble();

                if (high < ma240)
                {
                    retLst.append(data);
                }
            }

            mMA240DownMap.insert(date, retLst);

            ui->pushButton_klineform->setEnabled(true);
        }
    }
    else if (klineForm == QStringLiteral("成交量放大"))
    {
        if (mCJLFDMap.contains(date))
        {
            retLst = mCJLFDMap.value(date);
        }
        else
        {
            ui->pushButton_klineform->setEnabled(false);
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

            QList<StockData> prevLst;
            for (int i = 0; i < dataLst.size(); ++i)
            {
                StockData data = dataLst.at(i);
                int voturnover = data.Voturnover;

                prevLst = selectStockDataPrev(data.Code, data.Name, date);
                int voturnover2 = prevLst.first().Voturnover;

                if (voturnover >= (voturnover2 * 1.5))
                {
                    retLst.append(data);
                }
            }

            mCJLFDMap.insert(date, retLst);

            ui->pushButton_klineform->setEnabled(true);
        }
    }
    else if (klineForm == QStringLiteral("换手率增加"))
    {
        if (mHSLZJMap.contains(date))
        {
            retLst = mHSLZJMap.value(date);
        }
        else
        {
            ui->pushButton_klineform->setEnabled(false);
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

            QList<StockData> prevLst;
            for (int i = 0; i < dataLst.size(); ++i)
            {
                StockData data = dataLst.at(i);
                double turnover = data.Turnover;

                if (turnover >= 3.0)
                {
                    prevLst = selectStockDataPrev(data.Code, data.Name, date);
                    double turnover2 = prevLst.first().Turnover;

                    if (turnover >= (turnover2 * 2))
                    {
                        retLst.append(data);
                    }
                }
            }

            mHSLZJMap.insert(date, retLst);

            ui->pushButton_klineform->setEnabled(true);
        }
    }
    else if (klineForm == QStringLiteral("带量突破"))
    {
        if (mDLTPMap.contains(date))
        {
            retLst = mDLTPMap.value(date);
        }
        else
        {
            ui->pushButton_klineform->setEnabled(false);
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

            QList<StockData> prevLst;
            for (int i = 0; i < dataLst.size(); ++i)
            {
                StockData data = dataLst.at(i);
                double pchg = data.PChg;
                double turnover = data.Turnover;

                if ((turnover >= 3.0) && (pchg >= 6.0))
                {
                    prevLst = selectStockDataPrev(data.Code, data.Name, date);
                    double pchg2 = prevLst.first().PChg;

                    if (pchg2 <= 2.0)
                    {
                        retLst.append(data);
                    }
                }
            }

            mDLTPMap.insert(date, retLst);

            ui->pushButton_klineform->setEnabled(true);
        }
    }
    else if (klineForm == QStringLiteral("上升趋势"))
    {
        if (mSSQSMap.contains(date))
        {
            retLst = mSSQSMap.value(date);
        }
        else
        {
            ui->pushButton_klineform->setEnabled(false);
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

            QList<StockData> prevLst;
            for (int i = 0; i < dataLst.size(); ++i)
            {
                StockData data = dataLst.at(i);
                double tclose = data.TClose;

                if (data.isYangXian())
                {
                    prevLst = selectStockDataPrev(data.Code, data.Name, date, 4);
                    if (prevLst.size() == 4)
                    {
                        StockData data1 = prevLst.at(0);
                        StockData data2 = prevLst.at(1);
                        StockData data3 = prevLst.at(2);
                        StockData data4 = prevLst.at(3);

                        double tclose1 = data1.TClose;
                        double tclose2 = data2.TClose;
                        double tclose3 = data3.TClose;
                        double tclose4 = data4.TClose;

                        if (data1.isYangXian() && data2.isYangXian() && data3.isYangXian() && data4.isYangXian())
                        {
                            if ((tclose > tclose1) && (tclose1 > tclose2) && (tclose2 > tclose3) && (tclose3 > tclose4))
                            {
                                retLst.append(data);
                            }
                        }
                    }
                }
            }

            mSSQSMap.insert(date, retLst);

            ui->pushButton_klineform->setEnabled(true);
        }
    }
    else if (klineForm == QStringLiteral("均线多头"))
    {
        if (mMA5_10_20Map.contains(date))
        {
            retLst = mMA5_10_20Map.value(date);
        }
        else
        {
            ui->pushButton_klineform->setEnabled(false);
            qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

            QList<StockData> prevLst;
            for (int i = 0; i < dataLst.size(); ++i)
            {
                StockData data = dataLst.at(i);
                double tclose = data.TClose;
                double tclose5 = tclose;
                double tclose10 = tclose;
                double tclose20 = tclose;

                prevLst = selectStockDataPrev(data.Code, data.Name, date, 19);
                for (int i = 0; i < prevLst.size(); ++i)
                {
                    double tclose = prevLst.at(i).TClose;

                    if (i <= 3)
                    {
                        tclose5 += tclose;
                    }

                    if (i <= 8)
                    {
                        tclose10 += tclose;
                    }

                    if (i <= 18)
                    {
                        tclose20 += tclose;
                    }
                }

                double ma5 = QString::asprintf("%.2f", tclose5 / 5).toDouble();
                double ma10 = QString::asprintf("%.2f", tclose10 / 10).toDouble();
                double ma20 = QString::asprintf("%.2f", tclose20 / 20).toDouble();

                if ((ma5 >= ma10) && (ma5 >= ma20) && (ma10 >= ma20))
                {
                    retLst.append(data);
                }
            }

            mMA5_10_20Map.insert(date, retLst);

            ui->pushButton_klineform->setEnabled(true);
        }
    }

    QList<StockData> sortLst = sortStockDataLst(retLst);
    mScreeningStockDataLst = sortLst;
    stockDataTable(ui->tableWidget_screening, sortLst);
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值