1 // This file is part of Qt Bitcoin Trader
2 // https://github.com/JulyIGHOR/QtBitcoinTrader
3 // Copyright (C) 2013-2021 July Ighor <julyighor@gmail.com>
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // In addition, as a special exception, the copyright holders give
11 // permission to link the code of portions of this program with the
12 // OpenSSL library under certain conditions as described in each
13 // individual source file, and distribute linked combinations including
14 // the two.
15 //
16 // You must obey the GNU General Public License in all respects for all
17 // of the code used other than OpenSSL. If you modify file(s) with this
18 // exception, you may extend this exception to your version of the
19 // file(s), but you are not obligated to do so. If you do not wish to do
20 // so, delete this exception statement from your version. If you delete
21 // this exception statement from all source files in the program, then
22 // also delete it here.
23 //
24 // This program is distributed in the hope that it will be useful,
25 // but WITHOUT ANY WARRANTY; without even the implied warranty of
26 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 // GNU General Public License for more details.
28 //
29 // You should have received a copy of the GNU General Public License
30 // along with this program. If not, see <http://www.gnu.org/licenses/>.
31
32 #include "julyspinboxpicker.h"
33 #include <QTableWidget>
34 #include <QTimeLine>
35 #include <QScrollBar>
36 #include <QDir>
37 #include <QMessageBox>
38 #include <QSettings>
39 #include "main.h"
40 #include "timesync.h"
41 #include "julylightchanges.h"
42 #include "julyspinboxfix.h"
43 #include "julyscrolluponidle.h"
44 #include <QFileInfo>
45 #include <QClipboard>
46 #include <QProcess>
47 #include <QFile>
48 #include <QSysInfo>
49 #include <QProcess>
50 #include <QDesktopWidget>
51 #include <QDesktopServices>
52 #include <QUrl>
53 #include <QDockWidget>
54 #include "script/addscriptwindow.h"
55 #include "aboutdialog.h"
56 #include "exchange/exchange.h"
57 #include "exchange/exchange_bitstamp.h"
58 #include "exchange/exchange_bitfinex.h"
59 #include "exchange/exchange_indacoin.h"
60 #include "exchange/exchange_yobit.h"
61 #include "exchange/exchange_binance.h"
62 #include "exchange/exchange_bittrex.h"
63 #include "exchange/exchange_hitbtc.h"
64 #include "exchange/exchange_poloniex.h"
65 #include <QSystemTrayIcon>
66 #include <QtCore/qmath.h>
67 #include "script/addrulegroup.h"
68 #include "percentpicker.h"
69 #include "logobutton.h"
70 #include "script/scriptwidget.h"
71 #include "thisfeatureunderdevelopment.h"
72 #include "orderstablecancelbutton.h"
73 #include "script/rulescriptparser.h"
74 #include "julymath.h"
75 #include "platform/sound.h"
76 #include "dock/dock_host.h"
77 #include "config/config_manager.h"
78 #include "config/config_manager_dialog.h"
79 #include "utils/utils.h"
80 #include "settings/settingsdialog.h"
81 #include "indicatorengine.h"
82 #include "charts/chartsmodel.h"
83 #include "charts/chartsview.h"
84 #include "news/newsview.h"
85 #include "menu/networkmenu.h"
86 #include "menu/currencymenu.h"
87 #include "utils/currencysignloader.h"
88 #include "utils/traderspinbox.h"
89 #include "iniengine.h"
90 #include <QScreen>
91
92 #ifdef Q_OS_WIN
93 #ifdef SAPI_ENABLED
94 #include <windows.h>
95 #include <sapi.h>
96 #endif
97
98 #include "windows.h"
99 #endif
100
101 #include <QStyleFactory>
102
103 #ifdef Q_OS_MAC
104 #include <ApplicationServices/ApplicationServices.h>
105 #endif
106
107 static const int ContentMargin = 4;
108
QtBitcoinTrader()109 QtBitcoinTrader::QtBitcoinTrader() :
110 QMainWindow(),
111 feeCalculator(nullptr),
112 meridianPrice(0.0),
113 availableAmount(0.0),
114 exchangeId(-1),
115 floatFee(0.0),
116 floatFeeDec(1.0),
117 floatFeeInc(1.0),
118 ordersModel(nullptr),
119 currencyChangedDate(0),
120 iniSettings(new QSettings(baseValues.iniFileName, QSettings::IniFormat, this)),
121 isValidSoftLag(false),
122 confirmOpenOrder(false),
123 lastRuleExecutedTime(QTime(1, 0, 0, 0)),
124 secondTimer(new QTimer),
125
126 windowWidget(this),
127 lastCopyTable(nullptr),
128 swapedDepth(false),
129 depthAsksModel(nullptr),
130 depthBidsModel(nullptr),
131 tradesModel(nullptr),
132 historyModel(nullptr),
133 isDataPending(false),
134 waitingDepthLag(false),
135 trayMenu(nullptr),
136 trayIcon(nullptr),
137 checkForUpdates(true),
138 lastLoadedCurrency(-1),
139 constructorFinished(false),
140 appDir(QApplication::applicationDirPath() + "/"),
141
142 showingMessage(false),
143 balanceNotLoaded(true),
144 marketPricesNotLoaded(true),
145 sellLockBtcToSell(false),
146 sellLockPricePerCoin(false),
147 sellLockAmountToReceive(false),
148 buyLockTotalBtc(false),
149 buyLockTotalBtcSelf(false),
150 buyLockPricePerCoin(false),
151 profitSellThanBuyUnlocked(true),
152 profitBuyThanSellUnlocked(true),
153 profitBuyThanSellChangedUnlocked(true),
154 profitSellThanBuyChangedUnlocked(true),
155 debugViewer(nullptr),
156 tradesPrecentLast(0.0),
157 currentPopupDialogs(0),
158 networkMenu(nullptr),
159 currencyMenu(nullptr),
160 currencySignLoader(new CurrencySignLoader),
161 lockedDocks(false),
162 actionExit(nullptr),
163 actionUpdate(nullptr),
164 actionSendBugReport(nullptr),
165 actionAbout(nullptr),
166 actionAboutQt(nullptr),
167 actionLockDocks(nullptr),
168 actionConfigManager(nullptr),
169 actionSettings(nullptr),
170 actionDebug(nullptr),
171 actionUninstall(nullptr),
172 menuFile(nullptr),
173 menuView(nullptr),
174 menuConfig(nullptr),
175 menuHelp(nullptr),
176 configDialog(nullptr),
177 dockHost(new DockHost(this)),
178 dockLogo(nullptr),
179 dockDepth(nullptr),
180 buyTotalSpend(new TraderSpinBox(this)),
181 buyPricePerCoin(new TraderSpinBox(this)),
182 buyTotalBtc(new TraderSpinBox(this)),
183 profitLossSpinBox(new TraderSpinBox(this)),
184 profitLossSpinBoxPrec(new TraderSpinBox(this)),
185 sellTotalBtc(new TraderSpinBox(this)),
186 sellPricePerCoin(new TraderSpinBox(this)),
187 sellAmountToReceive(new TraderSpinBox(this)),
188 sellThanBuySpinBox(new TraderSpinBox(this)),
189 sellThanBuySpinBoxPrec(new TraderSpinBox(this))
190 {
191 historyForceUpdate.start();
192 speedTestTime.start();
193 lastMessageTime.start();
194 depthLagTime.restart();
195 softLagTime.restart();
196
197 ui.setupUi(this);
198 setupWidgets();
199 fixAllCurrencyLabels(this);
200 setSpinValue(ui.accountFee, 0.0);
201 ui.accountLoginLabel->setStyleSheet("background: " + baseValues.appTheme.white.name());
202 ui.noOpenedOrdersLabel->setStyleSheet("font-size:27px; border: 1px solid gray; background: " +
203 baseValues.appTheme.white.name() + "; color: " + baseValues.appTheme.gray.name());
204 ui.rulesNoMessage->setStyleSheet("font-size:27px; border: 1px solid gray; background: " +
205 baseValues.appTheme.white.name() + "; color: " + baseValues.appTheme.gray.name());
206 ui.ordersTableFrame->setVisible(false);
207
208 currentlyAddingOrders = false;
209 ordersModel = new OrdersModel;
210 ordersSortModel = new QSortFilterProxyModel;
211 ordersSortModel->setSortRole(Qt::EditRole);
212 ordersSortModel->setFilterRole(Qt::WhatsThisRole);
213 ordersSortModel->setDynamicSortFilter(true);
214 ordersSortModel->setSourceModel(ordersModel);
215 ui.ordersTable->setModel(ordersSortModel);
216 setColumnResizeMode(ui.ordersTable, 0, QHeaderView::ResizeToContents);
217 setColumnResizeMode(ui.ordersTable, 1, QHeaderView::Stretch);
218 setColumnResizeMode(ui.ordersTable, 2, QHeaderView::ResizeToContents);
219 setColumnResizeMode(ui.ordersTable, 3, QHeaderView::ResizeToContents);
220 setColumnResizeMode(ui.ordersTable, 4, QHeaderView::ResizeToContents);
221 setColumnResizeMode(ui.ordersTable, 5, QHeaderView::ResizeToContents);
222 setColumnResizeMode(ui.ordersTable, 6, QHeaderView::ResizeToContents);
223 setColumnResizeMode(ui.ordersTable, 7, QHeaderView::ResizeToContents);
224 ui.ordersTable->setItemDelegateForColumn(7, new OrdersTableCancelButton(ui.ordersTable));
225
226 ui.ordersTable->setSortingEnabled(true);
227 ui.ordersTable->sortByColumn(0, Qt::AscendingOrder);
228
229 connect(ordersModel, &OrdersModel::ordersIsAvailable, this, &QtBitcoinTrader::ordersIsAvailable);
230 connect(ordersModel, &OrdersModel::cancelOrder, this, &QtBitcoinTrader::cancelOrder);
231 connect(ordersModel, &OrdersModel::volumeAmountChanged, this, &QtBitcoinTrader::volumeAmountChanged);
232 connect(ui.ordersTable->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this,
233 SLOT(checkValidOrdersButtons()));
234
235 tradesModel = new TradesModel;
236 ui.tableTrades->setModel(tradesModel);
237 setColumnResizeMode(ui.tableTrades, 0, QHeaderView::Stretch);
238 setColumnResizeMode(ui.tableTrades, 1, QHeaderView::ResizeToContents);
239 setColumnResizeMode(ui.tableTrades, 2, QHeaderView::ResizeToContents);
240 setColumnResizeMode(ui.tableTrades, 3, QHeaderView::ResizeToContents);
241 setColumnResizeMode(ui.tableTrades, 4, QHeaderView::ResizeToContents);
242 setColumnResizeMode(ui.tableTrades, 5, QHeaderView::ResizeToContents);
243 setColumnResizeMode(ui.tableTrades, 6, QHeaderView::ResizeToContents);
244 setColumnResizeMode(ui.tableTrades, 7, QHeaderView::Stretch);
245 connect(tradesModel, SIGNAL(trades10MinVolumeChanged(double)), this, SLOT(setLastTrades10MinVolume(double)));
246 connect(tradesModel, SIGNAL(precentBidsChanged(double)), this, SLOT(precentBidsChanged(double)));
247
248 historyModel = new HistoryModel;
249 ui.tableHistory->setModel(historyModel);
250 setColumnResizeMode(ui.tableHistory, 0, QHeaderView::Stretch);
251 setColumnResizeMode(ui.tableHistory, 1, QHeaderView::ResizeToContents);
252 setColumnResizeMode(ui.tableHistory, 2, QHeaderView::ResizeToContents);
253 setColumnResizeMode(ui.tableHistory, 3, QHeaderView::ResizeToContents);
254 setColumnResizeMode(ui.tableHistory, 4, QHeaderView::ResizeToContents);
255 setColumnResizeMode(ui.tableHistory, 5, QHeaderView::ResizeToContents);
256 setColumnResizeMode(ui.tableHistory, 6, QHeaderView::Stretch);
257 connect(historyModel, SIGNAL(accLastSellChanged(const QString&, double)), this, SLOT(accLastSellChanged(const QString&, double)));
258 connect(historyModel, SIGNAL(accLastBuyChanged(const QString&, double)), this, SLOT(accLastBuyChanged(const QString&, double)));
259
260
261 depthAsksModel = new DepthModel(ui.comboBoxGroupByPrice, true);
262 ui.depthAsksTable->setModel(depthAsksModel);
263 depthBidsModel = new DepthModel(ui.comboBoxGroupByPrice, false);
264 ui.depthBidsTable->setModel(depthBidsModel);
265
266 new JulyScrollUpOnIdle(ui.depthAsksTable->verticalScrollBar());
267 new JulyScrollUpOnIdle(ui.depthBidsTable->verticalScrollBar());
268
269 setColumnResizeMode(ui.depthAsksTable, 0, QHeaderView::Stretch);
270 setColumnResizeMode(ui.depthAsksTable, 1, QHeaderView::ResizeToContents);
271 setColumnResizeMode(ui.depthAsksTable, 2, QHeaderView::ResizeToContents);
272 setColumnResizeMode(ui.depthAsksTable, 3, QHeaderView::ResizeToContents);
273 setColumnResizeMode(ui.depthAsksTable, 4, QHeaderView::ResizeToContents);
274 ui.depthAsksTable->horizontalHeader()->setMinimumSectionSize(0);
275
276 setColumnResizeMode(ui.depthBidsTable, 0, QHeaderView::ResizeToContents);
277 setColumnResizeMode(ui.depthBidsTable, 1, QHeaderView::ResizeToContents);
278 setColumnResizeMode(ui.depthBidsTable, 2, QHeaderView::ResizeToContents);
279 setColumnResizeMode(ui.depthBidsTable, 3, QHeaderView::ResizeToContents);
280 setColumnResizeMode(ui.depthBidsTable, 4, QHeaderView::Stretch);
281 ui.depthBidsTable->horizontalHeader()->setMinimumSectionSize(0);
282
283 closeToTray = iniSettings->value("UI/CloseToTray", false).toBool();
284 #ifdef Q_OS_MAC
285 closeToTray = false;
286 #endif
287
288 confirmOpenOrder = iniSettings->value("UI/ConfirmOpenOrder", true).toBool();
289 iniSettings->setValue("UI/ConfirmOpenOrder", confirmOpenOrder);
290
291 checkValidOrdersButtons();
292
293 new JulyLightChanges(ui.accountFee);
294 new JulyLightChanges(ui.marketVolume);
295 new JulyLightChanges(ui.marketBid);
296 new JulyLightChanges(ui.marketAsk);
297 new JulyLightChanges(ui.marketHigh);
298 new JulyLightChanges(ui.marketLow);
299 new JulyLightChanges(ui.marketLast);
300 new JulyLightChanges(ui.accountBTC);
301 new JulyLightChanges(ui.accountUSD);
302 new JulyLightChanges(ui.ordersLastSellPrice);
303 new JulyLightChanges(ui.ordersLastBuyPrice);
304 new JulyLightChanges(ui.tradesVolume5m);
305
306 new JulyLightChanges(ui.ruleTotalToBuyValue);
307 new JulyLightChanges(ui.ruleAmountToReceiveValue);
308 new JulyLightChanges(ui.ruleTotalToBuyBSValue);
309 new JulyLightChanges(ui.ruleAmountToReceiveBSValue);
310 new JulyLightChanges(ui.tradesBidsPrecent);
311
312 baseValues.forceDotInSpinBoxes = iniSettings->value("UI/ForceDotInDouble", true).toBool();
313 iniSettings->setValue("UI/ForceDotInDouble", baseValues.forceDotInSpinBoxes);
314
315 ui.totalToSpendLayout->addWidget(new JulySpinBoxPicker(buyTotalSpend));
316 ui.pricePerCoinLayout->addWidget(new JulySpinBoxPicker(buyPricePerCoin));
317 ui.totalBtcToBuyLayout->addWidget(new JulySpinBoxPicker(buyTotalBtc));
318
319 ui.totalToSellLayout->addWidget(new JulySpinBoxPicker(sellTotalBtc));
320 ui.pricePerCoinSellLayout->addWidget(new JulySpinBoxPicker(sellPricePerCoin));
321 ui.amountToReceiveLayout->addWidget(new JulySpinBoxPicker(sellAmountToReceive));
322
323 ui.gssoProfitLayout->addWidget(new JulySpinBoxPicker(profitLossSpinBox));
324 ui.gssoProfitPercLayout->addWidget(new JulySpinBoxPicker(profitLossSpinBoxPrec));
325
326 ui.gssboProfitLayout->addWidget(new JulySpinBoxPicker(sellThanBuySpinBox));
327 ui.gsboProfitPercLayout->addWidget(new JulySpinBoxPicker(sellThanBuySpinBoxPrec));
328
329 for (QDoubleSpinBox* spinBox : findChildren<QDoubleSpinBox*>())
330 {
331 new JulySpinBoxFix(spinBox);
332
333 QString scriptName = spinBox->whatsThis();
334
335 if (scriptName.isEmpty())
336 continue;
337
338 indicatorsMap[scriptName] = spinBox;
339 }
340
341 double iniFileVersion = iniSettings->value("Profile/Version", 1.0).toDouble();
342
343 if (iniFileVersion < baseValues.appVerReal)
344 iniSettings->setValue("Profile/Version", baseValues.appVerReal);
345
346 QSettings settingsMain(appDataDir + "/QtBitcoinTrader.cfg", QSettings::IniFormat);
347 checkForUpdates = settingsMain.value("CheckForUpdates", true).toBool();
348
349 int defTextHeight = baseValues.fontMetrics_->boundingRect("0123456789").height();
350 defaultHeightForRow = settingsMain.value("RowHeight", defTextHeight * 1.6).toInt();
351
352 if (defaultHeightForRow < defTextHeight)
353 defaultHeightForRow = defTextHeight;
354
355 settingsMain.setValue("RowHeight", defaultHeightForRow);
356
357 exchangeId = iniSettings->value("Profile/ExchangeId", 0).toInt();
358
359 if (exchangeId == 11)
360 {
361 ui.depthComboBoxLimitRows->blockSignals(true);
362 ui.depthComboBoxLimitRows->clear();
363 ui.depthComboBoxLimitRows->addItems({"1000", "500", "100", "50", "20", "10", "5"});
364 ui.depthComboBoxLimitRows->blockSignals(false);
365 }
366
367 baseValues.depthCountLimit = iniSettings->value("UI/DepthCountLimit", 100).toInt();
368
369 if (baseValues.depthCountLimit < 0)
370 baseValues.depthCountLimit = 100;
371
372 baseValues.depthCountLimitStr = QByteArray::number(baseValues.depthCountLimit);
373 int currentDepthComboBoxLimitIndex = 0;
374
375 for (int n = 0; n < ui.depthComboBoxLimitRows->count(); n++)
376 {
377 int currentValueDouble = ui.depthComboBoxLimitRows->itemText(n).toInt();
378
379 if (currentValueDouble == baseValues.depthCountLimit)
380 currentDepthComboBoxLimitIndex = n;
381
382 ui.depthComboBoxLimitRows->setItemData(n, currentValueDouble, Qt::UserRole);
383 }
384
385 ui.depthComboBoxLimitRows->setCurrentIndex(currentDepthComboBoxLimitIndex);
386
387 baseValues.apiDownCount = iniSettings->value("Network/ApiDownCounterMax", 5).toInt();
388
389 if (baseValues.apiDownCount < 0)
390 baseValues.apiDownCount = 5;
391
392 iniSettings->setValue("Network/ApiDownCounterMax", baseValues.apiDownCount);
393
394 baseValues.httpRetryCount = iniSettings->value("Network/HttpRetryCount", 8).toInt();
395
396 if (baseValues.httpRetryCount < 1 || baseValues.httpRetryCount > 50)
397 baseValues.httpRetryCount = 8;
398
399 iniSettings->setValue("Network/HttpRetryCount", baseValues.httpRetryCount);
400
401 baseValues.uiUpdateInterval = iniSettings->value("UI/UiUpdateInterval", 100).toInt();
402
403 if (baseValues.uiUpdateInterval < 1)
404 baseValues.uiUpdateInterval = 100;
405
406 baseValues.customUserAgent = iniSettings->value("Network/UserAgent", "").toString();
407 baseValues.customCookies = iniSettings->value("Network/Cookies", "").toString();
408
409 baseValues.gzipEnabled = iniSettings->value("Network/GZIPEnabled", true).toBool();
410 iniSettings->setValue("Network/GZIPEnabled", baseValues.gzipEnabled);
411
412 feeCalculatorSingleInstance = iniSettings->value("UI/FeeCalcSingleInstance", true).toBool();
413 iniSettings->setValue("UI/FeeCalcSingleInstance", feeCalculatorSingleInstance);
414
415 ui.depthAutoResize->setChecked(iniSettings->value("UI/DepthAutoResizeColumns", true).toBool());
416
417 if (!ui.depthAutoResize->isChecked())
418 {
419 ui.depthAsksTable->setColumnWidth(1, iniSettings->value("UI/DepthColumnAsksSizeWidth",
420 ui.depthAsksTable->columnWidth(1)).toInt());
421 ui.depthAsksTable->setColumnWidth(2, iniSettings->value("UI/DepthColumnAsksVolumeWidth",
422 ui.depthAsksTable->columnWidth(2)).toInt());
423 ui.depthAsksTable->setColumnWidth(3, iniSettings->value("UI/DepthColumnAsksPriceWidth",
424 ui.depthAsksTable->columnWidth(3)).toInt());
425
426 ui.depthBidsTable->setColumnWidth(0, iniSettings->value("UI/DepthColumnBidsPriceWidth",
427 ui.depthBidsTable->columnWidth(0)).toInt());
428 ui.depthBidsTable->setColumnWidth(1, iniSettings->value("UI/DepthColumnBidsVolumeWidth",
429 ui.depthBidsTable->columnWidth(1)).toInt());
430 ui.depthBidsTable->setColumnWidth(2, iniSettings->value("UI/DepthColumnBidsSizeWidth",
431 ui.depthBidsTable->columnWidth(2)).toInt());
432 }
433
434 ui.rulesTabs->setVisible(false);
435
436 iniSettings->setValue("Network/HttpRetryCount", baseValues.httpRetryCount);
437 iniSettings->setValue("UI/UiUpdateInterval", baseValues.uiUpdateInterval);
438 iniSettings->setValue("UI/DepthAutoResizeColumns", ui.depthAutoResize->isChecked());
439
440 profileName = iniSettings->value("Profile/Name", "Default Profile").toString();
441 windowTitleP = profileName + " - " + windowTitle() + " v" + baseValues.appVerStr;
442
443 #ifdef QTBUILDTARGETWIN32
444 windowTitleP += " (32bit)";
445 #endif
446
447 #ifdef QTBUILDTARGETWIN64
448 windowTitleP += " (64bit)";
449 #endif
450
451 if (debugLevel)
452 windowTitleP.append(" [DEBUG MODE]");
453
454 //else if (baseValues.appVerIsBeta)
455 // windowTitleP.append(" [BETA]");
456
457 windowWidget->setWindowTitle(windowTitleP);
458
459 fixTableViews(this);
460
461 int defaultMinWidth = qMax(1024, minimumSizeHint().width());
462 int defaultMinHeight = qMax(720, minimumSizeHint().height());
463
464 baseValues.highResolutionDisplay = false;
465 int screenCount = QApplication::screens().count();
466
467 QRect currScrRect;
468
469 for (int n = 0; n < screenCount; n++)
470 {
471 currScrRect = QApplication::screens().at(n)->availableGeometry();
472
473 if (currScrRect.width() > defaultMinWidth && currScrRect.height() > defaultMinHeight)
474 {
475 baseValues.highResolutionDisplay = true;
476 break;
477 }
478 }
479
480 setSpinValue(ui.accountBTC, 0.0);
481 setSpinValue(ui.accountUSD, 0.0);
482 setSpinValue(ui.marketBid, 0.0);
483 setSpinValue(ui.marketAsk, 0.0);
484 setSpinValue(ui.marketHigh, 0.0);
485 setSpinValue(ui.marketLow, 0.0);
486 setSpinValue(ui.marketLast, 0.0);
487 setSpinValue(ui.marketVolume, 0.0);
488
489 if (iniSettings->value("UI/SwapDepth", false).toBool())
490 on_swapDepth_clicked();
491
492 ui.depthLag->setValue(0.0);
493
494 copyTableValuesMenu.addAction("Copy selected Rows", this, SLOT(copySelectedRow()));
495 copyTableValuesMenu.addSeparator();
496 copyTableValuesMenu.addAction("Copy Date", this, SLOT(copyDate()));
497 copyTableValuesMenu.addAction("Copy Amount", this, SLOT(copyAmount()));
498 copyTableValuesMenu.addAction("Copy Price", this, SLOT(copyPrice()));
499 copyTableValuesMenu.addAction("Copy Total", this, SLOT(copyTotal()));
500 copyTableValuesMenu.addSeparator();
501 copyTableValuesMenu.addAction("Repeat Buy and Sell order", this, SLOT(repeatBuySellOrder()));
502 copyTableValuesMenu.addAction("Repeat Buy order", this, SLOT(repeatBuyOrder()));
503 copyTableValuesMenu.addAction("Repeat Sell order", this, SLOT(repeatSellOrder()));
504 copyTableValuesMenu.addSeparator();
505 copyTableValuesMenu.addAction("Cancel Order", this, SLOT(on_ordersCancelSelected_clicked()));
506 copyTableValuesMenu.addAction("Cancel All Orders", this, SLOT(on_ordersCancelAllButton_clicked()));
507
508 createActions();
509 createMenu();
510
511 networkMenu = new NetworkMenu(ui.networkMenuTool);
512
513 currencyMenu = new CurrencyMenu(ui.currencyMenuTool);
514 connect(currencyMenu, &CurrencyMenu::currencyMenuChanged, this, &QtBitcoinTrader::currencyMenuChanged);
515
516 reloadLanguage();
517
518 volumeAmountChanged(0.0, 0.0);
519
520 connect(&julyTranslator, SIGNAL(languageChanged()), this, SLOT(languageChanged()));
521
522 if (checkForUpdates)
523 QProcess::startDetached(QApplication::applicationFilePath(), QStringList("/checkupdate"));
524
525 connect(networkMenu, &NetworkMenu::trafficTotalToZero_clicked, this, &QtBitcoinTrader::trafficTotalToZero_clicked);
526 iniSettings->sync();
527
528 chartsView = new ChartsView;
529 connect(tradesModel, &TradesModel::addChartsTrades, chartsView->chartsModel.data(), &ChartsModel::addLastTrades);
530 connect(this, &QtBitcoinTrader::clearCharts, chartsView->chartsModel.data(), &ChartsModel::clearCharts);
531 connect(this, &QtBitcoinTrader::addBound, chartsView->chartsModel.data(), &ChartsModel::addBound);
532 ui.chartsLayout->addWidget(chartsView);
533
534 newsView = new NewsView();
535 ui.newsLayout->addWidget(newsView);
536
537 //ChatWindow *chatWindow=new ChatWindow();
538 //ui.chatLayout->addWidget(chatWindow);
539
540 setContentsMargins(ContentMargin, ContentMargin, ContentMargin, ContentMargin);
541 initDocks();
542 moveWidgetsToDocks();
543 ui.menubar->setFixedHeight(ui.menubar->height() + 2);
544
545 connect(::config, &ConfigManager::onChanged, this, &QtBitcoinTrader::onConfigChanged);
546 connect(::config, &ConfigManager::onError, this, &QtBitcoinTrader::onConfigError);
547 initConfigMenu();
548
549 if (iniSettings->value("UI/OptimizeInterface", false).toBool())
550 recursiveUpdateLayouts(this);
551
552 secondTimer->setSingleShot(true);
553 connect(secondTimer.data(), &QTimer::timeout, this, &QtBitcoinTrader::secondSlot);
554 secondSlot();
555 }
556
~QtBitcoinTrader()557 QtBitcoinTrader::~QtBitcoinTrader()
558 {
559 if (currentExchangeThread && currentExchangeThread->isRunning())
560 {
561 currentExchangeThread->quit();
562 currentExchangeThread->wait();
563 delete currentExchange;
564 currentExchange = nullptr;
565 currentExchangeThread.reset();
566 }
567 }
568
fixTableViews(QWidget * wid)569 void QtBitcoinTrader::fixTableViews(QWidget* wid)
570 {
571 for (QTableView* tables : wid->findChildren<QTableView*>())
572 {
573 QFont tableFont = tables->font();
574 tableFont.setFixedPitch(true);
575 tables->setFont(tableFont);
576 tables->setMinimumWidth(200);
577 tables->setMinimumHeight(190);
578 tables->verticalHeader()->setDefaultSectionSize(defaultHeightForRow);
579 }
580 }
581
getIndicatorValue(const QString & name)582 double QtBitcoinTrader::getIndicatorValue(const QString& name)
583 {
584 QDoubleSpinBox* spin = indicatorsMap.value(name, nullptr);
585
586 if (spin == nullptr)
587 return 0.0;
588
589 return spin->value();
590 }
591
setColumnResizeMode(QTableView * table,int column,QHeaderView::ResizeMode mode)592 void QtBitcoinTrader::setColumnResizeMode(QTableView* table, int column, QHeaderView::ResizeMode mode)
593 {
594 table->horizontalHeader()->setSectionResizeMode(column, mode);
595 }
596
setColumnResizeMode(QTableView * table,QHeaderView::ResizeMode mode)597 void QtBitcoinTrader::setColumnResizeMode(QTableView* table, QHeaderView::ResizeMode mode)
598 {
599 table->horizontalHeader()->setSectionResizeMode(mode);
600 }
601
setupClass()602 void QtBitcoinTrader::setupClass()
603 {
604 switch (exchangeId)
605 {
606 case 0:
607 QCoreApplication::quit();
608 return;//Secret Excange
609
610 case 2:
611 currentExchange = new Exchange_Bitstamp(baseValues.restSign, baseValues.restKey);
612 break;//Bitstamp
613
614 case 4:
615 currentExchange = new Exchange_Bitfinex(baseValues.restSign, baseValues.restKey);
616 break;//Bitfinex
617
618 case 6:
619 currentExchange = new Exchange_Indacoin(baseValues.restSign, baseValues.restKey);
620 break;//Indacoin
621
622 case 10:
623 currentExchange = new Exchange_YObit(baseValues.restSign, baseValues.restKey);
624 break;//YObit
625
626 case 11:
627 currentExchange = new Exchange_Binance(baseValues.restSign, baseValues.restKey);
628 break;//Binance
629
630 case 12:
631 currentExchange = new Exchange_Bittrex(baseValues.restSign, baseValues.restKey);
632 break;//Bittrex
633
634 case 13:
635 currentExchange = new Exchange_HitBTC(baseValues.restSign, baseValues.restKey);
636 break;//HitBTC
637
638 case 14:
639 currentExchange = new Exchange_Poloniex(baseValues.restSign, baseValues.restKey);
640 break;//Poloniex
641
642 default:
643 return;
644 }
645
646 baseValues.minimumRequestInterval = currentExchange->minimumRequestIntervalAllowed;
647 baseValues.httpRequestInterval = iniSettings->value("Network/HttpRequestsInterval", baseValues.minimumRequestInterval).toInt();
648 baseValues.minimumRequestTimeout = currentExchange->minimumRequestTimeoutAllowed;
649 baseValues.httpRequestTimeout = iniSettings->value("Network/HttpRequestsTimeout", baseValues.minimumRequestTimeout).toInt();
650
651 if (baseValues.httpRequestInterval < 50)
652 baseValues.httpRequestInterval = 50;
653
654 if (baseValues.httpRequestTimeout < 100)
655 baseValues.httpRequestTimeout = 100;
656
657 iniSettings->setValue("Network/HttpRequestsInterval", baseValues.httpRequestInterval);
658 iniSettings->setValue("Network/HttpRequestsTimeout", baseValues.httpRequestTimeout);
659
660 currentExchangeThread.reset(new QThread);
661 currentExchangeThread->setObjectName("Exchange Thread");
662 currentExchange->moveToThread(currentExchangeThread.data());
663 connect(currentExchangeThread.data(), &QThread::started, currentExchange, &Exchange::run);
664
665 baseValues.restSign.clear();
666
667 currentExchange->setupApi(this, false);
668
669 if (currentExchange->domain.isEmpty())
670 setCurrencyPairsList();
671
672 setApiDown(false);
673
674 if (!currentExchange->exchangeTickerSupportsHiLowPrices)
675 for (int n = 0; n < ui.highLowLayout->count(); n++)
676 {
677 QWidgetItem* curWid = dynamic_cast<QWidgetItem*>(ui.highLowLayout->itemAt(n));
678
679 if (curWid)
680 curWid->widget()->setVisible(false);
681 }
682
683 if (!currentExchange->supportsExchangeFee)
684 {
685 ui.accountFee->setButtonSymbols(QAbstractSpinBox::UpDownArrows);
686 ui.accountFee->setReadOnly(false);
687
688 setSpinValue(ui.accountFee, iniSettings->value("Profile/CustomFee", 0.35).toDouble());
689 ui.feeSpinboxLayout->addWidget(new JulySpinBoxPicker(ui.accountFee));
690 }
691
692 if (!currentExchange->supportsExchangeVolume)
693 {
694 ui.marketVolumeLabel->setVisible(false);
695 ui.btcLabel4->setVisible(false);
696 ui.marketVolume->setVisible(false);
697 }
698
699 if (currentExchange->clearOpenOrdersOnCurrencyChanged || currentExchange->exchangeDisplayOnlyCurrentPairOpenOrders)
700 {
701 ui.ordersFilterCheckBox->setVisible(false);
702
703 if (currentExchange->exchangeDisplayOnlyCurrentPairOpenOrders)
704 ui.ordersFilterCheckBox->setChecked(true);
705
706 ui.filterOrdersCurrency->setVisible(false);
707 ui.centerOrdersTotalSpacer->setVisible(true);
708 }
709 else
710 ui.centerOrdersTotalSpacer->setVisible(false);
711
712 if (!currentExchange->supportsLoginIndicator)
713 {
714 ui.loginVolumeBack->setVisible(false);
715 QSize sz = ui.widgetAccount->maximumSize();
716 ui.widgetAccount->setMaximumSize(QSize(200, sz.height()));
717 }
718 else if (currentExchange->supportsLoginIndicator && !currentExchange->supportsAccountVolume)
719 {
720 ui.labelAccountVolume->setVisible(false);
721 ui.btcLabelAccountVolume->setVisible(false);
722 ui.accountVolume->setVisible(false);
723 }
724
725 ordersModel->checkDuplicatedOID = currentExchange->checkDuplicatedOID;
726
727 {
728 QEventLoop waitStarted;
729 connect(currentExchange, &Exchange::started, &waitStarted, &QEventLoop::quit);
730 currentExchangeThread->start();
731 waitStarted.exec();
732 }
733
734 if (!ui.widgetStaysOnTop->isChecked())
735 on_widgetStaysOnTop_toggled(ui.widgetStaysOnTop->isChecked());
736
737 ui.widgetStaysOnTop->setChecked(iniSettings->value("UI/WindowOnTop", false).toBool());
738 languageChanged();
739 reloadScripts();
740 IndicatorEngine::global();
741 int nextTheme = iniSettings->value("UI/NightMode", 0).toInt();
742
743 if (nextTheme == 1)
744 on_buttonNight_clicked();
745 else if (nextTheme == 2)
746 {
747 baseValues.currentTheme = 1;
748 on_buttonNight_clicked();
749 }
750 else
751 ui.widgetLogo->setStyleSheet("background:white");
752
753 ::config->load("");
754
755 if (isHidden())
756 show();
757
758 ui.buyPercentage->setMaximumWidth(ui.buyPercentage->height());
759 ui.sellPercentage->setMaximumWidth(ui.sellPercentage->height());
760 fixDepthBidsTable();
761
762 ui.comboBoxGroupByPrice->blockSignals(true);
763 ui.comboBoxGroupByPrice->addItem(julyTr("DONT_GROUP", "None"), double(0));
764 ui.comboBoxGroupByPrice->blockSignals(false);
765 baseValues.groupPriceValue = iniSettings->value("UI/DepthGroupByPrice", 0.0).toDouble();
766
767 if (baseValues.groupPriceValue < 0.0)
768 baseValues.groupPriceValue = 0.0;
769 else if (baseValues.groupPriceValue > 0.0)
770 {
771 ui.comboBoxGroupByPrice->addItem(QString::number(baseValues.groupPriceValue), baseValues.groupPriceValue);
772 ui.comboBoxGroupByPrice->setCurrentIndex(1);
773 }
774 }
775
addRuleByHolder(RuleHolder & holder,bool isEnabled,QString titleName)776 void QtBitcoinTrader::addRuleByHolder(RuleHolder& holder, bool isEnabled, QString titleName)
777 {
778 int findNameTab = -1;
779
780 for (int n = 0; n < ui.rulesTabs->count(); n++)
781 {
782 QWidget* currentWidget = ui.rulesTabs->widget(n);
783
784 if (!titleName.isEmpty() && currentWidget->windowTitle() == titleName)
785 findNameTab = n;
786
787 if (findNameTab > -1)
788 break;
789 }
790
791 if (findNameTab > -1)
792 {
793 QWidget* currentWidget = ui.rulesTabs->widget(findNameTab);
794
795 if (currentWidget->property("GroupType").toString() == QLatin1String("Rule"))
796 (static_cast<RuleWidget*>(currentWidget))->addRuleByHolder(holder, isEnabled);
797 else if (currentWidget->property("GroupType").toString() == QLatin1String("Script"))
798 (static_cast<ScriptWidget*>(currentWidget))->replaceScript(RuleScriptParser::holderToScript(holder, false));
799 }
800 else
801 {
802 QString nameTemplate(baseValues.scriptFolder + "Script_%1.JLS");
803 int ruleN = 1;
804
805 while (QFile::exists(nameTemplate.arg(ruleN)))
806 ruleN++;
807
808 ScriptWidget* newRule = new ScriptWidget(titleName, nameTemplate.arg(ruleN));
809 findNameTab = ui.rulesTabs->count();
810 ui.rulesTabs->insertTab(findNameTab, newRule, newRule->windowTitle());
811 newRule->replaceScript(RuleScriptParser::holderToScript(holder, false));
812 }
813
814 if (findNameTab > -1 && findNameTab < ui.rulesTabs->count())
815 ui.rulesTabs->setCurrentIndex(findNameTab);
816 }
817
getRuleGroupsNames()818 QStringList QtBitcoinTrader::getRuleGroupsNames()
819 {
820 QStringList rezult;
821
822 for (RuleWidget* ruleWidget : ui.tabRules->findChildren<RuleWidget*>())
823 if (ruleWidget)
824 rezult << ruleWidget->windowTitle();
825
826 return rezult;
827 }
828
getScriptGroupsNames()829 QStringList QtBitcoinTrader::getScriptGroupsNames()
830 {
831 QStringList rezult;
832
833 for (ScriptWidget* scriptWidget : ui.tabRules->findChildren<ScriptWidget*>())
834 if (scriptWidget)
835 rezult << scriptWidget->windowTitle();
836
837 return rezult;
838 }
839
getIsGroupRunning(const QString & name)840 bool QtBitcoinTrader::getIsGroupRunning(const QString& name)
841 {
842 for (RuleWidget* ruleWidget : ui.tabRules->findChildren<RuleWidget*>())
843 if (ruleWidget && (ruleWidget->windowTitle().compare(name, Qt::CaseInsensitive) == 0))
844 return ruleWidget->haveWorkingRules();
845
846 for (ScriptWidget* scriptWidget : ui.tabRules->findChildren<ScriptWidget*>())
847 if (scriptWidget && (scriptWidget->windowTitle().compare(name, Qt::CaseInsensitive) == 0))
848 return scriptWidget->isRunning();
849
850 return false;
851 }
852
setGroupState(const QString & name,bool enabled)853 void QtBitcoinTrader::setGroupState(const QString& name, bool enabled)
854 {
855 for (RuleWidget* ruleWidget : ui.tabRules->findChildren<RuleWidget*>())
856 if (ruleWidget && (ruleWidget->windowTitle().compare(name, Qt::CaseInsensitive) == 0))
857 {
858 if (enabled)
859 ruleWidget->ruleEnableAll();
860 else
861 ruleWidget->ruleDisableAll();
862 }
863
864 for (ScriptWidget* scriptWidget : ui.tabRules->findChildren<ScriptWidget*>())
865 if (scriptWidget && (scriptWidget->windowTitle().compare(name, Qt::CaseInsensitive) == 0))
866 scriptWidget->setRunning(enabled);
867 }
868
clearPendingGroup(const QString & name)869 void QtBitcoinTrader::clearPendingGroup(const QString& name)
870 {
871 for (int n = pendingGroupStates.size() - 1; n >= 0; n--)
872 if (pendingGroupStates.at(n).name == name)
873 pendingGroupStates.removeAt(n);
874 }
875
setGroupRunning(const QString & name,bool enabled)876 void QtBitcoinTrader::setGroupRunning(const QString& name, bool enabled)
877 {
878 if (enabled)
879 pendingGroupStates << GroupStateItem(name, enabled);
880 else
881 {
882 clearPendingGroup(name);
883 setGroupState(name, enabled);
884 }
885 }
886
on_buyPercentage_clicked()887 void QtBitcoinTrader::on_buyPercentage_clicked()
888 {
889 PercentPicker* percentPicker = new PercentPicker(buyTotalBtc, getAvailableUSDtoBTC(buyPricePerCoin->value()));
890 QPoint execPos = ui.buyAmountPickerBack->mapToGlobal(ui.buyPercentage->geometry().center());
891 execPos.setX(execPos.x() - percentPicker->width() / 2);
892 execPos.setY(execPos.y() - percentPicker->width());
893 percentPicker->exec(execPos);
894 }
895
on_sellPercentage_clicked()896 void QtBitcoinTrader::on_sellPercentage_clicked()
897 {
898 PercentPicker* percentPicker = new PercentPicker(sellTotalBtc, getAvailableBTC());
899 QPoint execPos = ui.sellAmountPickerBack->mapToGlobal(ui.sellPercentage->geometry().center());
900 execPos.setX(execPos.x() - percentPicker->width() / 2);
901 execPos.setY(execPos.y() - percentPicker->width());
902 percentPicker->exec(execPos);
903 }
904
ordersFilterChanged()905 void QtBitcoinTrader::ordersFilterChanged()
906 {
907 QString filterSymbol;
908 QString currAStr;
909 QString currBStr;
910 QPixmap currPixmap;
911
912 if (ui.ordersFilterCheckBox->isChecked())
913 {
914 filterSymbol = ui.filterOrdersCurrency->currentText();
915 int posSplitter = filterSymbol.indexOf('/');
916
917 if (posSplitter == -1)
918 {
919 currAStr = filterSymbol.left(3);
920 currBStr = filterSymbol.right(3);
921 }
922 else
923 {
924 currAStr = filterSymbol.left(posSplitter);
925 currBStr = filterSymbol.right(filterSymbol.size() - posSplitter - 1);
926 }
927
928 if (filterSymbol.size())
929 if (baseValues.currentPair.symbol.indexOf("/") == -1)
930 filterSymbol.replace("/", "");
931 }
932 else
933 {
934 currAStr = baseValues.currentPair.currAStr.toUpper();
935 currBStr = baseValues.currentPair.currBStr.toUpper();
936 }
937
938 currencySignLoader->getCurrencySign(currAStr, currPixmap);
939 ui.currALabel->setPixmap(currPixmap);
940 ui.currALabel->setToolTip(currAStr);
941
942 currencySignLoader->getCurrencySign(currBStr, currPixmap);
943 ui.currBLabel->setPixmap(currPixmap);
944 ui.currBLabel->setToolTip(currBStr);
945
946 ordersSortModel->setFilterWildcard(filterSymbol);
947 ordersModel->filterSymbolChanged(filterSymbol);
948 }
949
tableCopyContextMenuRequested(QPoint point)950 void QtBitcoinTrader::tableCopyContextMenuRequested(QPoint point)
951 {
952 QTableView* table = dynamic_cast<QTableView*>(sender());
953
954 if (table == nullptr)
955 return;
956
957 int selectedCount = table->selectionModel()->selectedRows().size();
958
959 if (selectedCount == 0)
960 return;
961
962 lastCopyTable = table;
963 bool isOpenOrders = table == ui.ordersTable;
964 bool isDateAvailable = table != ui.depthAsksTable && table != ui.depthBidsTable;
965
966 copyTableValuesMenu.actions().at(2)->setVisible(isDateAvailable);
967
968 copyTableValuesMenu.actions().at(6)->setEnabled(selectedCount == 1);
969 copyTableValuesMenu.actions().at(7)->setEnabled(selectedCount == 1);
970 copyTableValuesMenu.actions().at(8)->setEnabled(selectedCount == 1);
971 copyTableValuesMenu.actions().at(9)->setEnabled(selectedCount == 1);
972
973 copyTableValuesMenu.actions().at(10)->setVisible(isOpenOrders);
974 copyTableValuesMenu.actions().at(11)->setVisible(isOpenOrders);
975 copyTableValuesMenu.actions().at(12)->setVisible(isOpenOrders);
976
977 copyTableValuesMenu.exec(lastCopyTable->viewport()->mapToGlobal(point));
978 }
979
getOpenOrdersCount(int all)980 int QtBitcoinTrader::getOpenOrdersCount(int all)//-1: asks, 0 all, 1: bids
981 {
982 if (all == 0)
983 return ordersModel->rowCount();
984
985 if (all == -1)
986 return ordersModel->getAsksCount();
987
988 return ordersModel->rowCount() - ordersModel->getAsksCount();
989 }
990
991
repeatSelectedOrderByType(int type,bool availableOnly)992 void QtBitcoinTrader::repeatSelectedOrderByType(int type, bool availableOnly)
993 {
994 if (lastCopyTable == nullptr || lastCopyTable->selectionModel()->selectedRows().size() != 1)
995 return;
996
997 int row = lastCopyTable->selectionModel()->selectedRows().first().row();
998
999 if (lastCopyTable == ui.tableTrades)
1000 repeatOrderFromTrades(type, row);
1001 else if (lastCopyTable == ui.tableHistory)
1002 repeatOrderFromValues(type, historyModel->getRowPrice(row), historyModel->getRowVolume(row), availableOnly);
1003
1004 if (lastCopyTable == ui.ordersTable)
1005 {
1006 row = ordersSortModel->mapToSource(ordersSortModel->index(row, 0)).row();
1007 repeatOrderFromValues(type, ordersModel->getRowPrice(row), ordersModel->getRowVolume(row)*floatFeeDec, availableOnly);
1008 }
1009
1010 if (lastCopyTable == ui.depthAsksTable)
1011 depthSelectOrder(swapedDepth ? depthBidsModel->index(row, 3) : depthAsksModel->index(row, 3), true, type);
1012
1013 if (lastCopyTable == ui.depthBidsTable)
1014 depthSelectOrder(!swapedDepth ? depthBidsModel->index(row, 1) : depthAsksModel->index(row, 1), false, type);
1015 }
1016
repeatBuySellOrder()1017 void QtBitcoinTrader::repeatBuySellOrder()
1018 {
1019 repeatSelectedOrderByType(0);
1020 }
1021
repeatBuyOrder()1022 void QtBitcoinTrader::repeatBuyOrder()
1023 {
1024 repeatSelectedOrderByType(1);
1025 }
1026
repeatSellOrder()1027 void QtBitcoinTrader::repeatSellOrder()
1028 {
1029 repeatSelectedOrderByType(-1);
1030 }
1031
copyDate()1032 void QtBitcoinTrader::copyDate()
1033 {
1034 if (lastCopyTable == nullptr)
1035 return;
1036
1037 if (lastCopyTable == ui.tableHistory)
1038 copyInfoFromTable(ui.tableHistory, historyModel, 1);
1039 else if (lastCopyTable == ui.tableTrades)
1040 copyInfoFromTable(ui.tableTrades, tradesModel, 1);
1041 else if (lastCopyTable == ui.ordersTable)
1042 copyInfoFromTable(ui.ordersTable, ordersSortModel, 1);
1043 }
1044
copyAmount()1045 void QtBitcoinTrader::copyAmount()
1046 {
1047 if (lastCopyTable == nullptr)
1048 return;
1049
1050 if (lastCopyTable == ui.tableHistory)
1051 copyInfoFromTable(ui.tableHistory, historyModel, 2);
1052 else if (lastCopyTable == ui.tableTrades)
1053 copyInfoFromTable(ui.tableTrades, tradesModel, 2);
1054 else
1055
1056 if (lastCopyTable == ui.depthAsksTable)
1057 copyInfoFromTable(ui.depthAsksTable, swapedDepth ? depthBidsModel : depthAsksModel, 3);
1058 else if (lastCopyTable == ui.depthBidsTable)
1059 copyInfoFromTable(ui.depthBidsTable, swapedDepth ? depthAsksModel : depthBidsModel, 1);
1060 else if (lastCopyTable == ui.ordersTable)
1061 copyInfoFromTable(ui.ordersTable, ordersSortModel, 4);
1062 }
1063
copyPrice()1064 void QtBitcoinTrader::copyPrice()
1065 {
1066 if (lastCopyTable == nullptr)
1067 return;
1068
1069 if (lastCopyTable == ui.tableHistory)
1070 copyInfoFromTable(ui.tableHistory, historyModel, 4);
1071 else if (lastCopyTable == ui.tableTrades)
1072 copyInfoFromTable(ui.tableTrades, tradesModel, 5);
1073 else
1074
1075 if (lastCopyTable == ui.depthAsksTable)
1076 copyInfoFromTable(ui.depthAsksTable, swapedDepth ? depthBidsModel : depthAsksModel, 4);
1077 else if (lastCopyTable == ui.depthBidsTable)
1078 copyInfoFromTable(ui.depthBidsTable, swapedDepth ? depthAsksModel : depthBidsModel, 0);
1079 else if (lastCopyTable == ui.ordersTable)
1080 copyInfoFromTable(ui.ordersTable, ordersSortModel, 5);
1081 }
1082
copyTotal()1083 void QtBitcoinTrader::copyTotal()
1084 {
1085 if (lastCopyTable == nullptr)
1086 return;
1087
1088 if (lastCopyTable == ui.tableHistory)
1089 copyInfoFromTable(ui.tableHistory, historyModel, 5);
1090 else if (lastCopyTable == ui.tableTrades)
1091 copyInfoFromTable(ui.tableTrades, tradesModel, 6);
1092 else
1093
1094 if (lastCopyTable == ui.depthAsksTable)
1095 copyInfoFromTable(ui.depthAsksTable, swapedDepth ? depthBidsModel : depthAsksModel, 1);
1096 else if (lastCopyTable == ui.depthBidsTable)
1097 copyInfoFromTable(ui.depthBidsTable, swapedDepth ? depthAsksModel : depthBidsModel, 3);
1098 else if (lastCopyTable == ui.ordersTable)
1099 copyInfoFromTable(ui.ordersTable, ordersSortModel, 6);
1100 }
1101
copyInfoFromTable(QTableView * table,QAbstractItemModel * model,int i)1102 void QtBitcoinTrader::copyInfoFromTable(QTableView* table, QAbstractItemModel* model, int i)
1103 {
1104 QModelIndexList selectedRows = table->selectionModel()->selectedRows();
1105
1106 if (selectedRows.size() == 0)
1107 return;
1108
1109 QStringList copyData;
1110
1111 for (int n = 0; n < selectedRows.size(); n++)
1112 {
1113 bool getToolTip = false;
1114
1115 if ((table == ui.tableHistory && i == 1) ||
1116 (table == ui.tableTrades && i == 1))
1117 getToolTip = true;
1118
1119 copyData << model->index(selectedRows.at(n).row(), i).data((getToolTip ? Qt::ToolTipRole : Qt::DisplayRole)).toString();
1120 }
1121
1122 QApplication::clipboard()->setText(copyData.join("\n"));
1123 }
1124
copySelectedRow()1125 void QtBitcoinTrader::copySelectedRow()
1126 {
1127 QStringList listToCopy;
1128
1129 if (lastCopyTable == nullptr)
1130 return;
1131
1132 QModelIndexList selectedRows = lastCopyTable->selectionModel()->selectedRows();
1133
1134 if (selectedRows.size() == 0)
1135 return;
1136
1137 for (int n = 0; n < selectedRows.size(); n++)
1138 {
1139 QString currentText = selectedRows.at(n).data(Qt::StatusTipRole).toString();
1140
1141 if (!currentText.isEmpty())
1142 listToCopy << currentText;
1143 }
1144
1145 if (listToCopy.isEmpty())
1146 return;
1147
1148 QApplication::clipboard()->setText(listToCopy.join("\n"));
1149 }
1150
on_buttonAddRuleGroup_clicked()1151 void QtBitcoinTrader::on_buttonAddRuleGroup_clicked()
1152 {
1153 AddRuleGroup ruleGroup;
1154
1155 if (ui.widgetStaysOnTop->isChecked())
1156 ruleGroup.setWindowFlags(Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint);
1157
1158 if (ruleGroup.exec() == QDialog::Rejected || ruleGroup.fileName.isEmpty() || !QFile::exists(ruleGroup.fileName))
1159 {
1160 return;
1161 }
1162
1163 RuleWidget* newRule = new RuleWidget(ruleGroup.fileName);
1164 ui.rulesTabs->insertTab(ui.rulesTabs->count(), newRule, newRule->windowTitle());
1165
1166 QStringList rulesListLoad = ruleGroup.groupsList;
1167
1168 if (rulesListLoad.size())
1169 {
1170 ui.rulesTabs->setVisible(true);
1171 ui.rulesNoMessage->setVisible(false);
1172 return;
1173 }
1174
1175 ui.rulesTabs->setCurrentIndex(ui.rulesTabs->count() - 1);
1176
1177 ui.rulesTabs->setVisible(true);
1178 ui.rulesNoMessage->setVisible(false);
1179 }
1180
on_buttonAddScript_clicked()1181 void QtBitcoinTrader::on_buttonAddScript_clicked()
1182 {
1183 AddScriptWindow scriptWindow;
1184
1185 if (ui.widgetStaysOnTop->isChecked())
1186 scriptWindow.setWindowFlags(Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint);
1187
1188 if (scriptWindow.exec() == QDialog::Rejected || scriptWindow.scriptName.isEmpty())
1189 return;
1190
1191 ScriptWidget* newScript = new ScriptWidget(scriptWindow.scriptName, "", scriptWindow.copyFromExistingScript);
1192 ui.rulesTabs->insertTab(ui.rulesTabs->count(), newScript, newScript->windowTitle());
1193
1194 ui.rulesTabs->setCurrentIndex(ui.rulesTabs->count() - 1);
1195
1196 ui.rulesTabs->setVisible(true);
1197 ui.rulesNoMessage->setVisible(false);
1198 }
1199
reloadScripts()1200 void QtBitcoinTrader::reloadScripts()
1201 {
1202 for (const QString& currentFilePath : QDir(baseValues.scriptFolder).entryList(QStringList() << "*.JLS" << "*.JLR"))
1203 {
1204 QString currentFile = baseValues.scriptFolder + currentFilePath;
1205
1206 QString suffix = QFileInfo(currentFile).suffix().toUpper();
1207
1208 if (suffix == QLatin1String("JLS"))
1209 {
1210 QSettings loadScript(currentFile, QSettings::IniFormat);
1211 QString currentName = loadScript.value("JLScript/Name").toString();
1212
1213 if (currentName != "")
1214 {
1215 ScriptWidget* scriptWidget = new ScriptWidget(currentName, currentFile);
1216 ui.rulesTabs->insertTab(ui.rulesTabs->count(), scriptWidget, scriptWidget->windowTitle());
1217 }
1218 else
1219 QFile::remove(currentFile);
1220 }
1221 else if (suffix == QLatin1String("JLR"))
1222 {
1223 QSettings loadScript(currentFile, QSettings::IniFormat);
1224 QString currentName = loadScript.value("JLRuleGroup/Name", "").toString();
1225
1226 if (currentName != "")
1227 {
1228 RuleWidget* newRule = new RuleWidget(currentFile);
1229 ui.rulesTabs->insertTab(ui.rulesTabs->count(), newRule, newRule->windowTitle());
1230 }
1231 else
1232 QFile::remove(currentFile);
1233 }
1234 }
1235
1236 ui.rulesTabs->setVisible(ui.rulesTabs->count());
1237 ui.rulesNoMessage->setVisible(ui.rulesTabs->count() == 0);
1238 }
1239
keyPressEvent(QKeyEvent * event)1240 void QtBitcoinTrader::keyPressEvent(QKeyEvent* event)
1241 {
1242 event->accept();
1243
1244 if (ui.ordersTable->hasFocus() && (event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace))
1245 {
1246 on_ordersCancelSelected_clicked();
1247 return;
1248 }
1249
1250 if (event->modifiers()&Qt::ControlModifier)
1251 {
1252 if (event->key() == Qt::Key_B)
1253 buyBitcoinsButton();
1254 else if (event->key() == Qt::Key_S)
1255 sellBitcoinButton();
1256 else
1257 #ifndef Q_OS_MAC
1258 if (event->key() == Qt::Key_H)
1259 buttonMinimizeToTray();
1260 else
1261 #endif
1262 if (event->key() == Qt::Key_N)
1263 buttonNewWindow();
1264 else if (event->key() == Qt::Key_T)
1265 ui.widgetStaysOnTop->setChecked(!ui.widgetStaysOnTop->isChecked());
1266
1267 return;
1268 }
1269
1270 int modifiersPressed = 0;
1271
1272 if (event->modifiers()&Qt::ControlModifier)
1273 modifiersPressed++;
1274
1275 if (event->modifiers()&Qt::ShiftModifier)
1276 modifiersPressed++;
1277
1278 if (event->modifiers()&Qt::AltModifier)
1279 modifiersPressed++;
1280
1281 if (event->modifiers()&Qt::MetaModifier)
1282 modifiersPressed++;
1283
1284 if (event->key() == Qt::Key_T && modifiersPressed > 1)
1285 {
1286 (new TranslationAbout(windowWidget))->showWindow();
1287 return;
1288 }
1289
1290 if (event->key() == Qt::Key_D && modifiersPressed > 1)
1291 {
1292 onActionDebug();
1293 return;
1294 }
1295 }
1296
precentBidsChanged(double val)1297 void QtBitcoinTrader::precentBidsChanged(double val)
1298 {
1299 ui.tradesBidsPrecent->setValue(val);
1300
1301 static bool lastPrecentGrowing = false;
1302 bool precentGrowing = tradesPrecentLast < val;
1303
1304 if (lastPrecentGrowing != precentGrowing)
1305 {
1306 lastPrecentGrowing = precentGrowing;
1307 ui.tradesLabelDirection->setText(precentGrowing ? upArrowNoUtfStr : downArrowNoUtfStr);
1308 }
1309
1310 tradesPrecentLast = val;
1311 }
1312
on_swapDepth_clicked()1313 void QtBitcoinTrader::on_swapDepth_clicked()
1314 {
1315 swapedDepth = !swapedDepth;
1316
1317 if (swapedDepth)
1318 {
1319 depthBidsModel->setAsk(true);
1320 ui.depthAsksTable->setModel(depthBidsModel);
1321 depthAsksModel->setAsk(false);
1322 ui.depthBidsTable->setModel(depthAsksModel);
1323 }
1324 else
1325 {
1326 depthAsksModel->setAsk(true);
1327 ui.depthAsksTable->setModel(depthAsksModel);
1328 depthBidsModel->setAsk(false);
1329 ui.depthBidsTable->setModel(depthBidsModel);
1330 }
1331
1332 QString tempText = ui.asksLabel->text();
1333 QString tempId = ui.asksLabel->accessibleName();
1334 QString tempStyle = ui.asksLabel->styleSheet();
1335
1336 ui.asksLabel->setText(ui.bidsLabel->text());
1337 ui.asksLabel->setAccessibleName(ui.bidsLabel->accessibleName());
1338 ui.asksLabel->setStyleSheet(ui.bidsLabel->styleSheet());
1339
1340 ui.bidsLabel->setText(tempText);
1341 ui.bidsLabel->setAccessibleName(tempId);
1342 ui.bidsLabel->setStyleSheet(tempStyle);
1343
1344 iniSettings->setValue("UI/SwapDepth", swapedDepth);
1345 iniSettings->sync();
1346 }
1347
anyDataReceived()1348 void QtBitcoinTrader::anyDataReceived()
1349 {
1350 softLagTime.restart();
1351 setSoftLagValue(0);
1352 }
1353
getFeeForUSDDec(double usd)1354 double QtBitcoinTrader::getFeeForUSDDec(double usd)
1355 {
1356 double result = JulyMath::cutDoubleDecimalsCopy(usd, baseValues.currentPair.currBDecimals, false);
1357 double calcFee = JulyMath::cutDoubleDecimalsCopy(result, baseValues.currentPair.priceDecimals, true) * floatFee;
1358 calcFee = JulyMath::cutDoubleDecimalsCopy(calcFee, baseValues.currentPair.priceDecimals, true);
1359 result = result - calcFee;
1360 return result;
1361 }
1362
addPopupDialog(int val)1363 void QtBitcoinTrader::addPopupDialog(int val)
1364 {
1365 currentPopupDialogs += val;
1366 ui.buttonNewWindow->setEnabled(currentPopupDialogs == 0);
1367 }
1368
buttonMinimizeToTray()1369 void QtBitcoinTrader::buttonMinimizeToTray()
1370 {
1371 if (trayIcon == nullptr)
1372 {
1373 trayIcon = new QSystemTrayIcon(QIcon(":/Resources/QtBitcoinTrader.png"), this);
1374 trayIcon->setToolTip(windowTitle());
1375 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this,
1376 SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
1377 trayMenu = new QMenu(this);
1378 trayIcon->setContextMenu(trayMenu);
1379 trayMenu->addAction(QIcon(":/Resources/exit.png"), "Exit");
1380 trayMenu->actions().last()->setWhatsThis("EXIT");
1381 connect(trayMenu->actions().first(), SIGNAL(triggered(bool)), this, SLOT(exitApp()));
1382 }
1383
1384 trayIcon->show();
1385 trayIcon->showMessage(windowTitleP, windowTitle());
1386 windowWidget->hide();
1387 dockHost->setFloatingVisible(false);
1388 }
1389
trayActivated(QSystemTrayIcon::ActivationReason reazon)1390 void QtBitcoinTrader::trayActivated(QSystemTrayIcon::ActivationReason reazon)
1391 {
1392 if (trayIcon == nullptr)
1393 return;
1394
1395 if (reazon == QSystemTrayIcon::Context)
1396 {
1397 QList<QAction*> tList = trayMenu->actions();
1398
1399 for (int n = 0; n < tList.size(); n++)
1400 tList.at(n)->setText(julyTr(tList.at(n)->whatsThis(), tList.at(n)->text()));
1401
1402 trayMenu->exec();
1403 return;
1404 }
1405
1406 windowWidget->show();
1407 dockHost->setFloatingVisible(true);
1408
1409 trayIcon->hide();
1410 delete trayMenu;
1411 trayMenu = nullptr;
1412 delete trayIcon;
1413 trayIcon = nullptr;
1414 }
1415
checkUpdate()1416 void QtBitcoinTrader::checkUpdate()
1417 {
1418 QProcess::startDetached(QApplication::applicationFilePath(), QStringList("/checkupdatemessage"));
1419 }
1420
startApplication(const QString & name,QStringList params)1421 void QtBitcoinTrader::startApplication(const QString& name, QStringList params)
1422 {
1423 #ifdef Q_OS_MAC
1424
1425 if (QFileInfo(name).fileName().contains(QLatin1Char('.')))
1426 params.prepend(name);
1427
1428 QProcess::startDetached(QLatin1String("open"), params);
1429 #else
1430 QProcess::startDetached(name, params);
1431 #endif
1432 }
1433
sayText(const QString & text)1434 void QtBitcoinTrader::sayText(const QString& text)
1435 {
1436 if (ttsEngine.isNull())
1437 ttsEngine.reset(new QTextToSpeech(this));
1438
1439 if (ttsEngine->availableEngines().isEmpty())
1440 startApplication(QLatin1String("say"), QStringList() << text);
1441 else
1442 ttsEngine->say(text);
1443 }
1444
setLastTrades10MinVolume(double val)1445 void QtBitcoinTrader::setLastTrades10MinVolume(double val)
1446 {
1447 ui.tradesVolume5m->setValue(val);
1448 }
1449
availableAmountChanged(const QString & symbol,double val)1450 void QtBitcoinTrader::availableAmountChanged(const QString& symbol, double val)
1451 {
1452 if (baseValues.currentPair.symbolSecond() == symbol)
1453 availableAmount = val;
1454 }
1455
addLastTrades(const QString & symbol,QList<TradesItem> * newItems)1456 void QtBitcoinTrader::addLastTrades(const QString& symbol, QList<TradesItem>* newItems)
1457 {
1458 if (secondTimer.isNull())
1459 {
1460 delete newItems;
1461 return;
1462 }
1463
1464 if (baseValues.currentPair.symbol != symbol)
1465 {
1466 delete newItems;
1467 return;
1468 }
1469
1470 int newRowsCount = newItems->size();
1471 tradesModel->addNewTrades(newItems);
1472
1473 tradesModel->updateTotalBTC();
1474
1475 if (ui.tradesAutoScrollCheck->isChecked() && ui.tabLastTrades->isVisible())
1476 {
1477 setTradesScrollBarValue(ui.tableTrades->verticalScrollBar()->value() + defaultHeightForRow * newRowsCount);
1478 tabTradesScrollUp();
1479 }
1480
1481 ui.tableTrades->resizeColumnToContents(1);
1482 ui.tableTrades->resizeColumnToContents(2);
1483 ui.tableTrades->resizeColumnToContents(3);
1484 ui.tableTrades->resizeColumnToContents(4);
1485 ui.tableTrades->resizeColumnToContents(5);
1486 ui.tableTrades->resizeColumnToContents(6);
1487 }
1488
clearTimeOutedTrades()1489 void QtBitcoinTrader::clearTimeOutedTrades()
1490 {
1491 if (secondTimer.isNull())
1492 return;
1493
1494 if (tradesModel->rowCount() == 0)
1495 return;
1496
1497 int lastSliderValue = ui.tableTrades->verticalScrollBar()->value();
1498 tradesModel->removeDataOlderThen(TimeSync::getTimeT() - 600);
1499 ui.tableTrades->verticalScrollBar()->setValue(qMin(lastSliderValue, ui.tableTrades->verticalScrollBar()->maximum()));
1500 }
1501
depthRequested()1502 void QtBitcoinTrader::depthRequested()
1503 {
1504 depthLagTime.restart();
1505 waitingDepthLag = true;
1506 }
1507
depthRequestReceived()1508 void QtBitcoinTrader::depthRequestReceived()
1509 {
1510 waitingDepthLag = false;
1511 }
1512
secondSlot()1513 void QtBitcoinTrader::secondSlot()
1514 {
1515 while (pendingGroupStates.size() && pendingGroupStates.first().elapsed.elapsed() >= 100)
1516 {
1517 setGroupState(pendingGroupStates.first().name, pendingGroupStates.first().enabled);
1518 pendingGroupStates.removeFirst();
1519 }
1520
1521 static int execCount = 0;
1522
1523 if (execCount == 0 || execCount == 2 || execCount == 4)
1524 {
1525 clearTimeOutedTrades();
1526 setSoftLagValue(softLagTime.elapsed());
1527 }
1528 else if (execCount == 1 || execCount == 3 || execCount == 5)
1529 {
1530 int currentElapsed = depthLagTime.elapsed();
1531
1532 if (ui.tabDepth->isVisible())
1533 ui.depthLag->setValue(currentElapsed / 1000.0);
1534 }
1535
1536 if (historyForceUpdate.elapsed() >= 15000)
1537 {
1538 historyForceUpdate.restart();
1539 emit getHistory(true);
1540 }
1541
1542 if (speedTestTime.elapsed() >= 500)
1543 {
1544 speedTestTime.restart();
1545
1546 static QList<double> halfSecondsList;
1547 halfSecondsList << static_cast<double>(baseValues.trafficSpeed / 512.0);
1548 baseValues.trafficTotal += baseValues.trafficSpeed;
1549 updateTrafficTotalValue();
1550
1551 while (halfSecondsList.size() > 10)
1552 halfSecondsList.removeFirst();
1553
1554 static double avSpeed;
1555 avSpeed = 0.0;
1556
1557 for (int n = 0; n < halfSecondsList.size(); n++)
1558 avSpeed += halfSecondsList.at(n);
1559
1560 if (halfSecondsList.size())
1561 avSpeed = avSpeed * 2.0 / halfSecondsList.size();
1562
1563 ui.trafficSpeed->setValue(avSpeed);
1564 baseValues.trafficSpeed = 0;
1565 }
1566
1567 if (++execCount > 5)
1568 execCount = 0;
1569
1570 secondTimer->start(baseValues.uiUpdateInterval);
1571 }
1572
depthVisibilityChanged(bool visible)1573 void QtBitcoinTrader::depthVisibilityChanged(bool visible)
1574 {
1575 if (currentExchange)
1576 currentExchange->depthEnabledFlag = visible || depthAsksModel->rowCount() == 0 || depthBidsModel->rowCount() == 0;
1577 }
1578
trafficTotalToZero_clicked()1579 void QtBitcoinTrader::trafficTotalToZero_clicked()
1580 {
1581 baseValues.trafficTotal = 0;
1582 updateTrafficTotalValue();
1583 }
1584
updateTrafficTotalValue()1585 void QtBitcoinTrader::updateTrafficTotalValue()
1586 {
1587 static int trafficTotalTypeLast = -1;
1588
1589 if (baseValues.trafficTotal > 1073741824) //Gb
1590 baseValues.trafficTotalType = 2;
1591 else if (baseValues.trafficTotal > 1048576) //Mb
1592 baseValues.trafficTotalType = 1;
1593 else if (baseValues.trafficTotal > 1024) //Kb
1594 baseValues.trafficTotalType = 0;
1595
1596 if (trafficTotalTypeLast != baseValues.trafficTotalType)
1597 {
1598 trafficTotalTypeLast = baseValues.trafficTotalType;
1599
1600 switch (trafficTotalTypeLast)
1601 {
1602 case 0:
1603 networkMenu->setSuffix(" Kb");
1604 break;
1605
1606 case 1:
1607 networkMenu->setSuffix(" Mb");
1608 break;
1609
1610 case 2:
1611 networkMenu->setSuffix(" Gb");
1612 break;
1613
1614 default:
1615 break;
1616 }
1617 }
1618
1619 static int totalValueLast = -1;
1620 int totalValue = 0;
1621
1622 switch (trafficTotalTypeLast)
1623 {
1624 case 0:
1625 totalValue = static_cast<int>(baseValues.trafficTotal / 1024);
1626 break;
1627
1628 case 1:
1629 totalValue = static_cast<int>(baseValues.trafficTotal / 1048576);
1630 break;
1631
1632 case 2:
1633 totalValue = static_cast<int>(baseValues.trafficTotal / 1073741824);
1634 break;
1635
1636 default:
1637 break;
1638 }
1639
1640 if (totalValueLast != totalValue)
1641 {
1642 totalValueLast = totalValue;
1643
1644 if (networkMenu->getNetworkTotalMaximum() < totalValue)
1645 networkMenu->setNetworkTotalMaximum(totalValue * 10);
1646
1647 networkMenu->setNetworkTotal(totalValue);
1648 }
1649 }
1650
tabTradesScrollUp()1651 void QtBitcoinTrader::tabTradesScrollUp()
1652 {
1653 if (secondTimer.isNull())
1654 return;
1655
1656 static QTimeLine timeLine(1, this);
1657
1658 if (timeLine.duration() == 1)
1659 {
1660 connect(&timeLine, SIGNAL(frameChanged(int)), this, SLOT(setTradesScrollBarValue(int)));
1661 timeLine.setDuration(500);
1662 timeLine.setEasingCurve(QEasingCurve::OutCirc);
1663 timeLine.setLoopCount(1);
1664 }
1665
1666 timeLine.stop();
1667 int currentScrollPos = ui.tableTrades->verticalScrollBar()->value();
1668
1669 if (currentScrollPos == 0)
1670 return;
1671
1672 timeLine.setFrameRange(currentScrollPos, 0);
1673 timeLine.start();
1674 }
1675
tabTradesIndexChanged(int)1676 void QtBitcoinTrader::tabTradesIndexChanged(int)
1677 {
1678 if (ui.tabLastTrades->isVisible() && ui.tradesAutoScrollCheck->isChecked())
1679 tabTradesScrollUp();
1680 }
1681
setTradesScrollBarValue(int val)1682 void QtBitcoinTrader::setTradesScrollBarValue(int val)
1683 {
1684 if (secondTimer.isNull())
1685 return;
1686
1687 if (val > ui.tableTrades->verticalScrollBar()->maximum())
1688 tabTradesScrollUp();
1689 else
1690 ui.tableTrades->verticalScrollBar()->setValue(val);
1691
1692 //ui.tableTrades->verticalScrollBar()->setValue(qMin(val,ui.tableTrades->verticalScrollBar()->maximum()));
1693 }
1694
fixAllCurrencyLabels(QWidget * par)1695 void QtBitcoinTrader::fixAllCurrencyLabels(QWidget* par)
1696 {
1697 for (QLabel* label : par->findChildren<QLabel*>())
1698 if (label->accessibleDescription() == "USD_ICON" || label->accessibleDescription() == "BTC_ICON")
1699 {
1700 label->setMaximumSize(20, 20);
1701 label->setScaledContents(true);
1702 }
1703 }
1704
fillAllUsdLabels(QWidget * par,QString curName)1705 void QtBitcoinTrader::fillAllUsdLabels(QWidget* par, QString curName)
1706 {
1707 curName = curName.toUpper();
1708 QPixmap btcPixmap;
1709 currencySignLoader->getCurrencySign(curName, btcPixmap);
1710
1711 for (QLabel* labels : par->findChildren<QLabel*>())
1712 if (labels->accessibleDescription() == "USD_ICON")
1713 {
1714 labels->setPixmap(btcPixmap);
1715 labels->setToolTip(curName);
1716 }
1717 }
fillAllBtcLabels(QWidget * par,QString curName)1718 void QtBitcoinTrader::fillAllBtcLabels(QWidget* par, QString curName)
1719 {
1720 curName = curName.toUpper();
1721 QPixmap btcPixmap;
1722 currencySignLoader->getCurrencySign(curName, btcPixmap);
1723
1724 for (QLabel* labels : par->findChildren<QLabel*>())
1725 {
1726 if (labels->accessibleDescription() == "BTC_ICON")
1727 {
1728 labels->setPixmap(btcPixmap);
1729 labels->setToolTip(curName);
1730 }
1731 else if (labels->accessibleDescription() == "DONATE_BTC_ICON")
1732 {
1733 if (labels->toolTip() != "BTC")
1734 {
1735 QPixmap btcPixmapBTC;
1736 currencySignLoader->getCurrencySign("BTC", btcPixmapBTC);
1737 labels->setPixmap(btcPixmapBTC);
1738 labels->setToolTip("BTC");
1739 }
1740 }
1741 }
1742 }
1743
makeRitchValue(QString * text)1744 void QtBitcoinTrader::makeRitchValue(QString* text)
1745 {
1746 int lastSymbol = text->length() - 1;
1747
1748 if (lastSymbol == -1)
1749 return;
1750
1751 while (lastSymbol > -1 && text->at(lastSymbol) == '0')
1752 lastSymbol--;
1753
1754 if (lastSymbol > -1 && text->at(lastSymbol) == '.')
1755 lastSymbol--;
1756
1757 if (lastSymbol < -1)
1758 return;
1759
1760 QString buff = text->left(lastSymbol + 1);
1761 text->remove(0, lastSymbol + 1);
1762 text->prepend("<font color=gray>");
1763 text->append("</font>");
1764 text->prepend(buff);
1765 }
1766
reloadLanguage(const QString & preferedLangFile)1767 void QtBitcoinTrader::reloadLanguage(const QString& preferedLangFile)
1768 {
1769 constructorFinished = false;
1770
1771 QString preferedLangFilePath = (preferedLangFile.isEmpty() || !QFile::exists(preferedLangFile)) ? julyTranslator.lastFile() : preferedLangFile;
1772
1773 julyTranslator.loadFromFile(preferedLangFilePath);
1774 constructorFinished = true;
1775
1776 languageChanged();
1777 }
1778
fixAllChildButtonsAndLabels(QWidget * par)1779 void QtBitcoinTrader::fixAllChildButtonsAndLabels(QWidget* par)
1780 {
1781 for (QPushButton* pushButtons : par->findChildren<QPushButton*>())
1782 if (!pushButtons->text().isEmpty())
1783 pushButtons->setMinimumWidth(qMin(pushButtons->maximumWidth(), textFontWidth(pushButtons->text()) + 10));
1784
1785 for (QToolButton* toolButtons : par->findChildren<QToolButton*>())
1786 if (!toolButtons->text().isEmpty())
1787 toolButtons->setMinimumWidth(toolButtons->minimumSizeHint().width());
1788
1789 for (QCheckBox* checkBoxes : par->findChildren<QCheckBox*>())
1790 checkBoxes->setMinimumWidth(qMin(checkBoxes->maximumWidth(), textFontWidth(checkBoxes->text()) + 20));
1791
1792 for (QLabel* labels : par->findChildren<QLabel*>())
1793 if (labels->text().length() && labels->text().at(0) != '<' && labels->accessibleDescription() != "IGNORED")
1794 labels->setMinimumWidth(qMin(labels->maximumWidth(), textFontWidth(labels->text())));
1795
1796 fixDecimals(this);
1797
1798 for (QWidget* widget : par->findChildren<QWidget*>())
1799 {
1800 if (widget->accessibleName() == "LOGOBUTTON")
1801 {
1802 QLayout* layout = widget->layout();
1803
1804 if (layout == nullptr)
1805 {
1806 layout = new QGridLayout();
1807 layout->setContentsMargins(0, 0, 0, 0);
1808 layout->setSpacing(0);
1809 widget->setLayout(layout);
1810 LogoButton* logoButton = new LogoButton(false);
1811 connect(this, SIGNAL(themeChanged()), logoButton, SLOT(themeChanged()));
1812 layout->addWidget(logoButton);
1813 }
1814 }
1815 }
1816
1817 if (par == this)
1818 return;
1819
1820 QSize minSizeHint = par->minimumSizeHint();
1821
1822 if (isValidSize(&minSizeHint))
1823 {
1824 par->setMinimumSize(par->minimumSizeHint());
1825
1826 if (par->width() < par->minimumSizeHint().width())
1827 par->resize(par->minimumSizeHint().width(), par->height());
1828 }
1829 }
1830
fixDecimals(QWidget * par)1831 void QtBitcoinTrader::fixDecimals(QWidget* par)
1832 {
1833 for (QDoubleSpinBox* spinBox : par->findChildren<QDoubleSpinBox*>())
1834 {
1835 if (!spinBox->whatsThis().isEmpty())
1836 continue;
1837
1838 if (spinBox->accessibleName().startsWith("BTC"))
1839 {
1840 if (spinBox->accessibleName().endsWith("BALANCE"))
1841 spinBox->setDecimals(baseValues.currentPair.currABalanceDecimals);
1842 else
1843 spinBox->setDecimals(baseValues.currentPair.currADecimals);
1844
1845 if (spinBox->accessibleDescription() != "CAN_BE_ZERO")
1846 spinBox->setMinimum(baseValues.currentPair.tradeVolumeMin);
1847 }
1848 else if (spinBox->accessibleName().startsWith("USD"))
1849 {
1850 if (spinBox->accessibleName().endsWith("BALANCE"))
1851 spinBox->setDecimals(baseValues.currentPair.currBBalanceDecimals);
1852 else
1853 spinBox->setDecimals(baseValues.currentPair.currBDecimals);
1854 }
1855 else if (spinBox->accessibleName() == "PRICE")
1856 {
1857 spinBox->setDecimals(baseValues.currentPair.priceDecimals);
1858
1859 if (spinBox->accessibleDescription() != "CAN_BE_ZERO")
1860 spinBox->setMinimum(baseValues.currentPair.tradePriceMin);
1861 }
1862 }
1863 }
1864
loginChanged(const QString & text)1865 void QtBitcoinTrader::loginChanged(const QString& text)
1866 {
1867 const QString& profileNameText = text.compare(QLatin1String(" ")) ? text : profileName;
1868 ui.accountLoginLabel->setText(profileNameText);
1869 ui.accountLoginLabel->setMinimumWidth(textFontWidth(profileNameText) + 20);
1870 }
1871
setCurrencyPairsList()1872 void QtBitcoinTrader::setCurrencyPairsList()
1873 {
1874 baseValues.currencyPairMap.clear();
1875 QString savedCurrency = iniSettings->value("Profile/Currency", "BTC/USD").toString();
1876 int indexCurrency = 0;
1877 QStringList currencyItems;
1878 QStringList filterItems;
1879
1880 for (int n = 0; n < IniEngine::getPairsCount(); n++)
1881 {
1882 CurrencyPairItem pairItem = IniEngine::getPairs()->at(n);
1883
1884 if (pairItem.currRequestSecond.isEmpty())
1885 baseValues.currencyPairMap[pairItem.symbol] = pairItem;
1886 else
1887 {
1888 baseValues.currencyPairMap[pairItem.symbol + pairItem.currRequestSecond.toUpper()] = pairItem;
1889
1890 if (pairItem.currRequestSecond == "exchange")
1891 {
1892 baseValues.currencyPairMap[pairItem.symbol] = pairItem;
1893 filterItems << pairItem.currAStr + "/" + pairItem.currBStr;
1894 }
1895 }
1896
1897 if (pairItem.name == savedCurrency)
1898 indexCurrency = n;
1899
1900 currencyItems << pairItem.name;
1901 }
1902
1903 currencyMenu->setPairs(currencyItems);
1904 currencyMenu->setCurrentIndex(indexCurrency);
1905
1906 ui.filterOrdersCurrency->clear();
1907 ui.filterOrdersCurrency->insertItems(0, filterItems.isEmpty() ? currencyItems : filterItems);
1908 ui.filterOrdersCurrency->setCurrentIndex(0);
1909 }
1910
currencyMenuChanged(int val)1911 void QtBitcoinTrader::currencyMenuChanged(int val)
1912 {
1913 if (!constructorFinished || val < 0 || IniEngine::getPairsCount() != currencyMenu->count())
1914 return;
1915
1916 /*bool fastChange = ui.currencyComboBox->itemText(val).left(5) ==
1917 ui.currencyComboBox->itemText(lastLoadedCurrency).left(5);
1918 if (val == lastLoadedCurrency)
1919 return;
1920 lastLoadedCurrency = val;*/
1921
1922 CurrencyPairItem nextCurrencyPair = IniEngine::getPairs()->at(val);
1923
1924 bool currencyAChanged = nextCurrencyPair.currAStr != baseValues.currentPair.currAStr;
1925 bool currencyBChanged = nextCurrencyPair.currBStr != baseValues.currentPair.currBStr;
1926
1927 /*if (fastChange)
1928 {
1929 baseValues.currentPair = nextCurrencyPair;
1930
1931 setSpinValue(ui.accountBTC, 0.0);
1932 setSpinValue(ui.accountUSD, 0.0);
1933
1934 for (RuleWidget* currentGroup: ui.tabRules->findChildren<RuleWidget*>())
1935 currentGroup->currencyChanged();
1936
1937 for (ScriptWidget* currentGroup: ui.tabRules->findChildren<ScriptWidget*>())
1938 currentGroup->currencyChanged();
1939
1940 return;
1941 }*/
1942
1943 fillAllUsdLabels(this, nextCurrencyPair.currBStr);
1944 fillAllBtcLabels(this, nextCurrencyPair.currAStr);
1945
1946 // TODO: ?? fillAll Usd/Btc for float
1947
1948 iniSettings->setValue("Profile/Currency", ui.currencyMenuTool->text());
1949
1950 if (currencyAChanged)
1951 setSpinValue(ui.accountBTC, 0.0);
1952
1953 if (currencyBChanged)
1954 setSpinValue(ui.accountUSD, 0.0);
1955
1956 buyTotalSpend->setValue(0.0);
1957 sellTotalBtc->setValue(0.0);
1958 ui.tradesVolume5m->setValue(0.0);
1959 setSpinValue(ui.ruleAmountToReceiveValue, 0.0);
1960 setSpinValue(ui.ruleTotalToBuyValue, 0.0);
1961 setSpinValue(ui.ruleAmountToReceiveBSValue, 0.0);
1962 setSpinValue(ui.ruleTotalToBuyBSValue, 0.0);
1963
1964 precentBidsChanged(0.0);
1965 tradesModel->clear();
1966 tradesPrecentLast = 0.0;
1967
1968 QString buyGroupboxText = julyTr("GROUPBOX_BUY", "Buy %1");
1969 bool buyGroupboxCase = false;
1970
1971 if (buyGroupboxText.length() > 2)
1972 buyGroupboxCase = buyGroupboxText.at(2).isUpper();
1973
1974 if (buyGroupboxCase)
1975 buyGroupboxText = buyGroupboxText.arg(nextCurrencyPair.currAName.toUpper());
1976 else
1977 buyGroupboxText = buyGroupboxText.arg(nextCurrencyPair.currAName);
1978
1979 ui.widgetBuy->parentWidget()->setWindowTitle(buyGroupboxText);
1980
1981 QString sellGroupboxText = julyTr("GROUPBOX_SELL", "Sell %1");
1982 bool sellGroupboxCase = true;
1983
1984 if (sellGroupboxText.length() > 2)
1985 sellGroupboxCase = sellGroupboxText.at(2).isUpper();
1986
1987 if (sellGroupboxCase)
1988 sellGroupboxText = sellGroupboxText.arg(nextCurrencyPair.currAName.toUpper());
1989 else
1990 sellGroupboxText = sellGroupboxText.arg(nextCurrencyPair.currAName);
1991
1992 ui.widgetSell->parentWidget()->setWindowTitle(sellGroupboxText);
1993
1994 static int firstLoad = 0;
1995
1996 if (++firstLoad > 1)
1997 {
1998 firstLoad = 3;
1999 emit clearValues();
2000 }
2001
2002 if (ui.comboBoxGroupByPrice->count() > 1)
2003 {
2004 ui.comboBoxGroupByPrice->blockSignals(true);
2005 ui.comboBoxGroupByPrice->clear();
2006 ui.comboBoxGroupByPrice->blockSignals(false);
2007 ui.comboBoxGroupByPrice->addItem(julyTr("DONT_GROUP", "None"), double(0));
2008 }
2009
2010 marketPricesNotLoaded = true;
2011 balanceNotLoaded = true;
2012 fixDecimals(this);
2013
2014 iniSettings->sync();
2015
2016 baseValues.currentPair = nextCurrencyPair;
2017 depthAsksModel->fixTitleWidths();
2018 depthBidsModel->fixTitleWidths();
2019
2020 setSpinValue(ui.ordersLastBuyPrice, 0.0);
2021 setSpinValue(ui.ordersLastSellPrice, 0.0);
2022
2023 if (currentExchange->clearHistoryOnCurrencyChanged)
2024 historyModel->clear();
2025 else
2026 historyModel->loadLastPrice();
2027
2028 calcOrdersTotalValues();
2029
2030 ui.filterOrdersCurrency->setCurrentIndex(val);
2031
2032 currencyChangedDate = TimeSync::getTimeT();
2033
2034 fixDecimals(this);
2035
2036 emit getHistory(true);
2037 emit clearCharts();
2038 chartsView->clearCharts();
2039
2040 setSpinValue(ui.marketHigh, IndicatorEngine::getValue(baseValues.exchangeName +
2041 '_' + baseValues.currentPair.symbol + "_High"));
2042 setSpinValue(ui.marketLow, IndicatorEngine::getValue(baseValues.exchangeName +
2043 '_' + baseValues.currentPair.symbol + "_Low"));
2044 setSpinValue(ui.marketLast, IndicatorEngine::getValue(baseValues.exchangeName +
2045 '_' + baseValues.currentPair.symbol + "_Last"));
2046 setSpinValue(ui.marketVolume, IndicatorEngine::getValue(baseValues.exchangeName +
2047 '_' + baseValues.currentPair.symbol + "_Volume"));
2048 setSpinValue(ui.marketAsk, IndicatorEngine::getValue(baseValues.exchangeName +
2049 '_' + baseValues.currentPair.symbol + "_Buy"));
2050 setSpinValue(ui.marketBid, IndicatorEngine::getValue(baseValues.exchangeName +
2051 '_' + baseValues.currentPair.symbol + "_Sell"));
2052
2053 if (qFuzzyIsNull(ui.marketAsk->value()))
2054 buyPricePerCoin->setValue(100.0);
2055 else
2056 buyPricePerCoin->setValue(ui.marketAsk->value());
2057
2058 if (qFuzzyIsNull(ui.marketBid->value()))
2059 sellPricePerCoin->setValue(200.0);
2060 else
2061 sellPricePerCoin->setValue(ui.marketBid->value());
2062 }
2063
clearDepth()2064 void QtBitcoinTrader::clearDepth()
2065 {
2066 depthAsksModel->clear();
2067 depthBidsModel->clear();
2068 emit reloadDepth();
2069 }
2070
volumeAmountChanged(double volumeTotal,double amountTotal)2071 void QtBitcoinTrader::volumeAmountChanged(double volumeTotal, double amountTotal)
2072 {
2073 setSpinValue(ui.ordersTotalBTC, volumeTotal);
2074 setSpinValue(ui.ordersTotalUSD, amountTotal);
2075 }
2076
calcOrdersTotalValues()2077 void QtBitcoinTrader::calcOrdersTotalValues()
2078 {
2079 checkValidBuyButtons();
2080 checkValidSellButtons();
2081 }
2082
profitSellThanBuyCalc()2083 void QtBitcoinTrader::profitSellThanBuyCalc()
2084 {
2085 if (!profitSellThanBuyUnlocked)
2086 return;
2087
2088 profitSellThanBuyUnlocked = false;
2089 double calcValue = 0.0;
2090
2091 if (sellTotalBtc->value() != 0.0 && ui.buyTotalBtcResult->value() != 0.0)
2092 calcValue = ui.buyTotalBtcResult->value() - sellTotalBtc->value();
2093
2094 sellThanBuySpinBox->setValue(calcValue);
2095 profitSellThanBuyUnlocked = true;
2096 }
2097
profitBuyThanSellCalc()2098 void QtBitcoinTrader::profitBuyThanSellCalc()
2099 {
2100 if (!profitBuyThanSellUnlocked)
2101 return;
2102
2103 profitBuyThanSellUnlocked = false;
2104 double calcValue = 0.0;
2105
2106 if (buyTotalSpend->value() != 0.0 && sellAmountToReceive->value() != 0.0)
2107 calcValue = sellAmountToReceive->value() - buyTotalSpend->value();
2108
2109 profitLossSpinBox->setValue(calcValue);
2110 profitBuyThanSellUnlocked = true;
2111 }
2112
profitLossSpinBoxPrec_valueChanged(double val)2113 void QtBitcoinTrader::profitLossSpinBoxPrec_valueChanged(double val)
2114 {
2115 if (profitBuyThanSellChangedUnlocked)
2116 {
2117 profitBuyThanSellChangedUnlocked = false;
2118 profitLossSpinBox->setValue(val == 0.0 ? 0.0 : buyTotalSpend->value()*val / 100.0);
2119 profitBuyThanSellChangedUnlocked = true;
2120 }
2121 }
2122
profitLossSpinBox_valueChanged(double val)2123 void QtBitcoinTrader::profitLossSpinBox_valueChanged(double val)
2124 {
2125 QString styleChanged;
2126
2127 if (val < -0.009)
2128 styleChanged = "QDoubleSpinBox {background: " + baseValues.appTheme.lightRed.name() + ";}";
2129 else if (val > 0.009)
2130 styleChanged = "QDoubleSpinBox {background: " + baseValues.appTheme.lightGreen.name() + ";}";
2131
2132 if (profitBuyThanSellChangedUnlocked)
2133 {
2134 profitBuyThanSellChangedUnlocked = false;
2135 profitLossSpinBoxPrec->setValue(buyTotalSpend->value() == 0.0 ? 0.0 : val * 100.0 / buyTotalSpend->value());
2136 profitBuyThanSellChangedUnlocked = true;
2137 }
2138
2139 profitLossSpinBox->setStyleSheet(styleChanged);
2140 profitLossSpinBoxPrec->setStyleSheet(styleChanged);
2141
2142 ui.buttonBuyThenSellApply->setEnabled(true);
2143 }
2144
sellThanBuySpinBoxPrec_valueChanged(double val)2145 void QtBitcoinTrader::sellThanBuySpinBoxPrec_valueChanged(double val)
2146 {
2147 if (profitBuyThanSellChangedUnlocked)
2148 {
2149 profitBuyThanSellChangedUnlocked = false;
2150 sellThanBuySpinBox->setValue(val == 0.0 ? 0.0 : sellTotalBtc->value()*val / 100.0);
2151 profitBuyThanSellChangedUnlocked = true;
2152 }
2153 }
2154
sellThanBuySpinBox_valueChanged(double val)2155 void QtBitcoinTrader::sellThanBuySpinBox_valueChanged(double val)
2156 {
2157 QString styleChanged;
2158
2159 if (val < -0.009)
2160 styleChanged = "QDoubleSpinBox {background: " + baseValues.appTheme.lightRed.name() + ";}";
2161 else if (val > 0.009)
2162 styleChanged = "QDoubleSpinBox {background: " + baseValues.appTheme.lightGreen.name() + ";}";
2163
2164 if (profitBuyThanSellChangedUnlocked)
2165 {
2166 profitBuyThanSellChangedUnlocked = false;
2167 sellThanBuySpinBoxPrec->setValue(sellTotalBtc->value() == 0.0 ? 0.0 : val * 100.0 / sellTotalBtc->value());
2168 profitBuyThanSellChangedUnlocked = true;
2169 }
2170
2171 sellThanBuySpinBox->setStyleSheet(styleChanged);
2172 sellThanBuySpinBoxPrec->setStyleSheet(styleChanged);
2173
2174 ui.buttonSellThenBuyApply->setEnabled(true);
2175 }
2176
on_zeroSellThanBuyProfit_clicked()2177 void QtBitcoinTrader::on_zeroSellThanBuyProfit_clicked()
2178 {
2179 sellThanBuySpinBox->setValue(0.0);
2180 }
2181
on_zeroBuyThanSellProfit_clicked()2182 void QtBitcoinTrader::on_zeroBuyThanSellProfit_clicked()
2183 {
2184 profitLossSpinBox->setValue(0.0);
2185 }
2186
profitSellThanBuy()2187 void QtBitcoinTrader::profitSellThanBuy()
2188 {
2189 profitSellThanBuyUnlocked = false;
2190 buyTotalSpend->setValue(sellAmountToReceive->value());
2191 buyPricePerCoin->setValue(buyTotalSpend->value() / ((sellTotalBtc->value() + sellThanBuySpinBox->value()) /
2192 floatFeeDec) - baseValues.currentPair.priceMin);
2193 profitSellThanBuyUnlocked = true;
2194 profitBuyThanSellCalc();
2195 profitSellThanBuyCalc();
2196 ui.buttonSellThenBuyApply->setEnabled(false);
2197 }
2198
profitBuyThanSell()2199 void QtBitcoinTrader::profitBuyThanSell()
2200 {
2201 profitBuyThanSellUnlocked = false;
2202 sellTotalBtc->setValue(ui.buyTotalBtcResult->value());
2203 sellPricePerCoin->setValue((buyTotalSpend->value() + profitLossSpinBox->value()) /
2204 (sellTotalBtc->value()*floatFeeDec) + baseValues.currentPair.priceMin);
2205 profitBuyThanSellUnlocked = true;
2206 profitBuyThanSellCalc();
2207 profitSellThanBuyCalc();
2208 ui.buttonBuyThenSellApply->setEnabled(false);
2209 }
2210
setApiDown(bool)2211 void QtBitcoinTrader::setApiDown(bool)
2212 {
2213 //ui.exchangeLagBack->setVisible(on);
2214 }
2215
clearData(QString data)2216 QString QtBitcoinTrader::clearData(QString data)
2217 {
2218 while (data.size() && (data.at(0) == '{' || data.at(0) == '[' || data.at(0) == '\"'))
2219 data.remove(0, 1);
2220
2221 while (data.size() && (data.at(data.length() - 1) == '}' || data.at(data.length() - 1) == ']' ||
2222 data.at(data.length() - 1) == '\"'))
2223 data.remove(data.length() - 1, 1);
2224
2225 return data;
2226 }
2227
on_accountFee_valueChanged(double val)2228 void QtBitcoinTrader::on_accountFee_valueChanged(double val)
2229 {
2230 floatFee = val / 100.0;
2231 floatFeeDec = 1.0 - floatFee;
2232 floatFeeInc = 1.0 + floatFee;
2233
2234 if (currentExchange && !currentExchange->supportsExchangeFee)
2235 iniSettings->setValue("Profile/CustomFee", ui.accountFee->value());
2236
2237 bool notZeroFee = floatFee > 0.0;
2238 ui.calcButton->setVisible(notZeroFee);
2239 ui.label_6->setVisible(notZeroFee);
2240 ui.label_10->setVisible(notZeroFee);
2241 ui.label_28->setVisible(notZeroFee);
2242 ui.label_29->setVisible(notZeroFee);
2243 ui.buyNextInSellPrice->setVisible(notZeroFee);
2244 ui.buyNextMinBuyStep->setVisible(notZeroFee);
2245 ui.sellNextMaxBuyPrice->setVisible(notZeroFee);
2246 ui.sellNextMaxBuyStep->setVisible(notZeroFee);
2247 ui.usdLabel9->setVisible(notZeroFee);
2248 ui.usdLabel10->setVisible(notZeroFee);
2249 ui.usdLabel13->setVisible(notZeroFee);
2250 ui.usdLabel14->setVisible(notZeroFee);
2251 ui.buyTotalBtcResult->setVisible(notZeroFee);
2252 ui.btcLabel6->setVisible(notZeroFee);
2253 ui.label_62->setVisible(notZeroFee);
2254 }
2255
getMidData(const QString & a,QString b,QByteArray * data)2256 QByteArray QtBitcoinTrader::getMidData(const QString& a, QString b, QByteArray* data)
2257 {
2258 QByteArray rez;
2259
2260 if (b.isEmpty())
2261 b = "\",";
2262
2263 int startPos = data->indexOf(a, 0);
2264
2265 if (startPos > -1)
2266 {
2267 int endPos = data->indexOf(b, startPos + a.length());
2268
2269 if (endPos > -1)
2270 rez = data->mid(startPos + a.length(), endPos - startPos - a.length());
2271 }
2272
2273 return rez;
2274 }
2275
adjustDockMinSize(QWidget * widget)2276 static void adjustDockMinSize(QWidget* widget)
2277 {
2278 QDockWidget* dock = static_cast<QDockWidget*>(widget->parentWidget());
2279 int minHint = widget->minimumSizeHint().width();
2280 int textWidth = textFontWidth(dock->windowTitle());
2281 static const int TitleExtra = 50; // left padding + undock/close buttons
2282 int minWidth = qMax(minHint, textWidth + TitleExtra);
2283 widget->setMinimumWidth(minWidth);
2284 widget->setMaximumWidth(minWidth + 100);
2285 }
2286
updateLogTable()2287 void QtBitcoinTrader::updateLogTable()
2288 {
2289 emit getHistory(false);
2290 }
2291
balanceChanged(double)2292 void QtBitcoinTrader::balanceChanged(double)
2293 {
2294 calcOrdersTotalValues();
2295 emit getHistory(true);
2296 }
2297
ordersIsAvailable()2298 void QtBitcoinTrader::ordersIsAvailable()
2299 {
2300 if (ui.ordersTableFrame->isVisible())
2301 return;
2302
2303 ui.noOpenedOrdersLabel->setVisible(false);
2304 ui.ordersTableFrame->setVisible(true);
2305 }
2306
ordersIsEmpty()2307 void QtBitcoinTrader::ordersIsEmpty()
2308 {
2309 if (ordersModel->rowCount())
2310 {
2311 if (debugLevel)
2312 logThread->writeLog("Order table cleared");
2313
2314 ordersModel->clear();
2315 setSpinValue(ui.ordersTotalBTC, 0.0);
2316 setSpinValue(ui.ordersTotalUSD, 0.0);
2317 ui.ordersTableFrame->setVisible(false);
2318 ui.noOpenedOrdersLabel->setVisible(true);
2319 }
2320
2321 //calcOrdersTotalValues();
2322 }
2323
orderCanceled(const QString & symbol,QByteArray oid)2324 void QtBitcoinTrader::orderCanceled(const QString& symbol, QByteArray oid)
2325 {
2326 if (debugLevel)
2327 logThread->writeLog("Removed order: " + oid + " " + symbol.toLatin1());
2328
2329 ordersModel->setOrderCanceled(oid);
2330 }
2331
orderBookChanged(const QString & symbol,QList<OrderItem> * orders)2332 void QtBitcoinTrader::orderBookChanged(const QString& symbol, QList<OrderItem>* orders)
2333 {
2334 if (symbol != baseValues.currentPair.symbol)
2335 {
2336 delete orders;
2337 return;
2338 }
2339
2340 currentlyAddingOrders = true;
2341 ordersModel->orderBookChanged(orders);
2342
2343 calcOrdersTotalValues();
2344 checkValidOrdersButtons();
2345
2346 depthAsksModel->reloadVisibleItems();
2347 depthBidsModel->reloadVisibleItems();
2348 currentlyAddingOrders = false;
2349
2350 ui.tableHistory->resizeColumnToContents(0);
2351 ui.tableHistory->resizeColumnToContents(2);
2352 ui.tableHistory->resizeColumnToContents(3);
2353 ui.tableHistory->resizeColumnToContents(4);
2354 ui.tableHistory->resizeColumnToContents(5);
2355 ui.tableHistory->resizeColumnToContents(6);
2356 }
2357
showErrorMessage(const QString & message)2358 void QtBitcoinTrader::showErrorMessage(const QString& message)
2359 {
2360 if (!showingMessage && lastMessageTime.elapsed() > 10000)
2361 {
2362 showingMessage = true;
2363
2364 if (debugLevel)
2365 logThread->writeLog(baseValues.exchangeName.toLatin1() + " Error: " + message.toUtf8(), 2);
2366
2367 lastMessageTime.restart();
2368
2369 if (message.startsWith("I:>"))
2370 identificationRequired(message.right(message.size() - 3));
2371 else
2372 QMessageBox::warning(windowWidget, julyTr("AUTH_ERROR", "%1 Error").arg(baseValues.exchangeName), message);
2373
2374 showingMessage = false;
2375 }
2376 }
2377
identificationRequired(QString message)2378 void QtBitcoinTrader::identificationRequired(QString message)
2379 {
2380 if (!message.isEmpty())
2381 message.prepend("<br><br>");
2382
2383 message.prepend(julyTr("TRUNAUTHORIZED",
2384 "Identification required to access private API.<br>Please enter valid API key and Secret."));
2385
2386 QMessageBox::warning(windowWidget, julyTr("AUTH_ERROR", "%1 Error").arg(baseValues.exchangeName), message);
2387 }
2388
historyChanged(QList<HistoryItem> * historyItems)2389 void QtBitcoinTrader::historyChanged(QList<HistoryItem>* historyItems)
2390 {
2391 historyModel->historyChanged(historyItems);
2392 ui.tableHistory->resizeColumnToContents(1);
2393 ui.tableHistory->resizeColumnToContents(2);
2394 ui.tableHistory->resizeColumnToContents(3);
2395 ui.tableHistory->resizeColumnToContents(4);
2396 ui.tableHistory->resizeColumnToContents(5);
2397
2398 if (debugLevel)
2399 logThread->writeLog("Log Table Updated");
2400 }
2401
accLastSellChanged(const QString & priceCurrency,double val)2402 void QtBitcoinTrader::accLastSellChanged(const QString& priceCurrency, double val)
2403 {
2404 setSpinValue(ui.ordersLastSellPrice, val);
2405
2406 if (ui.usdLabelLastSell->toolTip() != priceCurrency)
2407 {
2408 QPixmap btcPixmap;
2409 currencySignLoader->getCurrencySign(priceCurrency.toUpper(), btcPixmap);
2410 ui.usdLabelLastSell->setPixmap(btcPixmap);
2411 ui.usdLabelLastSell->setToolTip(priceCurrency);
2412 }
2413 }
2414
accLastBuyChanged(const QString & priceCurrency,double val)2415 void QtBitcoinTrader::accLastBuyChanged(const QString& priceCurrency, double val)
2416 {
2417 setSpinValue(ui.ordersLastBuyPrice, val);
2418
2419 if (ui.usdLabelLastBuy->toolTip() != priceCurrency)
2420 {
2421 QPixmap btcPixmap;
2422 currencySignLoader->getCurrencySign(priceCurrency.toUpper(), btcPixmap);
2423 ui.usdLabelLastBuy->setPixmap(btcPixmap);
2424 ui.usdLabelLastBuy->setToolTip(priceCurrency);
2425 }
2426 }
2427
translateUnicodeStr(QString * str)2428 void QtBitcoinTrader::translateUnicodeStr(QString* str)
2429 {
2430 const QRegExp rx("(\\\\u[0-9a-fA-F]{4})");
2431 int pos = 0;
2432
2433 while ((pos = rx.indexIn(*str, pos)) != -1)
2434 str->replace(pos++, 6, QChar(rx.cap(1).right(4).toUShort(nullptr, 16)));
2435 }
2436
cancelOrder(const QString & symbol,const QByteArray & oid)2437 void QtBitcoinTrader::cancelOrder(const QString& symbol, const QByteArray& oid)
2438 {
2439 emit cancelOrderByOid(symbol, oid);
2440 }
2441
on_ordersCancelBidsButton_clicked()2442 void QtBitcoinTrader::on_ordersCancelBidsButton_clicked()
2443 {
2444 QString cancelSymbol;
2445
2446 if (ui.ordersFilterCheckBox->isChecked())
2447 cancelSymbol = IniEngine::getPairSymbol(ui.filterOrdersCurrency->currentIndex());
2448
2449 ordersModel->ordersCancelBids(cancelSymbol);
2450 }
2451
on_ordersCancelAsksButton_clicked()2452 void QtBitcoinTrader::on_ordersCancelAsksButton_clicked()
2453 {
2454 QString cancelSymbol;
2455
2456 if (ui.ordersFilterCheckBox->isChecked())
2457 cancelSymbol = IniEngine::getPairSymbol(ui.filterOrdersCurrency->currentIndex());
2458
2459 ordersModel->ordersCancelAsks(cancelSymbol);
2460 }
2461
on_ordersCancelAllButton_clicked()2462 void QtBitcoinTrader::on_ordersCancelAllButton_clicked()
2463 {
2464 QString cancelSymbol;
2465
2466 if (ui.ordersFilterCheckBox->isChecked())
2467 cancelSymbol = IniEngine::getPairSymbol(ui.filterOrdersCurrency->currentIndex());
2468
2469 ordersModel->ordersCancelAll(cancelSymbol);
2470 }
2471
2472
cancelPairOrders(const QString & symbol)2473 void QtBitcoinTrader::cancelPairOrders(const QString& symbol)
2474 {
2475 ordersModel->ordersCancelAll(symbol);
2476 }
2477
cancelAskOrders(const QString & symbol)2478 void QtBitcoinTrader::cancelAskOrders(const QString& symbol)
2479 {
2480 ordersModel->ordersCancelAsks(symbol);
2481 }
2482
cancelBidOrders(const QString & symbol)2483 void QtBitcoinTrader::cancelBidOrders(const QString& symbol)
2484 {
2485 ordersModel->ordersCancelBids(symbol);
2486 }
2487
cancelAllCurrentPairOrders()2488 void QtBitcoinTrader::cancelAllCurrentPairOrders()
2489 {
2490 cancelPairOrders(baseValues.currentPair.symbol);
2491 }
2492
on_ordersCancelSelected_clicked()2493 void QtBitcoinTrader::on_ordersCancelSelected_clicked()
2494 {
2495 QModelIndexList selectedRows = ui.ordersTable->selectionModel()->selectedRows();
2496
2497 if (selectedRows.size() == 0)
2498 return;
2499
2500 for (int n = 0; n < selectedRows.size(); n++)
2501 {
2502 QByteArray oid = selectedRows.at(n).data(Qt::UserRole).toByteArray();
2503
2504 if (!oid.isEmpty())
2505 cancelOrder(selectedRows.at(n).data(Qt::AccessibleTextRole).toString(), oid);
2506 }
2507 }
2508
cancelOrderByXButton()2509 void QtBitcoinTrader::cancelOrderByXButton()
2510 {
2511 QPushButton* buttonCancel = dynamic_cast<QPushButton*>(sender());
2512
2513 if (!buttonCancel)
2514 return;
2515
2516 QByteArray order = buttonCancel->property("OrderId").toByteArray();
2517
2518 if (!order.isEmpty())
2519 cancelOrder(buttonCancel->property("Symbol").toString(), order);
2520 }
2521
on_buttonNight_clicked()2522 void QtBitcoinTrader::on_buttonNight_clicked()
2523 {
2524 baseValues.currentTheme++;
2525
2526 if (baseValues.currentTheme > 2)
2527 baseValues.currentTheme = 0;
2528
2529 if (baseValues.currentTheme == 1)
2530 {
2531 baseValues.appTheme = baseValues.appThemeDark;
2532 #if QT_VERSION < 0x050000
2533 qApp->setStyle(new QPlastiqueStyle);
2534 #endif
2535 }
2536 else if (baseValues.currentTheme == 2)
2537 {
2538 baseValues.appTheme = baseValues.appThemeGray;
2539 qApp->setStyle(baseValues.osStyle);
2540 }
2541 else if (baseValues.currentTheme == 0)
2542 {
2543 baseValues.appTheme = baseValues.appThemeLight;
2544 qApp->setStyle(baseValues.osStyle);
2545 }
2546
2547 qApp->setPalette(baseValues.appTheme.palette);
2548 qApp->setStyleSheet(baseValues.appTheme.styleSheet);
2549
2550 ui.accountLoginLabel->setStyleSheet("color: " + baseValues.appTheme.black.name() + "; background: " +
2551 baseValues.appTheme.white.name());
2552 ui.noOpenedOrdersLabel->setStyleSheet("font-size:27px; border: 1px solid gray; background: " +
2553 baseValues.appTheme.white.name() + "; color: " + baseValues.appTheme.gray.name());
2554 ui.rulesNoMessage->setStyleSheet("font-size:27px; border: 1px solid gray; background: " +
2555 baseValues.appTheme.white.name() + "; color: " + baseValues.appTheme.gray.name());
2556
2557 ui.buyBitcoinsButton->setStyleSheet("QPushButton {font-size:21px; color: " + baseValues.appTheme.blue.name() +
2558 "} QPushButton::disabled {color: " + baseValues.appTheme.gray.name() + "}");
2559 ui.sellBitcoinsButton->setStyleSheet("QPushButton {font-size:21px; color: " + baseValues.appTheme.red.name() +
2560 "} QPushButton::disabled {color: " + baseValues.appTheme.gray.name() + "}");
2561
2562 profitLossSpinBox_valueChanged(profitLossSpinBox->value());
2563 sellThanBuySpinBox_valueChanged(sellThanBuySpinBox->value());
2564 buyTotalSpend_valueChanged(buyTotalSpend->value());
2565 sellTotalBtc_valueChanged(sellTotalBtc->value());
2566
2567 for (RuleWidget* currentGroup : ui.tabRules->findChildren<RuleWidget*>())
2568 currentGroup->updateStyleSheets();
2569
2570 if (baseValues.currentTheme == 2)
2571 ui.buttonNight->setIcon(QIcon("://Resources/Day.png"));
2572 else if (baseValues.currentTheme == 0)
2573 ui.buttonNight->setIcon(QIcon("://Resources/Night.png"));
2574 else
2575 ui.buttonNight->setIcon(QIcon("://Resources/Gray.png"));
2576
2577 if (swapedDepth)
2578 {
2579 ui.asksLabel->setStyleSheet("color: " + baseValues.appTheme.blue.name());
2580 ui.bidsLabel->setStyleSheet("color: " + baseValues.appTheme.red.name());
2581 }
2582 else
2583 {
2584 ui.asksLabel->setStyleSheet("color: " + baseValues.appTheme.red.name());
2585 ui.bidsLabel->setStyleSheet("color: " + baseValues.appTheme.blue.name());
2586 }
2587
2588 iniSettings->setValue("UI/NightMode", baseValues.currentTheme);
2589
2590 emit themeChanged();
2591
2592 chartsView->setStyleSheet("background: " + baseValues.appTheme.white.name());
2593 chartsView->refreshCharts();
2594
2595 if (baseValues.currentTheme == 1)
2596 ui.widgetLogo->setStyleSheet("background:black");
2597 else
2598 ui.widgetLogo->setStyleSheet("background:white");
2599 }
2600
on_calcButton_clicked()2601 void QtBitcoinTrader::on_calcButton_clicked()
2602 {
2603 if (feeCalculatorSingleInstance && feeCalculator)
2604 feeCalculator->activateWindow();
2605 else
2606 feeCalculator = new FeeCalculator;
2607 }
2608
checkValidSellButtons()2609 void QtBitcoinTrader::checkValidSellButtons()
2610 {
2611 ui.widgetSellThenBuy->setEnabled(sellTotalBtc->value() >= baseValues.currentPair.tradeVolumeMin &&
2612 sellAmountToReceive->value() >= baseValues.currentPair.tradeTotalMin);
2613 ui.sellBitcoinsButton->setEnabled(ui.widgetSellThenBuy->isEnabled() &&
2614 /*ui.sellTotalBtc->value()<=getAvailableBTC()&&*/sellTotalBtc->value() > 0.0);
2615 }
2616
on_sellPricePerCoinAsMarketLastPrice_clicked()2617 void QtBitcoinTrader::on_sellPricePerCoinAsMarketLastPrice_clicked()
2618 {
2619 sellPricePerCoin->setValue(ui.marketLast->value());
2620 }
2621
on_sellTotalBtcAllIn_clicked()2622 void QtBitcoinTrader::on_sellTotalBtcAllIn_clicked()
2623 {
2624 sellTotalBtc->setValue(getAvailableBTC());
2625 }
2626
on_sellTotalBtcHalfIn_clicked()2627 void QtBitcoinTrader::on_sellTotalBtcHalfIn_clicked()
2628 {
2629 sellTotalBtc->setValue(getAvailableBTC() / 2.0);
2630 }
2631
setDataPending(bool on)2632 void QtBitcoinTrader::setDataPending(bool on)
2633 {
2634 isDataPending = on;
2635 }
2636
setSoftLagValue(int mseconds)2637 void QtBitcoinTrader::setSoftLagValue(int mseconds)
2638 {
2639 if (secondTimer.isNull())
2640 return;
2641
2642 if (!isDataPending && mseconds < baseValues.httpRequestTimeout)
2643 mseconds = 0;
2644
2645 static int lastSoftLag = -1;
2646
2647 if (lastSoftLag == mseconds)
2648 return;
2649
2650 ui.lastUpdate->setValue(mseconds / 1000.0);
2651
2652 static bool lastSoftLagValid = true;
2653 isValidSoftLag = mseconds <= baseValues.httpRequestTimeout + baseValues.httpRequestInterval + 200;
2654
2655 if (isValidSoftLag != lastSoftLagValid)
2656 {
2657 lastSoftLagValid = isValidSoftLag;
2658
2659 if (!isValidSoftLag)
2660 ui.lastUpdate->setStyleSheet("QDoubleSpinBox {background: " + baseValues.appTheme.lightRed.name() + ";}");
2661 else
2662 ui.lastUpdate->setStyleSheet("");
2663
2664 calcOrdersTotalValues();
2665 //ui.ordersControls->setEnabled(isValidSoftLag);
2666 //ui.buyButtonBack->setEnabled(isValidSoftLag);
2667 //ui.sellButtonBack->setEnabled(isValidSoftLag);
2668 QString toolTip;
2669
2670 if (!isValidSoftLag)
2671 toolTip = julyTr("TOOLTIP_API_LAG_TO_HIGH", "API Lag is to High");
2672
2673 ui.ordersControls->setToolTip(toolTip);
2674 ui.buyButtonBack->setToolTip(toolTip);
2675 ui.sellButtonBack->setToolTip(toolTip);
2676 }
2677 }
2678
sellTotalBtc_valueChanged(double val)2679 void QtBitcoinTrader::sellTotalBtc_valueChanged(double val)
2680 {
2681 if (val == 0.0)
2682 sellTotalBtc->setStyleSheet("QDoubleSpinBox {background: " + baseValues.appTheme.lightRed.name() + ";}");
2683 else
2684 sellTotalBtc->setStyleSheet("");
2685
2686 profitBuyThanSellCalc();
2687 profitSellThanBuyCalc();
2688
2689 if (sellLockBtcToSell)
2690 return;
2691
2692 sellLockBtcToSell = true;
2693
2694 sellLockAmountToReceive = true;
2695 sellAmountToReceive->setValue(sellPricePerCoin->value()*val * floatFeeDec);
2696
2697 sellLockAmountToReceive = false;
2698
2699 checkValidSellButtons();
2700 sellLockBtcToSell = false;
2701 }
2702
sellPricePerCoin_valueChanged(double)2703 void QtBitcoinTrader::sellPricePerCoin_valueChanged(double)
2704 {
2705 if (!sellLockPricePerCoin)
2706 {
2707 sellLockPricePerCoin = true;
2708 sellTotalBtc_valueChanged(sellTotalBtc->value());
2709 sellLockPricePerCoin = false;
2710 }
2711
2712 ui.sellNextMaxBuyPrice->setValue(sellPricePerCoin->value()*floatFeeDec * floatFeeDec -
2713 baseValues.currentPair.priceMin);
2714 ui.sellNextMaxBuyStep->setValue(sellPricePerCoin->value() - ui.sellNextMaxBuyPrice->value());
2715 checkValidSellButtons();
2716 ui.buttonSellThenBuyApply->setEnabled(true);
2717 profitBuyThanSellCalc();
2718 profitSellThanBuyCalc();
2719 }
2720
sellAmountToReceive_valueChanged(double val)2721 void QtBitcoinTrader::sellAmountToReceive_valueChanged(double val)
2722 {
2723 profitBuyThanSellCalc();
2724 profitSellThanBuyCalc();
2725
2726 if (sellLockAmountToReceive)
2727 return;
2728
2729 sellLockAmountToReceive = true;
2730
2731 sellLockBtcToSell = true;
2732 sellLockPricePerCoin = true;
2733
2734 sellTotalBtc->setValue(val / sellPricePerCoin->value() / floatFeeDec);
2735
2736 sellLockPricePerCoin = false;
2737 sellLockBtcToSell = false;
2738
2739 sellLockAmountToReceive = false;
2740 checkValidSellButtons();
2741 }
2742
sellBitcoinButton()2743 void QtBitcoinTrader::sellBitcoinButton()
2744 {
2745 checkValidSellButtons();
2746
2747 if (ui.sellBitcoinsButton->isEnabled() == false)
2748 return;
2749
2750 double sellTotalBtcV = sellTotalBtc->value();
2751 double sellPricePerCoinV = sellPricePerCoin->value();
2752
2753 if (confirmOpenOrder)
2754 {
2755 QMessageBox msgBox(windowWidget);
2756 msgBox.setIcon(QMessageBox::Question);
2757 msgBox.setWindowTitle(julyTr("MESSAGE_CONFIRM_SELL_TRANSACTION", "Please confirm transaction"));
2758 msgBox.setText(julyTr("MESSAGE_CONFIRM_SELL_TRANSACTION_TEXT",
2759 "Are you sure to sell %1 at %2 ?<br><br>Note: If total orders amount of your Bitcoins exceeds your balance, %3 will remove this order immediately.").arg(
2760 baseValues.currentPair.currASign + " " + JulyMath::textFromDouble(sellTotalBtcV,
2761 baseValues.currentPair.currADecimals)).arg(baseValues.currentPair.currBSign + " " + JulyMath::textFromDouble(sellPricePerCoinV,
2762 baseValues.currentPair.priceDecimals)).arg(baseValues.exchangeName));
2763 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
2764 msgBox.setDefaultButton(QMessageBox::Yes);
2765 msgBox.setButtonText(QMessageBox::Yes, julyTr("YES", "Yes"));
2766 msgBox.setButtonText(QMessageBox::No, julyTr("NO", "No"));
2767
2768 if (msgBox.exec() != QMessageBox::Yes)
2769 return;
2770 }
2771
2772 apiSellSend(baseValues.currentPair.symbolSecond(), sellTotalBtcV, sellPricePerCoinV);
2773 }
2774
buyTotalSpend_valueChanged(double val)2775 void QtBitcoinTrader::buyTotalSpend_valueChanged(double val)
2776 {
2777 if (val == 0.0)
2778 buyTotalSpend->setStyleSheet("QDoubleSpinBox {background: " + baseValues.appTheme.lightRed.name() + ";}");
2779 else
2780 buyTotalSpend->setStyleSheet("");
2781
2782 profitBuyThanSellCalc();
2783 profitSellThanBuyCalc();
2784
2785 buyLockTotalBtc = true;
2786
2787 if (!buyLockTotalBtcSelf)
2788 buyTotalBtc->setValue(val / buyPricePerCoin->value());
2789
2790 buyLockTotalBtc = false;
2791
2792 double valueForResult = val / buyPricePerCoin->value();
2793 valueForResult *= floatFeeDec;
2794 valueForResult = JulyMath::cutDoubleDecimalsCopy(valueForResult, baseValues.currentPair.currADecimals, false);
2795 setSpinValue(ui.buyTotalBtcResult, valueForResult);
2796
2797 checkValidBuyButtons();
2798 }
2799
sendIndicatorEvent(const QString & symbol,const QString & name,double val)2800 void QtBitcoinTrader::sendIndicatorEvent(const QString& symbol, const QString& name, double val)
2801 {
2802 emit indicatorEventSignal(symbol, name, val);
2803 }
2804
buyTotalBtc_valueChanged(double)2805 void QtBitcoinTrader::buyTotalBtc_valueChanged(double)
2806 {
2807 if (buyLockTotalBtc)
2808 {
2809 checkValidBuyButtons();
2810 return;
2811 }
2812
2813 buyLockTotalBtc = true;
2814 buyLockTotalBtcSelf = true;
2815
2816 buyTotalSpend->setValue(buyTotalBtc->value() * buyPricePerCoin->value());
2817 buyLockTotalBtcSelf = false;
2818 buyLockTotalBtc = false;
2819 checkValidBuyButtons();
2820 }
2821
buyPricePerCoin_valueChanged(double)2822 void QtBitcoinTrader::buyPricePerCoin_valueChanged(double)
2823 {
2824 if (!buyLockPricePerCoin)
2825 {
2826 buyLockPricePerCoin = true;
2827 buyTotalSpend_valueChanged(buyTotalSpend->value());
2828 buyLockPricePerCoin = false;
2829 }
2830
2831 ui.buyNextInSellPrice->setValue(buyPricePerCoin->value() * floatFeeInc * floatFeeInc +
2832 baseValues.currentPair.priceMin);
2833 ui.buyNextMinBuyStep->setValue(ui.buyNextInSellPrice->value() - buyPricePerCoin->value());
2834 checkValidBuyButtons();
2835 ui.buttonBuyThenSellApply->setEnabled(true);
2836 profitBuyThanSellCalc();
2837 profitSellThanBuyCalc();
2838 }
2839
checkValidBuyButtons()2840 void QtBitcoinTrader::checkValidBuyButtons()
2841 {
2842 ui.widgetBuyThenSell->setEnabled(buyTotalBtc->value() >= baseValues.currentPair.tradeVolumeMin &&
2843 buyTotalSpend->value() >= baseValues.currentPair.tradeTotalMin);
2844 ui.buyBitcoinsButton->setEnabled(ui.widgetBuyThenSell->isEnabled() &&
2845 /*ui.buyTotalSpend->value()<=getAvailableUSD()&&*/buyTotalSpend->value() > 0.0);
2846 }
2847
checkValidOrdersButtons()2848 void QtBitcoinTrader::checkValidOrdersButtons()
2849 {
2850 ui.ordersCancelAllButton->setEnabled(ordersModel->rowCount());
2851 ui.ordersCancelSelected->setEnabled(ui.ordersTable->selectionModel()->selectedRows().size());
2852 }
2853
on_buyTotalBtcAllIn_clicked()2854 void QtBitcoinTrader::on_buyTotalBtcAllIn_clicked()
2855 {
2856 buyTotalBtc->setValue(getAvailableUSDtoBTC(buyPricePerCoin->value()));
2857 }
2858
on_buyTotalBtcHalfIn_clicked()2859 void QtBitcoinTrader::on_buyTotalBtcHalfIn_clicked()
2860 {
2861 buyTotalBtc->setValue(getAvailableUSDtoBTC(buyPricePerCoin->value()) / 2.0);
2862 }
2863
on_sellPriceAsMarketBid_clicked()2864 void QtBitcoinTrader::on_sellPriceAsMarketBid_clicked()
2865 {
2866 sellPricePerCoin->setValue(ui.marketBid->value());
2867 }
2868
on_buyPriceAsMarketBid_clicked()2869 void QtBitcoinTrader::on_buyPriceAsMarketBid_clicked()
2870 {
2871 buyPricePerCoin->setValue(ui.marketBid->value());
2872 }
2873
on_sellPriceAsMarketAsk_clicked()2874 void QtBitcoinTrader::on_sellPriceAsMarketAsk_clicked()
2875 {
2876 sellPricePerCoin->setValue(ui.marketAsk->value());
2877 }
2878
on_buyPriceAsMarketAsk_clicked()2879 void QtBitcoinTrader::on_buyPriceAsMarketAsk_clicked()
2880 {
2881 buyPricePerCoin->setValue(ui.marketAsk->value());
2882 }
2883
on_buyPriceAsMarketLastPrice_clicked()2884 void QtBitcoinTrader::on_buyPriceAsMarketLastPrice_clicked()
2885 {
2886 buyPricePerCoin->setValue(ui.marketLast->value());
2887 }
2888
hasWorkingRules()2889 bool QtBitcoinTrader::hasWorkingRules()
2890 {
2891 for (RuleWidget* group : ui.tabRules->findChildren<RuleWidget*>())
2892 {
2893 if (group)
2894 {
2895 if (group->haveWorkingRules())
2896 return true;
2897 }
2898 }
2899
2900 for (ScriptWidget* group : ui.tabRules->findChildren<ScriptWidget*>())
2901 {
2902 if (group)
2903 {
2904 if (group->isRunning())
2905 return true;
2906 }
2907 }
2908
2909 return false;
2910 }
2911
buyBitcoinsButton()2912 void QtBitcoinTrader::buyBitcoinsButton()
2913 {
2914 checkValidBuyButtons();
2915
2916 if (ui.buyBitcoinsButton->isEnabled() == false)
2917 return;
2918
2919 double btcToBuy = 0.0;
2920 double priceToBuy = buyPricePerCoin->value();
2921
2922 if (currentExchange->buySellAmountExcludedFee && floatFee != 0.0)
2923 btcToBuy = ui.buyTotalBtcResult->value();
2924 else
2925 btcToBuy = buyTotalBtc->value();
2926
2927 //double amountWithoutFee=getAvailableUSD()/priceToBuy;
2928 //amountWithoutFee=JulyMath::cutDoubleDecimalsCopy(amountWithoutFee,baseValues.currentPair.currADecimals,false);
2929
2930 if (confirmOpenOrder)
2931 {
2932 QMessageBox msgBox(windowWidget);
2933 msgBox.setIcon(QMessageBox::Question);
2934 msgBox.setWindowTitle(julyTr("MESSAGE_CONFIRM_BUY_TRANSACTION", "Please confirm new order"));
2935 msgBox.setText(julyTr("MESSAGE_CONFIRM_BUY_TRANSACTION_TEXT",
2936 "Are you sure to buy %1 at %2 ?<br><br>Note: If total orders amount of your funds exceeds your balance, %3 will remove this order immediately.").arg(
2937 baseValues.currentPair.currASign + " " + JulyMath::textFromDouble(btcToBuy,
2938 baseValues.currentPair.currADecimals)).arg(baseValues.currentPair.currBSign + " " + JulyMath::textFromDouble(priceToBuy,
2939 baseValues.currentPair.priceDecimals)).arg(baseValues.exchangeName));
2940 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
2941 msgBox.setDefaultButton(QMessageBox::Yes);
2942 msgBox.setButtonText(QMessageBox::Yes, julyTr("YES", "Yes"));
2943 msgBox.setButtonText(QMessageBox::No, julyTr("NO", "No"));
2944
2945 if (msgBox.exec() != QMessageBox::Yes)
2946 return;
2947 }
2948
2949 apiBuySend(baseValues.currentPair.symbolSecond(), btcToBuy, priceToBuy);
2950 }
2951
playWav(const QString & wav,bool noBlink)2952 void QtBitcoinTrader::playWav(const QString& wav, bool noBlink)
2953 {
2954 Platform::playSound(wav);
2955
2956 if (!noBlink)
2957 blinkWindow();
2958 }
2959
beep(bool noBlink)2960 void QtBitcoinTrader::beep(bool noBlink)
2961 {
2962 QString fileName = appDataDir + "/Sound/Beep.wav";
2963
2964 if (!QFile::exists(fileName))
2965 {
2966 QDir().mkpath(QFileInfo(fileName).dir().path());
2967 QFile::copy(":/Resources/Sound/800.wav", fileName);
2968 }
2969
2970 if (!QFile::exists(fileName))
2971 QApplication::beep();
2972 else
2973 playWav(fileName, noBlink);
2974
2975 if (!noBlink)
2976 blinkWindow();
2977 }
2978
blinkWindow()2979 void QtBitcoinTrader::blinkWindow()
2980 {
2981 #ifdef Q_OS_WIN
2982
2983 if (!isActiveWindow())
2984 {
2985 FLASHWINFO flashInfo;
2986 flashInfo.cbSize = sizeof(FLASHWINFO);
2987 flashInfo.hwnd = reinterpret_cast<HWND>(windowWidget->winId());
2988 flashInfo.dwFlags = FLASHW_ALL;
2989 flashInfo.uCount = 10;
2990 flashInfo.dwTimeout = 400;
2991 ::FlashWindowEx(&flashInfo);
2992 }
2993
2994 #endif//ToDo: make this feature works on Mac OS X
2995 }
2996
ruleTotalToBuyValueChanged()2997 void QtBitcoinTrader::ruleTotalToBuyValueChanged()
2998 {
2999 if (ui.marketLast->value() == 0.0)
3000 return;
3001
3002 double newValue = ui.accountUSD->value() / ui.marketLast->value() * floatFeeDec;
3003
3004 if (!qFuzzyCompare(newValue, ui.ruleTotalToBuyValue->value()))
3005 {
3006 setSpinValueP(ui.ruleTotalToBuyValue, newValue);
3007 }
3008 }
3009
ruleAmountToReceiveValueChanged()3010 void QtBitcoinTrader::ruleAmountToReceiveValueChanged()
3011 {
3012 if (ui.marketLast->value() == 0.0)
3013 return;
3014
3015 double newValue = ui.accountBTC->value() * ui.marketLast->value() * floatFeeDec;
3016
3017 if (!qFuzzyCompare(newValue, ui.ruleAmountToReceiveValue->value()))
3018 {
3019 setSpinValueP(ui.ruleAmountToReceiveValue, newValue);
3020 }
3021 }
3022
ruleTotalToBuyBSValueChanged()3023 void QtBitcoinTrader::ruleTotalToBuyBSValueChanged()
3024 {
3025 if (ui.marketBid->value() == 0.0)
3026 return;
3027
3028 double newValue = ui.accountUSD->value() / ui.marketBid->value() * floatFeeDec;
3029
3030 if (!qFuzzyCompare(newValue, ui.ruleTotalToBuyValue->value()))
3031 {
3032 setSpinValueP(ui.ruleTotalToBuyBSValue, newValue);
3033 }
3034 }
3035
ruleAmountToReceiveBSValueChanged()3036 void QtBitcoinTrader::ruleAmountToReceiveBSValueChanged()
3037 {
3038 if (ui.marketAsk->value() == 0.0)
3039 return;
3040
3041 double newValue = ui.accountBTC->value() * ui.marketAsk->value() * floatFeeDec;
3042
3043 if (!qFuzzyCompare(newValue, ui.ruleAmountToReceiveBSValue->value()))
3044 {
3045 setSpinValueP(ui.ruleAmountToReceiveBSValue, newValue);
3046 }
3047 }
3048
on_accountUSD_valueChanged(double)3049 void QtBitcoinTrader::on_accountUSD_valueChanged(double)
3050 {
3051 ruleTotalToBuyValueChanged();
3052 ruleTotalToBuyBSValueChanged();
3053 }
3054
on_accountBTC_valueChanged(double)3055 void QtBitcoinTrader::on_accountBTC_valueChanged(double)
3056 {
3057 ruleAmountToReceiveValueChanged();
3058 ruleAmountToReceiveBSValueChanged();
3059 }
3060
on_marketBid_valueChanged(double val)3061 void QtBitcoinTrader::on_marketBid_valueChanged(double val)
3062 {
3063 ruleTotalToBuyBSValueChanged();
3064 meridianPrice = (val + ui.marketAsk->value()) / 2;
3065
3066 if (val > 0.000000001)
3067 {
3068 emit addBound(val, false);
3069
3070 double ask = ui.marketAsk->value();
3071
3072 if (ask > 0.000000001)
3073 {
3074 val = (val + ask) / 2;
3075
3076 static double lastValue = val;
3077 static int priceDirection = 0;
3078 int lastPriceDirection = priceDirection;
3079
3080 if (lastValue < val)
3081 priceDirection = 1;
3082 else if (lastValue > val)
3083 priceDirection = -1;
3084 else
3085 priceDirection = lastPriceDirection;
3086
3087 lastValue = val;
3088
3089 static QString directionChar("-");
3090
3091 switch (priceDirection)
3092 {
3093 case -1:
3094 directionChar = downArrowNoUtfStr;
3095 break;
3096
3097 case 1:
3098 directionChar = upArrowNoUtfStr;
3099 break;
3100
3101 default:
3102 break;
3103 }
3104
3105 static QString titleText;
3106 titleText = baseValues.currentPair.currBSign + " " + JulyMath::textFromDouble(val) + " " + directionChar + " " + windowTitleP;
3107
3108 if (windowWidget->isVisible())
3109 windowWidget->setWindowTitle(titleText);
3110
3111 if (trayIcon && trayIcon->isVisible())
3112 trayIcon->setToolTip(titleText);
3113 }
3114 }
3115 }
3116
on_marketAsk_valueChanged(double val)3117 void QtBitcoinTrader::on_marketAsk_valueChanged(double val)
3118 {
3119 ruleAmountToReceiveBSValueChanged();
3120 meridianPrice = (val + ui.marketBid->value()) / 2;
3121
3122 if (val > 0.000000001)
3123 {
3124 emit addBound(val, true);
3125
3126 double bid = ui.marketBid->value();
3127
3128 if (bid > 0.000000001)
3129 {
3130 val = (val + bid) / 2;
3131
3132 static double lastValue = val;
3133 static int priceDirection = 0;
3134 int lastPriceDirection = priceDirection;
3135
3136 if (lastValue < val)
3137 priceDirection = 1;
3138 else if (lastValue > val)
3139 priceDirection = -1;
3140 else
3141 priceDirection = lastPriceDirection;
3142
3143 lastValue = val;
3144
3145 static QString directionChar("-");
3146
3147 switch (priceDirection)
3148 {
3149 case -1:
3150 directionChar = downArrowNoUtfStr;
3151 break;
3152
3153 case 1:
3154 directionChar = upArrowNoUtfStr;
3155 break;
3156
3157 default:
3158 break;
3159 }
3160
3161 static QString titleText;
3162 titleText = baseValues.currentPair.currBSign + " " + JulyMath::textFromDouble(val) + " " + directionChar + " " + windowTitleP;
3163
3164 if (windowWidget->isVisible())
3165 windowWidget->setWindowTitle(titleText);
3166
3167 if (trayIcon && trayIcon->isVisible())
3168 trayIcon->setToolTip(titleText);
3169 }
3170 }
3171 }
3172
on_marketLast_valueChanged(double)3173 void QtBitcoinTrader::on_marketLast_valueChanged(double)
3174 {
3175 ruleTotalToBuyValueChanged();
3176 ruleAmountToReceiveValueChanged();
3177 }
3178
historyDoubleClicked(QModelIndex index)3179 void QtBitcoinTrader::historyDoubleClicked(QModelIndex index)
3180 {
3181 repeatOrderFromValues(0, historyModel->getRowPrice(index.row()), historyModel->getRowVolume(index.row()), false);
3182 }
3183
repeatOrderFromValues(int type,double itemPrice,double itemVolume,bool availableOnly)3184 void QtBitcoinTrader::repeatOrderFromValues(int type, double itemPrice, double itemVolume, bool availableOnly)
3185 {
3186 if (itemPrice == 0.0)
3187 return;
3188
3189 if (QApplication::keyboardModifiers() != Qt::NoModifier)
3190 availableOnly = !availableOnly;
3191
3192 if (type == 1 || type == 0)
3193 {
3194 buyPricePerCoin->setValue(itemPrice);
3195
3196 if (availableOnly)
3197 itemVolume = qMin(itemVolume, getAvailableUSD() / itemPrice);
3198
3199 buyTotalBtc->setValue(itemVolume);
3200 }
3201
3202 if (type == -1 || type == 0)
3203 {
3204 sellPricePerCoin->setValue(itemPrice);
3205
3206 if (availableOnly)
3207 itemVolume = qMin(getAvailableBTC(), itemVolume);
3208
3209 sellTotalBtc->setValue(itemVolume);
3210 }
3211 }
3212
repeatOrderFromTrades(int type,int row)3213 void QtBitcoinTrader::repeatOrderFromTrades(int type, int row)
3214 {
3215 repeatOrderFromValues(type, tradesModel->getRowPrice(row), tradesModel->getRowVolume(row));
3216 }
3217
tradesDoubleClicked(QModelIndex index)3218 void QtBitcoinTrader::tradesDoubleClicked(QModelIndex index)
3219 {
3220 repeatOrderFromTrades(0, index.row());
3221 }
3222
depthSelectOrder(QModelIndex index,bool isSell,int type)3223 void QtBitcoinTrader::depthSelectOrder(QModelIndex index, bool isSell, int type)
3224 {
3225 double itemPrice = 0.0;
3226 double itemVolume = 0.0;
3227 int row = index.row();
3228 int col = index.column();
3229
3230 if (swapedDepth)
3231 isSell = !isSell;
3232
3233 if (isSell)
3234 {
3235 if (!swapedDepth)
3236 col = depthAsksModel->columnCount() - col - 1;
3237
3238 if (row < 0 || depthAsksModel->rowCount() <= row)
3239 return;
3240
3241 itemPrice = depthAsksModel->rowPrice(row);
3242
3243 if (col == 0 || col == 1)
3244 itemVolume = depthAsksModel->rowVolume(row);
3245 else
3246 itemVolume = depthAsksModel->rowSize(row);
3247 }
3248 else
3249 {
3250 if (swapedDepth)
3251 col = depthBidsModel->columnCount() - col - 1;
3252
3253 if (row < 0 || depthBidsModel->rowCount() <= row)
3254 return;
3255
3256 itemPrice = depthBidsModel->rowPrice(row);
3257
3258 if (col == 0 || col == 1)
3259 itemVolume = depthBidsModel->rowVolume(row);
3260 else
3261 itemVolume = depthBidsModel->rowSize(row);
3262 }
3263
3264 repeatOrderFromValues(type, itemPrice, itemVolume * floatFeeDec);
3265 }
3266
depthSelectSellOrder(QModelIndex index)3267 void QtBitcoinTrader::depthSelectSellOrder(QModelIndex index)
3268 {
3269 depthSelectOrder(index, true);
3270 }
3271
depthSelectBuyOrder(QModelIndex index)3272 void QtBitcoinTrader::depthSelectBuyOrder(QModelIndex index)
3273 {
3274 depthSelectOrder(index, false);
3275 }
3276
translateTab(QWidget * tab)3277 void QtBitcoinTrader::translateTab(QWidget* tab)
3278 {
3279 QDockWidget* dock = static_cast<QDockWidget*>(tab->parentWidget());
3280
3281 if (dock)
3282 {
3283 QString key = tab->accessibleName();
3284 QString defaultValue = dock->windowTitle();
3285 QString s = julyTr(key, defaultValue);
3286
3287 if (dock->isFloating())
3288 {
3289 s += " [" + profileName + "]";
3290 }
3291
3292 tab->parentWidget()->setWindowTitle(s);
3293
3294 if (dock->isFloating())
3295 {
3296 julyTranslator.translateUi(tab);
3297 fixAllChildButtonsAndLabels(tab);
3298 }
3299 }
3300 }
3301
lockLogo(bool lock)3302 void QtBitcoinTrader::lockLogo(bool lock)
3303 {
3304 if (lock)
3305 {
3306 dockLogo->setFeatures(QDockWidget::NoDockWidgetFeatures);
3307 }
3308 else
3309 {
3310 dockLogo->setFeatures(QDockWidget::DockWidgetMovable);
3311 }
3312
3313 dockLogo->setAllowedAreas(Qt::AllDockWidgetAreas);
3314 }
3315
initConfigMenu()3316 void QtBitcoinTrader::initConfigMenu()
3317 {
3318 menuConfig->clear();
3319 menuConfig->addAction(actionConfigManager);
3320 menuConfig->addSeparator();
3321
3322 for (const QString& name : ::config->getConfigNames())
3323 {
3324 QAction* action = menuConfig->addAction(name);
3325 connect(action, &QAction::triggered, this, &QtBitcoinTrader::onMenuConfigTriggered);
3326 }
3327 }
3328
languageChanged()3329 void QtBitcoinTrader::languageChanged()
3330 {
3331 if (!constructorFinished)
3332 return;
3333
3334 julyTranslator.translateUi(this);
3335 julyTranslator.translateUi(networkMenu);
3336 baseValues.dateTimeFormat = julyTr("DATETIME_FORMAT", baseValues.dateTimeFormat);
3337 baseValues.timeFormat = julyTr("TIME_FORMAT", baseValues.timeFormat);
3338 QStringList ordersLabels;
3339 ordersLabels << julyTr("ORDERS_COUNTER", "#") << julyTr("ORDERS_DATE", "Date") << julyTr("ORDERS_TYPE",
3340 "Type") << julyTr("ORDERS_STATUS", "Status") << julyTr("ORDERS_AMOUNT", "Amount") << julyTr("ORDERS_PRICE",
3341 "Price") << julyTr("ORDERS_TOTAL", "Total");
3342 ordersModel->setHorizontalHeaderLabels(ordersLabels);
3343
3344 QStringList tradesLabels;
3345 tradesLabels << "" << julyTr("ORDERS_DATE", "Date") << julyTr("ORDERS_AMOUNT", "Amount") << julyTr("ORDERS_TYPE",
3346 "Type") << julyTr("ORDERS_PRICE", "Price") << julyTr("ORDERS_TOTAL", "Total") << "";
3347 historyModel->setHorizontalHeaderLabels(tradesLabels);
3348 tradesLabels.insert(4, upArrowStr + downArrowStr);
3349 tradesModel->setHorizontalHeaderLabels(tradesLabels);
3350
3351 QStringList depthHeaderLabels;
3352 depthHeaderLabels << julyTr("ORDERS_PRICE", "Price") << julyTr("ORDERS_AMOUNT",
3353 "Amount") << upArrowStr + downArrowStr << julyTr("ORDERS_TOTAL", "Total") << "";
3354 depthBidsModel->setHorizontalHeaderLabels(depthHeaderLabels);
3355 depthAsksModel->setHorizontalHeaderLabels(depthHeaderLabels);
3356
3357 translateTab(ui.tabOrdersLog);
3358 translateTab(ui.tabRules);
3359 translateTab(ui.tabLastTrades);
3360 translateTab(ui.tabDepth);
3361 translateTab(ui.tabCharts);
3362 translateTab(ui.tabNews);
3363 //translateTab(ui.tabChat);
3364
3365 ui.widgetAccount->parentWidget()->setWindowTitle(julyTr("ACCOUNT_GROUPBOX", "%1 Account").arg(baseValues.exchangeName));
3366
3367 QString curCurrencyName = IniEngine::getCurrencyInfo(baseValues.currentPair.currAStr).name;
3368 ui.widgetBuy->parentWidget()->setWindowTitle(julyTr("GROUPBOX_BUY", "Buy %1").arg(curCurrencyName));
3369 ui.widgetSell->parentWidget()->setWindowTitle(julyTr("GROUPBOX_SELL", "Sell %1").arg(curCurrencyName));
3370
3371 for (QToolButton* toolButton : findChildren<QToolButton*>())
3372 if (toolButton->accessibleDescription() == "TOGGLE_SOUND")
3373 toolButton->setToolTip(julyTr("TOGGLE_SOUND", "Toggle sound notification on value change"));
3374
3375 if (ui.comboBoxGroupByPrice->count())
3376 {
3377 ui.comboBoxGroupByPrice->setItemText(0, julyTr("DONT_GROUP", "None"));
3378 fixWidthComboBoxGroupByPrice();
3379 }
3380
3381 copyTableValuesMenu.actions().at(0)->setText(julyTr("COPY_ROW", "Copy selected Rows"));
3382
3383 copyTableValuesMenu.actions().at(2)->setText(julyTr("COPY_DATE", "Copy Date"));
3384 copyTableValuesMenu.actions().at(3)->setText(julyTr("COPY_AMOUNT", "Copy Amount"));
3385 copyTableValuesMenu.actions().at(4)->setText(julyTr("COPY_PRICE", "Copy Price"));
3386 copyTableValuesMenu.actions().at(5)->setText(julyTr("COPY_TOTAL", "Copy Total"));
3387
3388 copyTableValuesMenu.actions().at(7)->setText(julyTr("REPEAT_BUYSELL_ORDER", "Repeat Buy and Sell order"));
3389 copyTableValuesMenu.actions().at(8)->setText(julyTr("REPEAT_BUY_ORDER", "Repeat Buy order"));
3390 copyTableValuesMenu.actions().at(9)->setText(julyTr("REPEAT_SELL_ORDER", "Repeat Sell order"));
3391
3392 copyTableValuesMenu.actions().at(11)->setText(julyTr("CANCEL_ORDER", "Cancel selected Orders"));
3393 copyTableValuesMenu.actions().at(12)->setText(julyTranslator.translateCheckBox("TR00075", "Cancel All Orders"));
3394
3395 ui.tradesBidsPrecent->setToolTip(julyTr("10_MIN_BIDS_VOLUME", "(10 min Bids Volume)/(10 min Asks Volume)*100"));
3396
3397 for (RuleWidget* currentGroup : ui.tabRules->findChildren<RuleWidget*>())
3398 if (currentGroup)
3399 currentGroup->languageChanged();
3400
3401 for (ScriptWidget* currentGroup : ui.tabRules->findChildren<ScriptWidget*>())
3402 if (currentGroup)
3403 currentGroup->languageChanged();
3404
3405 actionLockDocks->setText(julyTr("LOCK_DOCKS", "&Lock Docks"));
3406 actionExit->setText(julyTr("EXIT", "E&xit"));
3407 actionUpdate->setText(julyTr("UPDATE", "Check for &updates"));
3408 actionSendBugReport->setText(julyTr("SEND_BUG_REPORT", "&Send bug report"));
3409 actionAbout->setText(julyTr("ABOUT", "&About Qt Bitcoin Trader"));
3410 actionAboutQt->setText(julyTr("ABOUT_QT", "About &Qt"));
3411 #ifndef Q_OS_MAC
3412
3413 if (!baseValues_->portableMode && actionUninstall)
3414 actionUninstall->setText(julyTr("UNINSTALL", "&Uninstall"));
3415
3416 #endif
3417 actionConfigManager->setText(julyTr("CONFIG_MANAGER", "&Save..."));
3418 actionSettings->setText(julyTr("CONFIG_SETTINGS", "Se&ttings"));
3419 actionDebug->setText(julyTr("CONFIG_DEBUG", "&Debug"));
3420 menuFile->setTitle("&QtBitcoinTrader");
3421 menuView->setTitle(julyTr("MENU_VIEW", "&View"));
3422 menuConfig->setTitle(julyTr("MENU_CONFIG", "&Interface"));
3423 menuHelp->setTitle(julyTr("MENU_HELP", "&Help"));
3424
3425 if (configDialog)
3426 configDialog->setWindowTitle(julyTr("CONFIG_MANAGER_TITLE", "Config Manager"));
3427
3428 ::config->translateDefaultNames();
3429
3430 if (configDialog)
3431 ::config->onChanged();
3432
3433 adjustDockMinSize(ui.widgetTotalAtLast);
3434 adjustDockMinSize(ui.widgetTotalAtBuySell);
3435
3436 fixAllChildButtonsAndLabels(this);
3437 }
3438
buttonNewWindow()3439 void QtBitcoinTrader::buttonNewWindow()
3440 {
3441 QProcess::startDetached(QApplication::applicationFilePath(), QStringList());
3442 }
3443
on_rulesTabs_tabCloseRequested(int tab)3444 void QtBitcoinTrader::on_rulesTabs_tabCloseRequested(int tab)
3445 {
3446 ScriptWidget* currentScript = dynamic_cast<ScriptWidget*>(ui.rulesTabs->widget(tab));
3447 RuleWidget* currentGroup = dynamic_cast<RuleWidget*>(ui.rulesTabs->widget(tab));
3448
3449 if (currentGroup == nullptr && currentScript == nullptr)
3450 return;
3451
3452 if (currentScript || currentGroup->haveAnyRules())
3453 {
3454 QMessageBox msgBox(windowWidget);
3455 msgBox.setIcon(QMessageBox::Question);
3456 msgBox.setWindowTitle(julyTr("RULES_CONFIRM_DELETION", "Please confirm rules group deletion"));
3457 msgBox.setText(julyTr("RULES_ARE_YOU_SURE_TO_DELETE_GROUP",
3458 "Are you sure to delete rules group %1?").arg(ui.rulesTabs->widget(tab)->windowTitle()));
3459 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
3460 msgBox.setDefaultButton(QMessageBox::Yes);
3461 msgBox.setButtonText(QMessageBox::Yes, julyTr("YES", "Yes"));
3462 msgBox.setButtonText(QMessageBox::No, julyTr("NO", "No"));
3463
3464 if (msgBox.exec() != QMessageBox::Yes)
3465 return;
3466 }
3467
3468 //bool removed = false;
3469 //Q_UNUSED(removed);
3470
3471 if (currentGroup)
3472 {
3473 //removed = currentGroup->removeGroup();
3474 currentGroup->removeGroup();
3475 }
3476 else if (currentScript)
3477 {
3478 //removed = currentScript->removeGroup();
3479 currentScript->removeGroup();
3480 }
3481
3482 delete ui.rulesTabs->widget(tab);
3483
3484 ui.rulesTabs->setVisible(ui.rulesTabs->count());
3485 ui.rulesNoMessage->setVisible(!ui.rulesTabs->isVisible());
3486 }
3487
on_widgetStaysOnTop_toggled(bool on)3488 void QtBitcoinTrader::on_widgetStaysOnTop_toggled(bool on)
3489 {
3490 bool visible = isVisible();
3491
3492 if (on)
3493 windowWidget->setWindowFlags(Qt::Window | Qt::WindowStaysOnTopHint);
3494 else
3495 windowWidget->setWindowFlags(Qt::Window);
3496
3497 dockHost->setStaysOnTop(on);
3498
3499 if (visible)
3500 windowWidget->show();
3501 }
3502
depthFirstOrder(const QString & symbol,double price,double volume,bool isAsk)3503 void QtBitcoinTrader::depthFirstOrder(const QString& symbol, double price, double volume, bool isAsk)
3504 {
3505 if (symbol != baseValues.currentPair.symbol)
3506 return;
3507
3508 waitingDepthLag = false;
3509
3510 if (price == 0.0 || ui.comboBoxGroupByPrice->currentIndex() == 0)
3511 return;
3512
3513 if (isAsk)
3514 depthAsksModel->depthFirstOrder(price, volume);
3515 else
3516 depthBidsModel->depthFirstOrder(price, volume);
3517 }
3518
fixDepthBidsTable()3519 void QtBitcoinTrader::fixDepthBidsTable()
3520 {
3521 ui.depthAsksTable->resizeColumnToContents(1);
3522 ui.depthAsksTable->resizeColumnToContents(3);
3523 ui.depthAsksTable->resizeColumnToContents(4);
3524
3525 ui.depthBidsTable->resizeColumnToContents(0);
3526 ui.depthBidsTable->resizeColumnToContents(1);
3527 ui.depthBidsTable->resizeColumnToContents(3);
3528
3529 int asksWidth = ui.depthAsksTable->columnWidth(1) + ui.depthAsksTable->columnWidth(2) +
3530 ui.depthAsksTable->columnWidth(3) + ui.depthAsksTable->columnWidth(4) + 16;
3531 int bidsWidth = ui.depthBidsTable->columnWidth(0) + ui.depthBidsTable->columnWidth(1) +
3532 ui.depthBidsTable->columnWidth(2) + ui.depthBidsTable->columnWidth(3) + 16;
3533
3534 ui.depthAsksTable->setMinimumWidth(asksWidth);
3535 ui.depthAsksTable->horizontalScrollBar()->setValue(ui.depthAsksTable->horizontalScrollBar()->maximum());
3536 ui.depthBidsTable->setMinimumWidth(bidsWidth);
3537 ui.depthBidsTable->horizontalScrollBar()->setValue(0);
3538
3539 ui.tabDepth->setMinimumWidth(qMax(ui.gridLayout_31->minimumSize().width(), asksWidth + bidsWidth + 24));
3540 }
3541
depthSubmitOrders(const QString & symbol,QList<DepthItem> * asks,QList<DepthItem> * bids)3542 void QtBitcoinTrader::depthSubmitOrders(const QString& symbol, QList<DepthItem>* asks, QList<DepthItem>* bids)
3543 {
3544 if (symbol != baseValues.currentPair.symbol)
3545 return;
3546
3547 waitingDepthLag = false;
3548 int currentAsksScroll = ui.depthAsksTable->verticalScrollBar()->value();
3549 int currentBidsScroll = ui.depthBidsTable->verticalScrollBar()->value();
3550 depthAsksModel->depthUpdateOrders(asks);
3551 depthBidsModel->depthUpdateOrders(bids);
3552 depthVisibilityChanged(dockDepth->isVisible());
3553 ui.depthAsksTable->verticalScrollBar()->setValue(qMin(currentAsksScroll,
3554 ui.depthAsksTable->verticalScrollBar()->maximum()));
3555 ui.depthBidsTable->verticalScrollBar()->setValue(qMin(currentBidsScroll,
3556 ui.depthBidsTable->verticalScrollBar()->maximum()));
3557
3558 fixDepthBidsTable();
3559 }
3560
saveAppState()3561 void QtBitcoinTrader::saveAppState()
3562 {
3563 for (RuleWidget* currentGroup : ui.tabRules->findChildren<RuleWidget*>())
3564 if (currentGroup)
3565 currentGroup->saveRulesData();
3566
3567 for (ScriptWidget* currentGroup : ui.tabRules->findChildren<ScriptWidget*>())
3568 if (currentGroup)
3569 currentGroup->saveScriptToFile();
3570
3571 if (trayIcon)
3572 trayIcon->hide();
3573
3574 //saveRulesData();////
3575
3576 iniSettings->setValue("UI/ConfirmOpenOrder", confirmOpenOrder);
3577
3578 iniSettings->setValue("UI/CloseToTray", closeToTray);
3579
3580 iniSettings->setValue("UI/WindowOnTop", ui.widgetStaysOnTop->isChecked());
3581
3582 iniSettings->setValue("UI/DepthAutoResizeColumns", ui.depthAutoResize->isChecked());
3583
3584 if (!ui.depthAutoResize->isChecked())
3585 {
3586 iniSettings->setValue("UI/DepthColumnAsksSizeWidth", ui.depthAsksTable->columnWidth(1));
3587 iniSettings->setValue("UI/DepthColumnAsksVolumeWidth", ui.depthAsksTable->columnWidth(2));
3588 iniSettings->setValue("UI/DepthColumnAsksPriceWidth", ui.depthAsksTable->columnWidth(3));
3589
3590 iniSettings->setValue("UI/DepthColumnBidsPriceWidth", ui.depthBidsTable->columnWidth(0));
3591 iniSettings->setValue("UI/DepthColumnBidsVolumeWidth", ui.depthBidsTable->columnWidth(1));
3592 iniSettings->setValue("UI/DepthColumnBidsSizeWidth", ui.depthBidsTable->columnWidth(2));
3593 }
3594
3595 iniSettings->setValue("UI/FeeCalcSingleInstance", feeCalculatorSingleInstance);
3596
3597 iniSettings->setValue("UI/LockedDocks", lockedDocks);
3598
3599 iniSettings->sync();
3600 }
3601
on_depthComboBoxLimitRows_currentIndexChanged(int val)3602 void QtBitcoinTrader::on_depthComboBoxLimitRows_currentIndexChanged(int val)
3603 {
3604 baseValues.depthCountLimit = ui.depthComboBoxLimitRows->itemData(val, Qt::UserRole).toInt();
3605 baseValues.depthCountLimitStr = QByteArray::number(baseValues.depthCountLimit);
3606 iniSettings->setValue("UI/DepthCountLimit", baseValues.depthCountLimit);
3607 iniSettings->sync();
3608 clearDepth();
3609 }
3610
on_comboBoxGroupByPrice_currentIndexChanged(int val)3611 void QtBitcoinTrader::on_comboBoxGroupByPrice_currentIndexChanged(int val)
3612 {
3613 baseValues.groupPriceValue = ui.comboBoxGroupByPrice->itemData(val, Qt::UserRole).toDouble();
3614 iniSettings->setValue("UI/DepthGroupByPrice", baseValues.groupPriceValue);
3615 iniSettings->sync();
3616 clearDepth();
3617 }
3618
fixWidthComboBoxGroupByPrice()3619 void QtBitcoinTrader::fixWidthComboBoxGroupByPrice()
3620 {
3621 if (ui.comboBoxGroupByPrice->count() == 0)
3622 return;
3623
3624 int width = textFontWidth(ui.comboBoxGroupByPrice->itemText(0));
3625
3626 if (ui.comboBoxGroupByPrice->count() > 1)
3627 width = qMax(textFontWidth(ui.comboBoxGroupByPrice->itemText(ui.comboBoxGroupByPrice->count() - 1)), width);
3628
3629 if (ui.comboBoxGroupByPrice->count() > 2)
3630 width = qMax(textFontWidth(ui.comboBoxGroupByPrice->itemText(1)), width);
3631
3632 int bonus = static_cast<int>(ui.comboBoxGroupByPrice->height() * 1.1);
3633 ui.comboBoxGroupByPrice->setMinimumWidth(width + bonus);
3634 }
3635
on_depthAutoResize_toggled(bool on)3636 void QtBitcoinTrader::on_depthAutoResize_toggled(bool on)
3637 {
3638 if (on)
3639 {
3640 ui.depthAsksTable->horizontalHeader()->showSection(0);
3641 ui.depthBidsTable->horizontalHeader()->showSection(4);
3642
3643 setColumnResizeMode(ui.depthAsksTable, 0, QHeaderView::Stretch);
3644 setColumnResizeMode(ui.depthAsksTable, 1, QHeaderView::ResizeToContents);
3645 setColumnResizeMode(ui.depthAsksTable, 2, QHeaderView::ResizeToContents);
3646 setColumnResizeMode(ui.depthAsksTable, 3, QHeaderView::ResizeToContents);
3647 setColumnResizeMode(ui.depthAsksTable, 4, QHeaderView::ResizeToContents);
3648
3649 setColumnResizeMode(ui.depthBidsTable, 0, QHeaderView::ResizeToContents);
3650 setColumnResizeMode(ui.depthBidsTable, 1, QHeaderView::ResizeToContents);
3651 setColumnResizeMode(ui.depthBidsTable, 2, QHeaderView::ResizeToContents);
3652 setColumnResizeMode(ui.depthBidsTable, 3, QHeaderView::ResizeToContents);
3653 setColumnResizeMode(ui.depthBidsTable, 4, QHeaderView::Stretch);
3654
3655 QCoreApplication::processEvents();
3656 ui.depthAsksTable->horizontalScrollBar()->setValue(ui.depthAsksTable->horizontalScrollBar()->maximum());
3657 ui.depthBidsTable->horizontalScrollBar()->setValue(0);
3658 }
3659 else
3660 {
3661 setColumnResizeMode(ui.depthAsksTable, QHeaderView::Interactive);
3662 setColumnResizeMode(ui.depthBidsTable, QHeaderView::Interactive);
3663 ui.depthAsksTable->horizontalHeader()->hideSection(0);
3664 ui.depthBidsTable->horizontalHeader()->hideSection(4);
3665 }
3666 }
3667
getAvailableBTC()3668 double QtBitcoinTrader::getAvailableBTC()
3669 {
3670 if (currentExchange->balanceDisplayAvailableAmount)
3671 return JulyMath::cutDoubleDecimalsCopy(ui.accountBTC->value(), baseValues.currentPair.currADecimals, false);
3672
3673 return JulyMath::cutDoubleDecimalsCopy(ui.accountBTC->value() - ui.ordersTotalBTC->value(), baseValues.currentPair.currADecimals, false);
3674 }
3675
getAvailableUSD()3676 double QtBitcoinTrader::getAvailableUSD()
3677 {
3678 if (floatFee == 0.0)
3679 return ui.accountUSD->value();
3680
3681 double amountToReturn = 0.0;
3682
3683 if (currentExchange->balanceDisplayAvailableAmount)
3684 amountToReturn = ui.accountUSD->value();
3685 else
3686 amountToReturn = ui.accountUSD->value() - ui.ordersTotalUSD->value();
3687
3688 amountToReturn = JulyMath::cutDoubleDecimalsCopy(amountToReturn, baseValues.currentPair.currBDecimals, false);
3689
3690 if (currentExchange->exchangeSupportsAvailableAmount)
3691 amountToReturn = qMin(availableAmount, amountToReturn);
3692
3693 currentExchange->filterAvailableUSDAmountValue(&amountToReturn);
3694
3695 return amountToReturn;
3696 }
3697
getAvailableUSDtoBTC(double priceToBuy)3698 double QtBitcoinTrader::getAvailableUSDtoBTC(double priceToBuy)
3699 {
3700 double avUSD = getAvailableUSD();
3701 double decValue = 0.0L;
3702
3703 if (floatFee > 0.0)
3704 {
3705 switch (currentExchange->calculatingFeeMode)
3706 {
3707 case 1:
3708 decValue = qPow(0.1, qMax(baseValues.currentPair.currADecimals, 1));
3709 break;
3710
3711 case 2:
3712 decValue = 2.0 * qPow(0.1, qMax(baseValues.currentPair.currADecimals, 1));
3713 break;
3714
3715 case 3:
3716 {
3717 double zeros = qPow(10, baseValues.currentPair.currBDecimals);
3718 avUSD = ceil(avUSD / (floatFee + 1.0) * zeros) / zeros;
3719 break;
3720 }
3721
3722 default:
3723 break;
3724 }
3725 }
3726
3727 return JulyMath::cutDoubleDecimalsCopy(avUSD / priceToBuy - decValue, baseValues.currentPair.currADecimals, false);
3728 }
3729
apiSellSend(const QString & symbol,double btc,double price)3730 void QtBitcoinTrader::apiSellSend(const QString& symbol, double btc, double price)
3731 {
3732 if (baseValues.currentPair.symbolSecond().startsWith(symbol, Qt::CaseInsensitive))
3733 {
3734 emit apiSell(symbol, btc, price);
3735 }
3736 }
3737
apiBuySend(const QString & symbol,double btc,double price)3738 void QtBitcoinTrader::apiBuySend(const QString& symbol, double btc, double price)
3739 {
3740 if (baseValues.currentPair.symbolSecond().startsWith(symbol, Qt::CaseInsensitive))
3741 {
3742 emit apiBuy(symbol, btc, price);
3743 }
3744 }
3745
accFeeChanged(const QString & symbol,double val)3746 void QtBitcoinTrader::accFeeChanged(const QString& symbol, double val)
3747 {
3748 if (baseValues.currentPair.symbolSecond().startsWith(symbol, Qt::CaseInsensitive))
3749 setSpinValue(ui.accountFee, val);
3750 }
3751
accBtcBalanceChanged(const QString & symbol,double val)3752 void QtBitcoinTrader::accBtcBalanceChanged(const QString& symbol, double val)
3753 {
3754 if (baseValues.currentPair.symbolSecond().startsWith(symbol, Qt::CaseInsensitive))
3755 setSpinValue(ui.accountBTC, val);
3756 }
3757
accUsdBalanceChanged(const QString & symbol,double val)3758 void QtBitcoinTrader::accUsdBalanceChanged(const QString& symbol, double val)
3759 {
3760 if (baseValues.currentPair.symbolSecond().startsWith(symbol, Qt::CaseInsensitive))
3761 setSpinValue(ui.accountUSD, val);
3762 }
3763
indicatorHighChanged(const QString & symbol,double val)3764 void QtBitcoinTrader::indicatorHighChanged(const QString& symbol, double val)
3765 {
3766 if (baseValues.currentPair.symbolSecond().startsWith(symbol, Qt::CaseInsensitive))
3767 setSpinValue(ui.marketHigh, val);
3768 }
3769
indicatorLowChanged(const QString & symbol,double val)3770 void QtBitcoinTrader::indicatorLowChanged(const QString& symbol, double val)
3771 {
3772 if (baseValues.currentPair.symbolSecond().startsWith(symbol, Qt::CaseInsensitive))
3773 setSpinValue(ui.marketLow, val);
3774 }
3775
indicatorBuyChanged(const QString & symbol,double val)3776 void QtBitcoinTrader::indicatorBuyChanged(const QString& symbol, double val)
3777 {
3778 if (secondTimer.isNull())
3779 return;
3780
3781 if (baseValues.currentPair.symbolSecond().startsWith(symbol, Qt::CaseInsensitive))
3782 {
3783 if (val == 0.0)
3784 val = ui.marketLast->value();
3785
3786 if (val == 0.0)
3787 val = ui.marketBid->value();
3788
3789 if (ui.marketAsk->value() == 0.0 && val > 0.0)
3790 buyPricePerCoin->setValue(val);
3791
3792 setSpinValue(ui.marketAsk, val);
3793 }
3794 }
3795
indicatorLastChanged(const QString & symbol,double val)3796 void QtBitcoinTrader::indicatorLastChanged(const QString& symbol, double val)
3797 {
3798 if (baseValues.currentPair.symbolSecond().startsWith(symbol, Qt::CaseInsensitive))
3799 setSpinValue(ui.marketLast, val);
3800 }
3801
indicatorSellChanged(const QString & symbol,double val)3802 void QtBitcoinTrader::indicatorSellChanged(const QString& symbol, double val)
3803 {
3804 if (secondTimer.isNull())
3805 return;
3806
3807 if (baseValues.currentPair.symbolSecond().startsWith(symbol, Qt::CaseInsensitive))
3808 {
3809 if (val == 0.0)
3810 val = ui.marketLast->value();
3811
3812 if (val == 0.0)
3813 val = ui.marketAsk->value();
3814
3815 if (ui.marketBid->value() == 0.0 && val > 0.0)
3816 sellPricePerCoin->setValue(val);
3817
3818 setSpinValue(ui.marketBid, val);
3819 }
3820 }
3821
indicatorVolumeChanged(const QString & symbol,double val)3822 void QtBitcoinTrader::indicatorVolumeChanged(const QString& symbol, double val)
3823 {
3824 if (baseValues.currentPair.symbolSecond().startsWith(symbol, Qt::CaseInsensitive))
3825 setSpinValue(ui.marketVolume, val);
3826 }
3827
setRuleTabRunning(const QString & name,bool on)3828 void QtBitcoinTrader::setRuleTabRunning(const QString& name, bool on)
3829 {
3830 if (secondTimer.isNull())
3831 return;
3832
3833 for (int n = 0; n < ui.rulesTabs->count(); n++)
3834 if (ui.rulesTabs->tabText(n) == name)
3835 {
3836 static QIcon playIcon(":/Resources/Play.png");
3837 ui.rulesTabs->setTabIcon(n, on ? playIcon : QIcon());
3838 }
3839 }
3840
setSpinValueP(QDoubleSpinBox * spin,double & val)3841 void QtBitcoinTrader::setSpinValueP(QDoubleSpinBox* spin, double& val)
3842 {
3843 if (spin == nullptr || secondTimer.isNull())
3844 return;
3845
3846 spin->blockSignals(true);
3847 int needChangeDecimals = 0;
3848
3849 if (val < 0.00000001)
3850 spin->setDecimals(1);
3851 else
3852 {
3853 QByteArray valueStr = JulyMath::byteArrayFromDouble(val);
3854 int dotPos = valueStr.indexOf('.');
3855
3856 if (dotPos == -1)
3857 spin->setDecimals(1);
3858 else
3859 {
3860 int newDecimals = valueStr.size() - dotPos - 1;
3861
3862 if (spin->decimals() > newDecimals)
3863 needChangeDecimals = newDecimals;
3864 else
3865 spin->setDecimals(newDecimals);
3866 }
3867 }
3868
3869 spin->blockSignals(false);
3870
3871 spin->setMaximum(val);
3872 spin->setValue(val);
3873
3874 if (needChangeDecimals)
3875 {
3876 spin->blockSignals(true);
3877 spin->setDecimals(needChangeDecimals);
3878 spin->blockSignals(false);
3879 }
3880 }
3881
setSpinValue(QDoubleSpinBox * spin,double val)3882 void QtBitcoinTrader::setSpinValue(QDoubleSpinBox* spin, double val)
3883 {
3884 setSpinValueP(spin, val);
3885 }
3886
getVolumeByPrice(const QString & symbol,double price,bool isAsk)3887 double QtBitcoinTrader::getVolumeByPrice(const QString& symbol, double price, bool isAsk)
3888 {
3889 if (!baseValues.currentPair.symbolSecond().startsWith(symbol, Qt::CaseInsensitive))
3890 return 0.0;
3891
3892 return (isAsk ? depthAsksModel : depthBidsModel)->getVolumeByPrice(price, isAsk);
3893 }
3894
getPriceByVolume(const QString & symbol,double size,bool isAsk)3895 double QtBitcoinTrader::getPriceByVolume(const QString& symbol, double size, bool isAsk)
3896 {
3897 if (!baseValues.currentPair.symbolSecond().startsWith(symbol, Qt::CaseInsensitive))
3898 return 0.0;
3899
3900 return (isAsk ? depthAsksModel : depthBidsModel)->getPriceByVolume(size);
3901 }
3902
on_helpButton_clicked()3903 void QtBitcoinTrader::on_helpButton_clicked()
3904 {
3905 QString helpType = "JLRule";
3906
3907 if (ui.rulesTabs->count())
3908 {
3909 if (qobject_cast<ScriptWidget*>(ui.rulesTabs->currentWidget()))
3910 helpType = "JLScript";
3911 }
3912
3913 QDesktopServices::openUrl(QUrl("https://qbtapi.centrabit.com/?Object=Help&Method="
3914 + helpType + "&Locale=" + QLocale().name()));
3915 }
3916
initDocks()3917 void QtBitcoinTrader::initDocks()
3918 {
3919 setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
3920 setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks);
3921 }
3922
createActions()3923 void QtBitcoinTrader::createActions()
3924 {
3925 actionLockDocks = new QAction("&Lock Docks", this);
3926 actionLockDocks->setCheckable(true);
3927 connect(actionLockDocks, SIGNAL(triggered(bool)), this, SLOT(onActionLockDocks(bool)));
3928
3929 actionExit = new QAction("E&xit", this);
3930 actionExit->setShortcut(QKeySequence::Quit);
3931 connect(actionExit, SIGNAL(triggered()), this, SLOT(exitApp()));
3932
3933 actionUpdate = new QAction("Check for &updates...", this);
3934 connect(actionUpdate, SIGNAL(triggered()), this, SLOT(checkUpdate()));
3935
3936 actionSendBugReport = new QAction("&Send bug report", this);
3937 connect(actionSendBugReport, SIGNAL(triggered()), this, SLOT(onActionSendBugReport()));
3938
3939 actionAbout = new QAction("&About", this);
3940 connect(actionAbout, SIGNAL(triggered()), this, SLOT(onActionAbout()));
3941
3942 actionAboutQt = new QAction("About &Qt", this);
3943 connect(actionAboutQt, SIGNAL(triggered()), this, SLOT(onActionAboutQt()));
3944
3945 actionConfigManager = new QAction("&Save...", this);
3946 connect(actionConfigManager, &QAction::triggered, this, &QtBitcoinTrader::onActionConfigManager);
3947
3948 actionSettings = new QAction("Se&ttings", this);
3949 connect(actionSettings, &QAction::triggered, this, &QtBitcoinTrader::onActionSettings);
3950
3951 actionDebug = new QAction("&Debug", this);
3952 connect(actionDebug, &QAction::triggered, this, &QtBitcoinTrader::onActionDebug);
3953
3954 #ifndef Q_OS_MAC
3955
3956 if (!baseValues_->portableMode)
3957 {
3958 actionUninstall = new QAction("&Uninstall", this);
3959 connect(actionUninstall, &QAction::triggered, this, &QtBitcoinTrader::uninstall);
3960 }
3961
3962 #endif
3963 }
3964
createMenu()3965 void QtBitcoinTrader::createMenu()
3966 {
3967 menuFile = menuBar()->addMenu("&QtBitcoinTrader");
3968 menuFile->addSeparator();
3969
3970 menuFile->addSeparator();
3971 menuFile->addAction(actionSettings);
3972 menuFile->addAction(actionDebug);
3973 menuFile->addSeparator();
3974 menuFile->addAction(actionExit);
3975 #ifdef Q_OS_MAC
3976 actionSettings->setMenuRole(QAction::ApplicationSpecificRole);
3977 actionDebug->setMenuRole(QAction::ApplicationSpecificRole);
3978 #endif
3979 actionExit->setMenuRole(QAction::QuitRole);
3980
3981 menuView = menuBar()->addMenu("&View");
3982 menuView->addAction(actionLockDocks);
3983 menuView->addSeparator();
3984
3985 menuConfig = menuBar()->addMenu("&Config");
3986
3987 menuHelp = menuBar()->addMenu("&Help");
3988 menuHelp->addAction(actionUpdate);
3989 menuHelp->addAction(actionSendBugReport);
3990 menuHelp->addSeparator();
3991 menuHelp->addAction(actionAbout);
3992 menuHelp->addAction(actionAboutQt);
3993
3994 #ifndef Q_OS_MAC
3995
3996 if (actionUninstall && !baseValues_->portableMode)
3997 {
3998 menuHelp->addSeparator();
3999 menuHelp->addAction(actionUninstall);
4000 }
4001
4002 #endif
4003
4004 ui.menubar->setStyleSheet("font-size:12px");
4005 }
4006
uninstall()4007 void QtBitcoinTrader::uninstall()
4008 {
4009 QMessageBox msgBox(windowWidget);
4010 msgBox.setIcon(QMessageBox::Question);
4011 msgBox.setWindowTitle("Qt Bitcoin Trader");
4012 msgBox.setText(julyTr("CONFIRM_UNINSTALL",
4013 "Are you sure to uninstall Application?<br>All configs, scripts, rules will be deleted"));
4014 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
4015 msgBox.setDefaultButton(QMessageBox::Yes);
4016 msgBox.setButtonText(QMessageBox::Yes, julyTr("YES", "Yes"));
4017 msgBox.setButtonText(QMessageBox::No, julyTr("NO", "No"));
4018
4019 if (msgBox.exec() != QMessageBox::Yes)
4020 return;
4021
4022 QString tmpDir = QStandardPaths::standardLocations(QStandardPaths::TempLocation).first();
4023
4024 QString fileName = QFileInfo(QCoreApplication::applicationFilePath()).fileName();
4025 QFile::Permissions selfPerms = QFile(QCoreApplication::applicationFilePath()).permissions();
4026
4027 if (QFile::exists(tmpDir + "/TMP_" + fileName))
4028 {
4029 QFile::remove(tmpDir + "/TMP_" + fileName);
4030
4031 if (QFile::exists(tmpDir + "/TMP_" + fileName))
4032 QFile::rename(tmpDir + "/TMP_" + fileName, tmpDir + "/TMP_" + QString::number(QDateTime::currentSecsSinceEpoch()) + "_" + fileName);
4033 }
4034
4035 QFile::copy(QCoreApplication::applicationFilePath(), tmpDir + "/TMP_" + fileName);
4036 QFile(tmpDir + "/TMP_" + fileName).setPermissions(selfPerms);
4037 QProcess proc;
4038
4039 if (!proc.startDetached(tmpDir + "/TMP_" + fileName, QStringList() << "/uninstall"))
4040 {
4041 QMessageBox::warning(this, "Qt Bitcoin Trader", julyTr("UNINSTALL_ERROR",
4042 "Can't uninstall app, you can delete files manually") + "\n" + appDataDir + "\n" + tmpDir + "/TMP_" + fileName + "\n" + proc.errorString());
4043 QFile::remove(tmpDir + "/TMP_" + fileName);
4044 return;
4045 }
4046
4047 QCoreApplication::quit();
4048 }
4049
createDock(QWidget * widget,const QString & title)4050 QDockWidget* QtBitcoinTrader::createDock(QWidget* widget, const QString& title)
4051 {
4052 widget->setProperty("IsDockable", true);
4053 QDockWidget* dock = dockHost->createDock(this, widget, title);
4054
4055 if (widget != ui.widgetLogo)
4056 {
4057 menuView->addAction(dock->toggleViewAction());
4058 }
4059
4060 return dock;
4061 }
4062
moveWidgetsToDocks()4063 void QtBitcoinTrader::moveWidgetsToDocks()
4064 {
4065 // Top
4066 Qt::DockWidgetArea area = Qt::TopDockWidgetArea;
4067 addDockWidget(area, createDock(ui.widgetAccount, "Exchange Account"));
4068 addDockWidget(area, createDock(ui.widgetBalance, "Balance"));
4069 addDockWidget(area, createDock(ui.widgetTotalAtLast, "Total at Last Price"));
4070 addDockWidget(area, createDock(ui.widgetTotalAtBuySell, "Total at Buy/Sell Price"));
4071
4072 QWidget* titleNULL = new QWidget();
4073 QDockWidget* dockNULL = new QDockWidget();
4074 dockNULL->setObjectName("dockNULL");
4075 dockNULL->setTitleBarWidget(titleNULL);
4076 dockNULL->setMinimumSize(0, 1);
4077 addDockWidget(area, dockNULL);
4078
4079 addDockWidget(area, createDock(ui.widgetMarket, "Market"));
4080 addDockWidget(area, createDock(ui.widgetNetwork, "Network"));
4081
4082 // Bottom
4083 QDockWidget* dockBuy = createDock(ui.widgetBuy, "Buy Bitcoin");
4084 QDockWidget* dockBuySell = createDock(ui.widgetBuyThenSell, "Generate subsequent sell order");
4085 QDockWidget* dockSell = createDock(ui.widgetSell, "Sell Bitcoin");
4086 QDockWidget* dockSellBuy = createDock(ui.widgetSellThenBuy, "Generate subsequent buy order");
4087 QDockWidget* dockGeneral = createDock(ui.widgetSellBuy, "General");
4088 dockLogo = createDock(ui.widgetLogo, "Qt Trader Exchange"); //Powered By
4089 dockLogo->setMinimumSize(170, 70);
4090 ui.widgetBuyThenSell->setFixedHeight(ui.widgetBuyThenSell->minimumSizeHint().height());
4091 ui.widgetSellThenBuy->setFixedHeight(ui.widgetSellThenBuy->minimumSizeHint().height());
4092
4093 QWidget* titleBottomNULL = new QWidget();
4094 QDockWidget* dockHSpacer = new QDockWidget();
4095 dockHSpacer->setObjectName("dockHSpacer");
4096 dockHSpacer->setMinimumSize(0, 1);
4097 dockHSpacer->setTitleBarWidget(titleBottomNULL);
4098
4099 addDockWidget(Qt::BottomDockWidgetArea, dockBuy);
4100 splitDockWidget(dockBuy, dockSell, Qt::Horizontal);
4101 splitDockWidget(dockSell, dockHSpacer, Qt::Horizontal);
4102 splitDockWidget(dockHSpacer, dockGeneral, Qt::Horizontal);
4103 splitDockWidget(dockBuy, dockBuySell, Qt::Vertical);
4104 splitDockWidget(dockSell, dockSellBuy, Qt::Vertical);
4105 splitDockWidget(dockGeneral, dockLogo, Qt::Vertical);
4106
4107 // Left
4108 QDockWidget* dockGroupOrders = createDock(ui.groupOrders, "Your Open Orders");
4109 addDockWidget(Qt::LeftDockWidgetArea, dockGroupOrders);
4110
4111 // lock Logo
4112 lockLogo(false);
4113
4114 // tabs
4115 QDockWidget* dockOrdersLog = createDock(ui.tabOrdersLog, "Orders Log");
4116 QDockWidget* dockRules = createDock(ui.tabRules, "Rules");
4117 dockDepth = createDock(ui.tabDepth, "Order Book");
4118 QDockWidget* dockLastTrades = createDock(ui.tabLastTrades, "Trades");
4119 QDockWidget* dockCharts = createDock(ui.tabCharts, "Charts");
4120 QDockWidget* dockNews = createDock(ui.tabNews, "News");
4121 //QDockWidget* dockChat = createDock(ui.tabChat, "Chat");
4122 splitDockWidget(dockGroupOrders, dockOrdersLog, Qt::Horizontal);
4123 tabifyDockWidget(dockOrdersLog, dockRules);
4124 tabifyDockWidget(dockOrdersLog, dockDepth);
4125 tabifyDockWidget(dockOrdersLog, dockLastTrades);
4126 tabifyDockWidget(dockOrdersLog, dockCharts);
4127 tabifyDockWidget(dockOrdersLog, dockNews);
4128 //tabifyDockWidget(dockOrdersLog, dockChat);
4129 delete ui.tabWidget;
4130
4131 // Central
4132 QDockWidget* centralDockNULL = new QDockWidget(this);
4133 centralDockNULL->setFixedWidth(0);
4134 setCentralWidget(centralDockNULL);
4135 //centralWidget()->deleteLater();
4136
4137 connect(dockDepth, SIGNAL(visibilityChanged(bool)), this, SLOT(depthVisibilityChanged(bool)));
4138 connect(dockCharts, SIGNAL(visibilityChanged(bool)), chartsView, SLOT(visibilityChanged(bool)));
4139 connect(dockNews, SIGNAL(visibilityChanged(bool)), newsView, SLOT(visibilityChanged(bool)));
4140
4141 lockedDocks = iniSettings->value("UI/LockedDocks", false).toBool();
4142
4143 if (lockedDocks)
4144 actionLockDocks->setChecked(true);
4145
4146 onActionLockDocks(lockedDocks);
4147 }
4148
onActionAbout()4149 void QtBitcoinTrader::onActionAbout()
4150 {
4151 (new TranslationAbout(windowWidget))->showWindow();
4152 }
4153
onActionSendBugReport()4154 void QtBitcoinTrader::onActionSendBugReport()
4155 {
4156 QDesktopServices::openUrl(QUrl("https://github.com/JulyIGHOR/QtBitcoinTrader/issues"));
4157 }
4158
onActionAboutQt()4159 void QtBitcoinTrader::onActionAboutQt()
4160 {
4161 QApplication::aboutQt();
4162 }
4163
onActionLockDocks(bool checked)4164 void QtBitcoinTrader::onActionLockDocks(bool checked)
4165 {
4166 lockedDocks = checked;
4167 dockHost->lockDocks(checked);
4168 lockLogo(checked);
4169 }
4170
onActionConfigManager()4171 void QtBitcoinTrader::onActionConfigManager()
4172 {
4173 if (!configDialog)
4174 {
4175 configDialog = new ConfigManagerDialog(this);
4176 }
4177
4178 julyTranslator.translateUi(configDialog);
4179 configDialog->setWindowTitle(julyTr("CONFIG_MANAGER_TITLE", "Config Manager"));
4180 configDialog->setWindowFlags(configDialog->windowFlags() & ~Qt::WindowContextHelpButtonHint);
4181 configDialog->show();
4182 }
4183
onActionSettings()4184 void QtBitcoinTrader::onActionSettings()
4185 {
4186 SettingsDialog settingsDialog;
4187
4188 if (currentPopupDialogs != 0)
4189 settingsDialog.disableTranslateButton();
4190
4191 settingsDialog.exec();
4192 }
4193
onActionDebug()4194 void QtBitcoinTrader::onActionDebug()
4195 {
4196 if (debugLevel == 0)
4197 debugViewer = new DebugViewer;
4198 else
4199 {
4200 if (debugViewer == nullptr)
4201 debugViewer = new DebugViewer;
4202
4203 debugViewer->setWindowState(Qt::WindowActive);
4204 debugViewer->activateWindow();
4205 }
4206 }
4207
onMenuConfigTriggered()4208 void QtBitcoinTrader::onMenuConfigTriggered()
4209 {
4210 QAction* action = static_cast<QAction*>(sender());
4211 QString name = action->text();
4212
4213 ::config->load(name);
4214 }
4215
onConfigChanged()4216 void QtBitcoinTrader::onConfigChanged()
4217 {
4218 initConfigMenu();
4219 }
4220
onConfigError(const QString &)4221 void QtBitcoinTrader::onConfigError(const QString&)
4222 {
4223 }
4224
changeEvent(QEvent * event)4225 void QtBitcoinTrader::changeEvent(QEvent* event)
4226 {
4227 if (event->type() == QEvent::WindowStateChange)
4228 {
4229 QWindowStateChangeEvent* stateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
4230
4231 if (stateChangeEvent)
4232 {
4233 if (stateChangeEvent->oldState() == Qt::WindowMaximized && windowState() == Qt::WindowNoState)
4234 {
4235 adjustWidgetGeometry(this);
4236 }
4237 }
4238 }
4239 }
4240
executeConfirmExitDialog()4241 bool QtBitcoinTrader::executeConfirmExitDialog()
4242 {
4243 QMessageBox msgBox(windowWidget);
4244 msgBox.setIcon(QMessageBox::Question);
4245 msgBox.setWindowTitle("Qt Bitcoin Trader");
4246 msgBox.setText(julyTr("CONFIRM_EXIT",
4247 "Are you sure to close Application?<br>Active rules works only while application is running."));
4248 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
4249 msgBox.setDefaultButton(QMessageBox::Yes);
4250 msgBox.setButtonText(QMessageBox::Yes, julyTr("YES", "Yes"));
4251 msgBox.setButtonText(QMessageBox::No, julyTr("NO", "No"));
4252 return msgBox.exec() == QMessageBox::Yes;
4253 }
4254
closeEvent(QCloseEvent * event)4255 void QtBitcoinTrader::closeEvent(QCloseEvent* event)
4256 {
4257 event->ignore();
4258
4259 if (closeToTray)
4260 {
4261 buttonMinimizeToTray();
4262 }
4263 else if (confirmExitApp())
4264 {
4265 exitApp();
4266 }
4267 }
4268
confirmExitApp()4269 bool QtBitcoinTrader::confirmExitApp()
4270 {
4271 if (hasWorkingRules())
4272 {
4273 return executeConfirmExitDialog();
4274 }
4275 else
4276 {
4277 return true;
4278 }
4279 }
4280
exitApp()4281 void QtBitcoinTrader::exitApp()
4282 {
4283 secondTimer.reset();
4284
4285 saveAppState();
4286 ::config->save("", false);
4287 dockHost->hideFloatingWindow();
4288 hide();
4289
4290 if (configDialog)
4291 configDialog->deleteLater();
4292
4293 QCoreApplication::quit();
4294 }
4295
setupWidgets()4296 void QtBitcoinTrader::setupWidgets()
4297 {
4298 buyTotalSpend->setAccessibleName("USD");
4299 buyTotalSpend->setAccessibleDescription("CAN_BE_ZERO");
4300 buyTotalSpend->setDecimals(5);
4301 buyTotalSpend->setMaximum(999999999.0);
4302 ui.totalToSpendLayout->addWidget(buyTotalSpend);
4303
4304 buyPricePerCoin->setAccessibleName("PRICE");
4305 buyPricePerCoin->setDecimals(5);
4306 buyPricePerCoin->setMinimum(0.01);
4307 buyPricePerCoin->setMaximum(999999999.0);
4308 buyPricePerCoin->setValue(100.0);
4309 ui.pricePerCoinLayout->addWidget(buyPricePerCoin);
4310
4311 buyTotalBtc->setAccessibleName("BTC");
4312 buyTotalBtc->setAccessibleDescription("CAN_BE_ZERO");
4313 buyTotalBtc->setDecimals(8);
4314 buyTotalBtc->setMaximum(999999999.0);
4315 ui.totalBtcToBuyLayout->addWidget(buyTotalBtc);
4316
4317 profitLossSpinBox->setAccessibleName("USD");
4318 profitLossSpinBox->setAccessibleDescription("CAN_BE_ZERO");
4319 profitLossSpinBox->setDecimals(5);
4320 profitLossSpinBox->setMinimum(-999999999.0);
4321 profitLossSpinBox->setMaximum(999999999.0);
4322 ui.profitLossSpinBoxLayout->addWidget(profitLossSpinBox);
4323
4324 profitLossSpinBoxPrec->setDecimals(3);
4325 profitLossSpinBoxPrec->setMinimum(-1000.0);
4326 profitLossSpinBoxPrec->setMaximum(1000.0);
4327 ui.profitLossSpinBoxPrecLayout->addWidget(profitLossSpinBoxPrec);
4328
4329 sellTotalBtc->setAccessibleName("BTC");
4330 sellTotalBtc->setAccessibleDescription("CAN_BE_ZERO");
4331 sellTotalBtc->setDecimals(8);
4332 sellTotalBtc->setMaximum(999999999.0);
4333 ui.totalToSellLayout->addWidget(sellTotalBtc);
4334
4335 sellPricePerCoin->setAccessibleName("PRICE");
4336 sellPricePerCoin->setDecimals(5);
4337 sellPricePerCoin->setMinimum(0.01);
4338 sellPricePerCoin->setMaximum(999999999.0);
4339 sellPricePerCoin->setValue(200.0);
4340 ui.pricePerCoinSellLayout->addWidget(sellPricePerCoin);
4341
4342 sellAmountToReceive->setAccessibleName("USD");
4343 sellAmountToReceive->setAccessibleDescription("CAN_BE_ZERO");
4344 sellAmountToReceive->setDecimals(5);
4345 sellAmountToReceive->setMaximum(999999999.0);
4346 ui.amountToReceiveLayout->addWidget(sellAmountToReceive);
4347
4348 sellThanBuySpinBox->setAccessibleName("BTC");
4349 sellThanBuySpinBox->setAccessibleDescription("CAN_BE_ZERO");
4350 sellThanBuySpinBox->setDecimals(8);
4351 sellThanBuySpinBox->setMinimum(-999999999.0);
4352 sellThanBuySpinBox->setMaximum(999999999.0);
4353 ui.sellThanBuySpinBoxLayout->addWidget(sellThanBuySpinBox);
4354
4355 sellThanBuySpinBoxPrec->setDecimals(3);
4356 sellThanBuySpinBoxPrec->setMinimum(-9999.0);
4357 sellThanBuySpinBoxPrec->setMaximum(9999.0);
4358 ui.sellThanBuySpinBoxPrecLayout->addWidget(sellThanBuySpinBoxPrec);
4359
4360 connect(buyTotalSpend, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QtBitcoinTrader::buyTotalSpend_valueChanged);
4361 connect(buyPricePerCoin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QtBitcoinTrader::buyPricePerCoin_valueChanged);
4362 connect(buyTotalBtc, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QtBitcoinTrader::buyTotalBtc_valueChanged);
4363 connect(profitLossSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QtBitcoinTrader::profitLossSpinBox_valueChanged);
4364 connect(profitLossSpinBoxPrec, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QtBitcoinTrader::profitLossSpinBoxPrec_valueChanged);
4365 connect(sellTotalBtc, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QtBitcoinTrader::sellTotalBtc_valueChanged);
4366 connect(sellPricePerCoin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QtBitcoinTrader::sellPricePerCoin_valueChanged);
4367 connect(sellAmountToReceive, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QtBitcoinTrader::sellAmountToReceive_valueChanged);
4368 connect(sellThanBuySpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QtBitcoinTrader::sellThanBuySpinBox_valueChanged);
4369 connect(sellThanBuySpinBoxPrec, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QtBitcoinTrader::sellThanBuySpinBoxPrec_valueChanged);
4370 }
4371