Comparison and display of stock historical trends

        This article summarizes a sub-project of a stock analysis software that I participated in before (only part of the code is placed). The project is implemented with QT, and the stock historical data is stored in an excel file.

        The goal of the subproject is to find a time period similar to the recent stock data based on the provided stock historical data, and to predict the trend based on the historical data. Key features include:

  • (1) Display of stock data in any time period
  • (2) Search for similar historical data
  • (3) Prediction of the future trend of stocks
  • (4) Update stock data
  • (5) Import/store corresponding data

The following is a conceptual summary of the above functions:

  • Display of stock data

Use candle charts to display stock data, including current stock prices, trading volume, trends, etc., as shown in the following figure:

    /**************Price Chart (Candle Chart)******************/

    //data link

    QCandlestickSeries *acmeSeries = new QCandlestickSeries();

    acmeSeries->setName( name );

    acmeSeries->setIncreasingColor(QColor(Qt::red));

    acmeSeries->setDecreasingColor(QColor(Qt::green));

    //acmeSeries->setBodyOutlineVisible(false);

    //acmeSeries->setBodyWidth(0.01);

    //Information displayed on the horizontal axis

    QStringList categories;

    for( i=0;i<stock_chart->date.size();i++ )

        categories.append( stock_chart->date.at(i) );

    //Add the data of the last trading days

    add_chart_set( stock_chart,acmeSeries );

    //Create Chart

    QChart *chart = new QChart();

    chart->addSeries(acmeSeries);

    //chart->setTitle( name );

    chart->setAnimationOptions(QChart::SeriesAnimations);

    chart->createDefaultAxes();

    QBarCategoryAxis *axisX = qobject_cast<QBarCategoryAxis *>(chart->axes(Qt::Horizontal).at(0));

    axisX->setCategories(categories);

    axisX->setLabelsAngle( 90 );

    axisX->setLabelsFont( QFont("Times",7) );

    QValueAxis *axisY = qobject_cast<QValueAxis *>(chart->axes(Qt::Vertical).at(0));

    axisY->setMax(axisY->max() * 1.01);

    axisY->setMin(axisY->min() * 0.99);

    chart->legend()->setVisible(false);

    //chart->legend()->setAlignment(Qt::AlignBottom);

    stock_chart->chart_view->setChart( chart );

    /**************Price Chart (Candle Chart)******************/

    /**************Trading Volume Chart******************/

    QBarSet *set0 = new QBarSet("Jane");

    for( i=0;i<stock_chart->date.size();i++ )

        *set0 << stock_chart->volumes.at(i).toDouble()/100000;

    QBarSeries *series = new QBarSeries();

    series->append(set0);

    QChart *chart2 = new QChart();

    chart2->addSeries(series);

    //chart2->setTitle("Simple barchart example");

    chart2->setAnimationOptions(QChart::SeriesAnimations);

    chart2->createDefaultAxes();

    QBarCategoryAxis *axisX2 = qobject_cast<QBarCategoryAxis *>(chart2->axes(Qt::Horizontal).at(0));

    axisX2->setCategories(categories);

    axisX2->setLabelsAngle( 90 );

    axisX2->setLabelsFont( QFont("Times",7) );

    axisX2->setLabelsVisible(false);

    QValueAxis *axisY2 = qobject_cast<QValueAxis *>(chart2->axes(Qt::Vertical).at(0));

    axisY2->setMax(axisY2->max() * 1.01);

    axisY2->setMin(axisY2->min() * 0.99);

    //axisY2->setLabelsVisible(false);

    chart2->legend()->setVisible(false);

    //chart2->legend()->setAlignment(Qt::AlignBottom);

    stock_chart->chart_volume->setChart( chart2 );

 /**************Trading Volume Chart******************/

(2) Search for similar historical data

Because searching historical data is a time-consuming operation, it is necessary to create a sub-thread dedicated to searching and connect control signals, such as start and end, etc. When the data that meets the conditions is found, the search_resul signal is generated and sent to the main thread. Process in thread:

    /******************Create a child thread******************/

    child_thread  = new QThread();

    child_process = new ProcessObject();

    child_process->moveToThread( child_thread );

    connect( child_thread,SIGNAL(finished()),child_process,SLOT(deleteLater()) );

    connect( child_thread,SIGNAL(finished()),child_thread,SLOT(deleteLater()) );

    connect( this,SIGNAL(start_search(QString,MultString,ListDouble,bool)),

             child_process,SLOT(reply_start_search(QString,MultString,ListDouble,bool)) );

    connect( child_process,SIGNAL(search_result(QString,ListInt,ListDouble)),

             this,SLOT(reply_search_result(QString,ListInt,ListDouble)) );

    connect( this,SIGNAL(stop_search()),child_process ,SLOT(reply_stop_search()) );

child_thread->start();

The search algorithm uses a similarity algorithm. The algorithm itself is not difficult. The main problem is how to use the data.

double similarity(QList<double> data1,QList<double> data2)

{

    if( data1.isEmpty() || data2.isEmpty() )

        return 0;

    if( data1.size() != data2.size() )

        return 0;

    if( data1.size() < 1  )

        return 0;

    int i;

    int _size = data1.size();

    double r1,r2,r3,avg1,avg2,var1,var2;

    r1 = r2 = var1 = var2 = 0;

    //average value

    for( i=0;i<_size;i++ )

    {

        r1 += data1[i];

        r2 += data2[i];

    }

    avg1 = r1/_size;

    avg2 = r2/_size;

    //variance

    r1 = r2 = 0;

    for( i=0;i<_size;i++ )

    {  

        r1 += ( data1[i] - avg1 )*( data1[i] - avg1 );

        r2 += ( data2[i] - avg2 )*( data2[i] - avg2 );

    }

    var1 = 1/sqrt( r1/(_size -1) );

    var2 = 1/sqrt( r2/(_size -1) );

    //data normalization

    QList<double> std_data1,std_data2;

    std_data1.clear();

    std_data2.clear();

    for( i=0;i<_size;i++ )

    {

        std_data1.append ( ( data1[i] - avg1)*var1 );

        std_data2.append ( ( data2[i] - avg2)*var2 );

    }

    //Calculate correlation, consine

    r1 = r2 = r3 = 0;

    for( i=0;i<_size;i++ )

    {

        r1 = r1 + std_data1[i]*std_data2[i];

        r2 = r2 + std_data1[i]*std_data1[i];

        r3 = r3 + std_data2[i]*std_data2[i];

    }

    return (r1/sqrt(r2*r3));

}

The figure below is the interface for searching stock data. The result of the search includes the start position, end time (subscript in excel), similarity, and the similarity can be adjusted by yourself:

(3) Prediction of the future trend of stocks

            The future trend forecast is calculated based on the time period found in the historical data. Because the historical data has already obtained the trend data, the forecast is relatively simple. The picture below is the forecast picture. Red indicates the predicted data, and green indicates the actual The data (because the data is not updated, the actual data is not displayed):

(4) Update stock data

            Click the update button on the interface to update the stock data. Obtain stock data on Sina.com, and it can be automatically updated once after 15:00. The network part uses QNetworkManager to send a request.

    //Get the name, for example, 003300.xls, the obtained is 003300
        QString _name = stock_names.takeFirst();
        _name = _name.split('.').at(0).trimmed();
        if (_name.split('.').isEmpty())
            return;
 
 
        //Construct URL, note: changing datalen can get more time data
        //100 is equivalent to getting half a year's data, temporarily take 50 here
        //完整的:QString url = "http://money.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_MarketData.getKLineData?symbol=sh000001&scale=240&ma=no&datalen=100";
 
 
        QString url = "http://money.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_MarketData.getKLineData?symbol=";
        if( _name.at(0)=='0' )//Start with 0, Shenzhen Stock Exchange
            url = url + "sz";
        else //Other cases should start with 6, Shanghai Stock Exchange
            url = url + "sh";
 
 
        url = url + _name;
        url = url + "&scale=240&ma=no&datalen=50";
 
 
        //Send a network request (update the first stock, refer to reply_network_finished() for updates of other stocks
        QNetworkRequest request;
        request.setUrl( QUrl(url) );
        QNetworkReply *reply = network_manager->get(request);
        connect( reply,SIGNAL( finished() ),this,SLOT( reply_network_finished() ) );
(5) Data storage
Data is stored in json files. The storage content includes the found data, predicted data, etc.
    //The time corresponding to the source data
    QJsonArray _src_days;
    for (i = 0;i < info.src_day.size();i ++)
        _src_days.append(info.src_day.at(i));
    jsobject.insert("src_day",QJsonValue(_src_days));
     //The stock price corresponding to the source data
    QJsonArray _src_prices;
    for (i = 0;i < info.src_price.size();i ++)
        _src_prices.append(info.src_price.at(i));
    jsobject.insert("src_price",QJsonValue(_src_prices));
 
 
    //The time corresponding to the target data
    QJsonArray _dst_days;
    for (i = 0;i < info.dst_day.size();i ++)
        _dst_days.append(info.dst_day.at(i));
    jsobject.insert("dst_day",QJsonValue(_dst_days));
    //The stock price corresponding to the target data
    QJsonArray _dst_prices;
    for (i = 0;i < info.dst_price.size();i ++)
        _dst_prices.append(info.dst_price.at(i));
    jsobject.insert("dst_price",QJsonValue(_dst_prices));
 
 

Guess you like

Origin blog.csdn.net/hulinhulin/article/details/121522799