From 5ce2cd53b99531ff4074defc977537fe11a75530 Mon Sep 17 00:00:00 2001 From: fekt Date: Sat, 13 Apr 2024 19:11:58 -0400 Subject: [PATCH] Market data/charts --- README.md | 2 +- silentdragon.pro | 1 + silentdragonx.pro | 1 + src/mainwindow.cpp | 12 +++ src/mainwindow.h | 5 +- src/mainwindow.ui | 222 ++++++++++++++++++++++++++------------------- src/rpc.cpp | 220 +++++++++++++++++++++++++++++++++++++++++++- src/rpc.h | 1 + 8 files changed, 370 insertions(+), 94 deletions(-) diff --git a/README.md b/README.md index a26a45d..1d90951 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ sudo apt-get -y install libglu1-mesa-dev freeglut3-dev mesa-common-dev You can install the pre-reqs and build on Ubuntu 18.04 & 20.04 with: ```shell script -sudo apt-get -y install qt5-default qt5-qmake qtcreator +sudo apt-get -y install qt5-default qt5-qmake qtcreator libqt5charts5-dev git clone https://git.hush.is/hush/SilentDragon cd SilentDragon ./build.sh linguist diff --git a/silentdragon.pro b/silentdragon.pro index 74eaede..a5a1fa6 100644 --- a/silentdragon.pro +++ b/silentdragon.pro @@ -9,6 +9,7 @@ CONFIG += precompile_header PRECOMPILED_HEADER = src/precompiled.h QT += widgets +QT += charts TARGET = silentdragon diff --git a/silentdragonx.pro b/silentdragonx.pro index 18cfe00..bd6efa8 100644 --- a/silentdragonx.pro +++ b/silentdragonx.pro @@ -8,6 +8,7 @@ CONFIG += precompile_header PRECOMPILED_HEADER = src/precompiled.h QT += widgets +QT += charts TARGET = silentdragonx diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 1af8cc4..66ab62b 100755 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -25,6 +25,7 @@ #include "requestdialog.h" #include #include +#include #include "sd.h" extern bool isdragonx; @@ -2247,6 +2248,10 @@ void MainWindow::setupMarketTab() { ui->volume->setText(QString::number((double) s->get_volume("HUSH") ,'f',8) + " HUSH"); ui->volumeLocal->setText(QString::number((double) s->get_volume(ticker) ,'f',8) + " " + ticker); ui->volumeBTC->setText(QString::number((double) s->get_volume("BTC") ,'f',8) + " BTC"); + + ui->chartType->addItem("Price"); + ui->chartType->addItem("Volume"); + //ui->chartType->addItem("Marketcap"); } void MainWindow::setupTransactionsTab() { @@ -2848,3 +2853,10 @@ MainWindow::~MainWindow() delete logger; } + +void MainWindow::on_chartType_currentTextChanged(const QString &chartType) +{ + qDebug() << "chartType = " << chartType; + rpc->getMarketChart(chartType); +} + diff --git a/src/mainwindow.h b/src/mainwindow.h index f4eaf05..1b283e4 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -81,7 +81,10 @@ protected slots: // this slot is called by the language menu actions void slotLanguageChanged(QString lang); -private: +private slots: + void on_chartType_currentTextChanged(const QString &chartType); + +private: void closeEvent(QCloseEvent* event); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 899abc5..f45acf6 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -14,7 +14,7 @@ SilentDragon - + :/icons/icon.ico:/icons/icon.ico @@ -22,7 +22,7 @@ - 0 + 5 @@ -388,8 +388,8 @@ 0 0 - 1447 - 860 + 1439 + 899 @@ -1053,145 +1053,181 @@ Market - - - - - 15 - - + + - <html><head/><body><p align="center"><span style=" font-weight:600;">Market Information</span></p></body></html> - - - - - - - Qt::Horizontal + Loading... - + Market Cap - - + + Loading... - + - - + + Loading... - - + + - 24H Volume + Loading... - - - - Loading... + + + + Qt::Horizontal - - + + - Loading... + 24H Volume - + Loading... + + + + false + + + + + + + + + + + + 192 + 191 + 188 + + + + + + + + + 192 + 191 + 188 + + + + + + + + + 192 + 191 + 188 + + + + + + + + + + + Select chart to display + + + - Debug Log - - - - - - - true - - - - 0 - 0 - - - - - 0 - 0 - - - - Click to see the latest debug log data - - - - Refresh - - - + + + + + true + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + Refresh + + + - - - Number of lines to show - - + + + Number of lines to show + + - - - true - - - 50 - - + + + true + + + 50 + + + + + + + + + - - - - - - - - - Node info @@ -1664,14 +1700,13 @@ - 0 0 1487 - 30 + 22 @@ -1838,6 +1873,11 @@ QLabel
qrcodelabel.h
+ + QChartView + QGraphicsView +
QtCharts
+
inputsCombo @@ -1863,7 +1903,7 @@ sendToScrollArea - + diff --git a/src/rpc.cpp b/src/rpc.cpp index 1c648c7..e0b6080 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -1574,12 +1574,15 @@ void RPC::refreshPrice() { return noConnection(); QString price_feed; + QString history_feed; - // TODO: Make price_feed dynamic to support HACs + // TODO: Make feeds dynamic to support HACs if (isdragonx) { price_feed = "https://api.coingecko.com/api/v3/simple/price?ids=dragonx-2&vs_currencies=btc%2Cusd%2Ceur%2Ceth%2Cgbp%2Ccny%2Cjpy%2Cidr%2Crub%2Ccad%2Csgd%2Cchf%2Cinr%2Caud%2Cinr%2Ckrw%2Cthb%2Cnzd%2Czar%2Cvef%2Cxau%2Cxag%2Cvnd%2Csar%2Ctwd%2Caed%2Cars%2Cbdt%2Cbhd%2Cbmd%2Cbrl%2Cclp%2Cczk%2Cdkk%2Chuf%2Cils%2Ckwd%2Clkr%2Cpkr%2Cnok%2Ctry%2Csek%2Cmxn%2Cuah%2Chkd&include_market_cap=true&include_24hr_vol=true&include_24hr_change=true"; + history_feed = "https://api.coingecko.com/api/v3/coins/dragonx-2/market_chart?vs_currency=usd&days=90&precision=full"; } else { price_feed = "https://api.coingecko.com/api/v3/simple/price?ids=hush&vs_currencies=btc%2Cusd%2Ceur%2Ceth%2Cgbp%2Ccny%2Cjpy%2Cidr%2Crub%2Ccad%2Csgd%2Cchf%2Cinr%2Caud%2Cinr%2Ckrw%2Cthb%2Cnzd%2Czar%2Cvef%2Cxau%2Cxag%2Cvnd%2Csar%2Ctwd%2Caed%2Cars%2Cbdt%2Cbhd%2Cbmd%2Cbrl%2Cclp%2Cczk%2Cdkk%2Chuf%2Cils%2Ckwd%2Clkr%2Cpkr%2Cnok%2Ctry%2Csek%2Cmxn%2Cuah%2Chkd&include_market_cap=true&include_24hr_vol=true&include_24hr_change=true"; + history_feed = "https://api.coingecko.com/api/v3/coins/hush/market_chart?vs_currency=usd&days=90&precision=full"; } auto s = Settings::getInstance(); @@ -1713,6 +1716,221 @@ void RPC::refreshPrice() { Settings::getInstance()->setHUSHPrice(0); Settings::getInstance()->setBTCPrice(0); }); + + getMarketChart("Price"); +} + +// Get price history chart +void RPC::getMarketChart(QString chartType) { + if (conn == nullptr) + return noConnection(); + + QString history_feed; + + // TODO: Make feeds dynamic to support HACs + if (isdragonx) { + history_feed = "https://api.coingecko.com/api/v3/coins/dragonx-2/market_chart?vs_currency=usd&days=7"; + } else { + history_feed = "https://api.coingecko.com/api/v3/coins/hush/market_chart?vs_currency=usd&days=7"; + } + + auto s = Settings::getInstance(); + + if (s->getAllowFetchPrices() == false) { + qDebug() << "Price fetching disabled"; + return; + } + + qDebug() << "Requesting history feed data via " << history_feed; + + QUrl histURL(history_feed); + QNetworkRequest req; + req.setUrl(histURL); + QNetworkReply *reply = conn->restclient->get(req); + + QObject::connect(reply, &QNetworkReply::finished, [=] { + reply->deleteLater(); + + try { + + QByteArray ba_raw_reply = reply->readAll(); + QString raw_reply = QString::fromUtf8(ba_raw_reply); + QByteArray unescaped_raw_reply = raw_reply.toUtf8(); + QJsonDocument jd_reply = QJsonDocument::fromJson(unescaped_raw_reply); + QJsonObject parsed = jd_reply.object(); + + QJsonArray prices = parsed["prices"].toArray(); + QJsonArray volumes = parsed["total_volumes"].toArray(); + QJsonArray mcaps = parsed["market_caps"].toArray(); + + if (prices.size()>0 && volumes.size()>0) { + + // Create Price Series + QLineSeries *priceSeries = new QLineSeries(); + + // Loop through price data and add to series + for (int i = 0; i < prices.size(); i++){ + + // QJson doesn't support long ints so we convert - https://bugreports.qt.io/browse/QTBUG-28560 + quint64 timestamp = QString("%1").arg(prices.at(i).toArray().at(0).toDouble(),0,'f',0).toLongLong(); + auto price = prices.at(i).toArray().at(1).toDouble(); + + qDebug() << "Epoch = " << timestamp; + qDebug() << "Price = " << price; + + priceSeries->append(timestamp, price); + } + + // Set color of price series + priceSeries->setColor(Qt::green); + + // Create Price chart + QChart *priceChart = new QChart(); + priceChart->setTitleBrush(QBrush(Qt::darkGray)); + + priceChart->addSeries(priceSeries); + priceChart->setTitle("Price History"); + priceChart->setBackgroundVisible(false); + priceChart->legend()->hide(); + + auto priceaxisX = new QDateTimeAxis; + priceaxisX->setTickCount(7); + priceaxisX->setFormat("yyyy-MM-dd"); + priceaxisX->setLabelsColor(Qt::lightGray); + priceaxisX->setGridLineColor(Qt::darkGray); + priceaxisX->setTitleText("Date"); + priceChart->addAxis(priceaxisX, Qt::AlignBottom); + priceSeries->attachAxis(priceaxisX); + + auto priceaxisY = new QValueAxis; + priceaxisY->setTickCount(10); + priceaxisY->setLabelsColor(Qt::lightGray); + priceaxisY->setGridLineColor(Qt::darkGray); + priceaxisY->setTitleText("USD Price"); + priceChart->addAxis(priceaxisY, Qt::AlignLeft); + priceSeries->attachAxis(priceaxisY); + + + // Create Volume Series + QLineSeries *volumeSeries = new QLineSeries(); + + // Loop through price data and add to series + for (int i = 0; i < volumes.size(); i++){ + + // QJson doesn't support long ints so we convert - https://bugreports.qt.io/browse/QTBUG-28560 + quint64 timestamp = QString("%1").arg(volumes.at(i).toArray().at(0).toDouble(),0,'f',0).toLongLong(); + auto volume = volumes.at(i).toArray().at(1).toDouble(); + + qDebug() << "Epoch = " << timestamp; + qDebug() << "Volume = " << volume; + + volumeSeries->append(timestamp, volume); + } + + // Set color of Volume series + volumeSeries->setColor(Qt::green); + + // Create Volume chart + QChart *volumeChart = new QChart(); + volumeChart->setTitleBrush(QBrush(Qt::darkGray)); + + volumeChart->addSeries(volumeSeries); + volumeChart->setTitle("Volume History"); + volumeChart->setBackgroundVisible(false); + volumeChart->legend()->hide(); + + auto volumeaxisX = new QDateTimeAxis; + volumeaxisX->setTickCount(7); + volumeaxisX->setFormat("yyyy-MM-dd"); + volumeaxisX->setLabelsColor(Qt::lightGray); + volumeaxisX->setGridLineColor(Qt::darkGray); + volumeaxisX->setTitleText("Date"); + volumeChart->addAxis(volumeaxisX, Qt::AlignBottom); + volumeSeries->attachAxis(volumeaxisX); + + auto volumeaxisY = new QValueAxis; + volumeaxisY->setTickCount(10); + volumeaxisY->setLabelsColor(Qt::lightGray); + volumeaxisY->setGridLineColor(Qt::darkGray); + volumeaxisY->setTitleText("DRGX"); + volumeChart->addAxis(volumeaxisY, Qt::AlignLeft); + volumeSeries->attachAxis(volumeaxisY); + + + // Create Market Cap Series + QLineSeries *mcapSeries = new QLineSeries(); + + // Loop through price data and add to series + for (int i = 0; i < mcaps.size(); i++){ + + // QJson doesn't support long ints so we convert - https://bugreports.qt.io/browse/QTBUG-28560 + quint64 timestamp = QString("%1").arg(mcaps.at(i).toArray().at(0).toDouble(),0,'f',0).toLongLong(); + auto mcap = mcaps.at(i).toArray().at(1).toDouble(); + + qDebug() << "Epoch = " << timestamp; + qDebug() << "Mcap = " << mcap; + + mcapSeries->append(timestamp, mcap); + } + + // Set color of Market Cap series + mcapSeries->setColor(Qt::green); + + // Create Market Cap chart + QChart *mcapChart = new QChart(); + mcapChart->setTitleBrush(QBrush(Qt::darkGray)); + + mcapChart->addSeries(mcapSeries); + mcapChart->setTitle("Market Cap History"); + mcapChart->setBackgroundVisible(false); + mcapChart->legend()->hide(); + + auto mcapaxisX = new QDateTimeAxis; + mcapaxisX->setTickCount(7); + mcapaxisX->setFormat("yyyy-MM-dd"); + mcapaxisX->setLabelsColor(Qt::lightGray); + mcapaxisX->setGridLineColor(Qt::darkGray); + mcapaxisX->setTitleText("Date"); + mcapChart->addAxis(mcapaxisX, Qt::AlignBottom); + mcapSeries->attachAxis(mcapaxisX); + + auto mcapaxisY = new QValueAxis; + mcapaxisY->setTickCount(10); + mcapaxisY->setLabelsColor(Qt::lightGray); + mcapaxisY->setGridLineColor(Qt::darkGray); + mcapaxisY->setTitleText("DRGX"); + mcapChart->addAxis(mcapaxisY, Qt::AlignLeft); + mcapSeries->attachAxis(mcapaxisY); + + + // Add chart to UI + qDebug() << "chartType = " << chartType; + + if(chartType=="Price") { + ui->marketChart->setChart(priceChart); + } else if(chartType=="Volume") { + ui->marketChart->setChart(volumeChart); + } else if(chartType=="Marketcap") { + ui->marketChart->setChart(mcapChart); + } else{ + ui->marketChart->setChart(priceChart); + } + + // Set anti-aliasing + ui->marketChart->setRenderHint(QPainter::Antialiasing, true); + + return; + } else { + qDebug() << "No market_chart history returned. API might be down or we are rate-limited"; + + QMessageBox msgBox; + msgBox.setText("No market data returned. API is down or rate limited. Try again after a minute."); + msgBox.exec(); + } + } catch (const std::exception& e) { + qDebug() << QString("History feed update failure"); + } + }); } void RPC::shutdownHushd() { diff --git a/src/rpc.h b/src/rpc.h index c83de80..46e1ba6 100755 --- a/src/rpc.h +++ b/src/rpc.h @@ -76,6 +76,7 @@ public: void checkForUpdate(bool silent = true); void refreshPrice(); + void getMarketChart(QString chartType); void executeTransaction(Tx tx, const std::function submitted,