├── rabbi.png
├── resources
├── qml
│ ├── CommonLibs
│ │ ├── qmldir
│ │ └── common.js
│ ├── BaseElements
│ │ ├── ListViewHeaderStyled.qml
│ │ ├── HeaderLabel.qml
│ │ ├── ListViewDelegateStyled.qml
│ │ ├── SearchField.qml
│ │ ├── Separator.qml
│ │ ├── TabBarIcon.qml
│ │ ├── ToolBarIcon.qml
│ │ ├── EmptyLabel.qml
│ │ ├── PasswordField.qml
│ │ ├── TableToolButton.qml
│ │ ├── ListViewStyled.qml
│ │ ├── qmldir
│ │ ├── DoubleSpinBox8Prec.qml
│ │ ├── DoubleSpinBox2Prec.qml
│ │ └── BusyIndicatorStyled.qml
│ ├── ModelViews
│ │ ├── qmldir
│ │ ├── OrdersListView.qml
│ │ └── OrdersView.qml
│ ├── ExchangePageSection.qml
│ ├── Emulation.qml
│ └── TopBar.qml
├── ui_icons
│ ├── droid.ico
│ ├── droid.png
│ ├── rabbi.ico
│ ├── left-arrow.svg
│ ├── right-arrow.svg
│ ├── down-arrow.svg
│ ├── folder.svg
│ ├── smartphone.svg
│ ├── up-arrow.svg
│ ├── cursor.svg
│ ├── bookmark.svg
│ ├── cancel.svg
│ ├── monitor.svg
│ ├── settings-2.svg
│ ├── search.svg
│ ├── layer.svg
│ ├── refresh.svg
│ ├── remove.svg
│ ├── video-camera.svg
│ ├── prohibition.svg
│ ├── push-pin.svg
│ ├── headphones.svg
│ ├── unlock.svg
│ ├── credit-card.svg
│ ├── heart.svg
│ ├── moon.svg
│ ├── forward.svg
│ ├── rewind.svg
│ ├── clock.svg
│ ├── menu.svg
│ ├── profile.svg
│ ├── magnet.svg
│ ├── video.svg
│ ├── lightning.svg
│ ├── left-arrow-1.svg
│ ├── play-button.svg
│ ├── shield.svg
│ ├── add.svg
│ ├── right-arrow-1.svg
│ ├── bluetooth.svg
│ ├── edit.svg
│ ├── info.svg
│ ├── cursor-1.svg
│ ├── power.svg
│ ├── switch.svg
│ ├── download.svg
│ ├── zoom-out.svg
│ ├── pause.svg
│ ├── bag.svg
│ ├── volume.svg
│ ├── map.svg
│ ├── cloud.svg
│ ├── cancel-1.svg
│ ├── hourglass.svg
│ ├── visible.svg
│ ├── cut.svg
│ ├── export.svg
│ ├── paint.svg
│ ├── battery.svg
│ ├── favorite.svg
│ ├── home.svg
│ ├── cutlery.svg
│ ├── speech-bubble.svg
│ ├── briefcase.svg
│ ├── correct.svg
│ ├── garbage.svg
│ ├── printer.svg
│ ├── zoom.svg
│ ├── voice-recorder.svg
│ ├── clip.svg
│ ├── bell.svg
│ ├── screen.svg
│ ├── tag.svg
│ ├── share.svg
│ ├── waiting.svg
│ ├── target.svg
│ ├── shutter.svg
│ ├── file.svg
│ ├── gamepad.svg
│ ├── placeholder.svg
│ ├── timer.svg
│ ├── calendar.svg
│ ├── padnote.svg
│ ├── layout.svg
│ ├── logout.svg
│ ├── photo-camera.svg
│ ├── gallery.svg
│ ├── presentation.svg
│ ├── shopping-cart.svg
│ ├── upload.svg
│ ├── stats.svg
│ ├── settings.svg
│ ├── link.svg
│ ├── envelope.svg
│ ├── wifi.svg
│ ├── speedometer.svg
│ ├── puzzle.svg
│ ├── rocket-launch.svg
│ ├── sun.svg
│ ├── settings-1.svg
│ ├── store.svg
│ ├── bitcoin.svg
│ ├── clock-1.svg
│ └── big-database.svg
├── fonts
│ └── Montserrat-Regular.ttf
├── default.cfg
└── exchange_logos
│ └── binance.svg
├── enter_account.png
├── share
├── deploy
│ └── linux
│ │ └── run.sh
└── sql
│ ├── dbCryptoShloma.sqlite
│ └── dbCryptoShloma.sqlite.sql
├── .gitmodules
├── installer
├── resources
│ └── cryptoshloma.qrc
├── packages
│ └── cryptoshloma
│ │ └── meta
│ │ ├── package.xml
│ │ └── installscript.qs
├── installer.pro
└── config
│ └── config.xml
├── src
├── common
│ ├── stacktrace.h
│ ├── encrypt.h
│ ├── enums.h
│ ├── constants.h
│ ├── utils.h
│ └── settings_manager.h
├── models
│ ├── trading_pairs_proxy_model.h
│ ├── spread_markets_proxy_model.h
│ ├── volume_markets_proxy_model.h
│ ├── buy_orders_proxy_model.h
│ ├── sell_orders_proxy_model.h
│ ├── balances_proxy_model.h
│ ├── market_orders_proxy_model.h
│ ├── trading_pairs_proxy_model.cpp
│ ├── open_orders_proxy_model.h
│ ├── market_orders_proxy_model.cpp
│ ├── balances_model.h
│ ├── open_orders_model.h
│ ├── trade_history_proxy_model.h
│ ├── market_orders_model.h
│ ├── trade_history_model.h
│ ├── markets_model.h
│ ├── buy_orders_proxy_model.cpp
│ ├── sell_orders_proxy_model.cpp
│ ├── balances_proxy_model.cpp
│ ├── spread_markets_proxy_model.cpp
│ └── volume_markets_proxy_model.cpp
├── algo
│ ├── hanukkah
│ │ ├── zero_step.h
│ │ ├── step.h
│ │ └── i_step.h
│ ├── trend_searcher.h
│ ├── i_trade_algo.h
│ ├── i_analytics_algo.h
│ ├── i_analytics_algo.cpp
│ ├── hanukkah.h
│ ├── spreder.h
│ └── i_trade_algo.cpp
├── boilerplate
│ ├── base_entry.h
│ └── singly_linked_stack.h
├── api
│ ├── i_exchange_api_entry.h
│ ├── binance_api_controller.h
│ ├── temporary_orders_table.h
│ └── i_exchange_api_controller.h
├── cryptoshloma.h
├── crud.h
├── storage
│ ├── balances_storage.h
│ ├── trade_history_storage.h
│ ├── market_orders_storage.h
│ ├── open_orders_storage.h
│ ├── markets_storage.h
│ ├── trade_history_storage.cpp
│ └── market_orders_storage.cpp
├── emulator.h
├── network
│ ├── http_client.h
│ └── websocket_client.h
└── base
│ └── currency.cpp
├── launcher
├── main.cpp
├── ProcessObserver.h
└── CMakeLists.txt
├── include
├── Models
└── init_logger.h
├── .github
├── workflows
│ ├── install_qt.yml
│ └── cmake.yml
└── ISSUE_TEMPLATE
│ └── bug_report.md
├── .gitignore
└── cmake
├── utils.cmake
├── version.in
├── VersionResource.rc
└── stacktrace.cmake
/rabbi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/man-k28/CryptoShloma/HEAD/rabbi.png
--------------------------------------------------------------------------------
/resources/qml/CommonLibs/qmldir:
--------------------------------------------------------------------------------
1 | module CommonLibs
2 | CommonLibs 1.0 common.js
3 |
--------------------------------------------------------------------------------
/enter_account.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/man-k28/CryptoShloma/HEAD/enter_account.png
--------------------------------------------------------------------------------
/share/deploy/linux/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | export LD_LIBRARY_PATH=$(pwd)/framework/lib
3 | ./Launcher $1
4 |
--------------------------------------------------------------------------------
/resources/ui_icons/droid.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/man-k28/CryptoShloma/HEAD/resources/ui_icons/droid.ico
--------------------------------------------------------------------------------
/resources/ui_icons/droid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/man-k28/CryptoShloma/HEAD/resources/ui_icons/droid.png
--------------------------------------------------------------------------------
/resources/ui_icons/rabbi.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/man-k28/CryptoShloma/HEAD/resources/ui_icons/rabbi.ico
--------------------------------------------------------------------------------
/share/sql/dbCryptoShloma.sqlite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/man-k28/CryptoShloma/HEAD/share/sql/dbCryptoShloma.sqlite
--------------------------------------------------------------------------------
/resources/fonts/Montserrat-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/man-k28/CryptoShloma/HEAD/resources/fonts/Montserrat-Regular.ttf
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "share/libs/CuteLogger"]
2 | path = share/libs/CuteLogger
3 | url = https://github.com/man-k28/CuteLogger.git
4 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/ListViewHeaderStyled.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.12
2 |
3 | Rectangle {
4 | color: "#303030" //"#252324" : "#322f31"
5 | height: 25
6 | z: 2
7 | }
8 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/HeaderLabel.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.12
2 |
3 | EmptyLabel {
4 | font.bold: true
5 | padding: 5
6 | horizontalAlignment: Text.AlignHCenter
7 | text: ""
8 | }
9 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/ListViewDelegateStyled.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.12
2 |
3 | Rectangle {
4 | color: index % 2 == 0 ? "#252324" : "#303030"
5 | width: view.width
6 | height: 15
7 | }
8 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/SearchField.qml:
--------------------------------------------------------------------------------
1 | import QtQuick.Controls 2.12
2 | import QtQuick.Controls.Material 2.12
3 |
4 | TextField {
5 | placeholderText: qsTr("Filter")
6 | selectByMouse: true
7 | }
8 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/Separator.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.12
2 | import QtQuick.Controls.Material 2.12
3 |
4 | Rectangle {
5 | color: Material.color(Material.Grey)
6 | width: parent.width
7 | height: 1
8 | }
9 |
--------------------------------------------------------------------------------
/installer/resources/cryptoshloma.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | ../../resources/ui_icons/rabbi.ico
4 | ../../resources/ui_icons/rabbi.svg
5 |
6 |
7 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/TabBarIcon.qml:
--------------------------------------------------------------------------------
1 | import QtQuick.Controls 2.12
2 |
3 | TabButton {
4 | ToolTip.timeout: 2000
5 | ToolTip.visible: hovered
6 | display: AbstractButton.IconOnly
7 | antialiasing: true
8 | }
9 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/ToolBarIcon.qml:
--------------------------------------------------------------------------------
1 | import QtQuick.Controls 2.12
2 | import QtQuick.Controls.Material 2.12
3 |
4 | ToolButton {
5 | antialiasing: true
6 | ToolTip.timeout: 2000
7 | ToolTip.visible: hovered
8 | }
9 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/EmptyLabel.qml:
--------------------------------------------------------------------------------
1 | import QtQuick.Controls 2.12
2 | import QtQuick.Controls.Material 2.12
3 |
4 | Label {
5 | text: qsTr("NaN")
6 | font.pixelSize: 10
7 | font.family: "Montserrat"
8 | color: "#fff"
9 | }
10 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/PasswordField.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.12
2 | import QtQuick.Controls 2.12
3 | import QtQuick.Controls.Material 2.12
4 |
5 | TextField {
6 | focus: true
7 | echoMode: TextInput.Password
8 | selectByMouse: true
9 | ToolTip.timeout: 3000
10 | ToolTip.visible: hovered
11 | }
12 |
--------------------------------------------------------------------------------
/installer/packages/cryptoshloma/meta/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | CryptoShloma
4 | CryptoShloma
5 | 0.3
6 | 2020-12-27
7 | true
8 |
9 |
10 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/TableToolButton.qml:
--------------------------------------------------------------------------------
1 | import QtQuick.Controls 2.12
2 | import QtQuick.Controls.Material 2.12
3 |
4 | ToolButton {
5 | padding: 0
6 | spacing: 0
7 | width: 14
8 | height: 14
9 | icon.color: Material.color(Material.Green)
10 | antialiasing: true
11 | hoverEnabled: true
12 | ToolTip.timeout: 2000
13 | ToolTip.visible: hovered
14 | }
15 |
--------------------------------------------------------------------------------
/src/common/stacktrace.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #ifdef Q_OS_LINUX
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | void linuxSignalStacktraceHandler(int signalNumber, siginfo_t *, void * secret ) noexcept;
14 |
15 | #endif
16 |
17 | void installSignalHandlers() noexcept;
18 |
--------------------------------------------------------------------------------
/resources/ui_icons/left-arrow.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/common/encrypt.h:
--------------------------------------------------------------------------------
1 | #ifndef ENCRYPT_H
2 | #define ENCRYPT_H
3 |
4 | #include
5 |
6 | class Encrypt
7 | {
8 | public:
9 | Encrypt() = default;
10 | static QByteArray sha256(const QByteArray& text);
11 | static QByteArray decrypt(const QByteArray& data, const QByteArray& password);
12 | static QByteArray encrypt(const QByteArray& data, const QByteArray& password);
13 | };
14 |
15 | #endif // ENCRYPT_H
16 |
--------------------------------------------------------------------------------
/resources/ui_icons/right-arrow.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/down-arrow.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/qml/CommonLibs/common.js:
--------------------------------------------------------------------------------
1 | function toDouble(styledData) {
2 | if ( styledData !== undefined && styledData !== null) {
3 | if ( typeof styledData === 'number' ) {
4 | if ( (Number(styledData) === styledData && styledData % 1 === 0) )
5 | return styledData
6 | else
7 | return styledData.toFixed(8)
8 | } else
9 | return styledData
10 |
11 | } else
12 | return ""
13 | }
14 |
--------------------------------------------------------------------------------
/src/common/enums.h:
--------------------------------------------------------------------------------
1 | #ifndef ENUMS_H
2 | #define ENUMS_H
3 | #include
4 |
5 | class Exchange final {
6 | Q_GADGET
7 | public:
8 | Exchange() = delete;
9 | enum class Type : quint8
10 | {
11 | Unknown = 1,
12 | Binance
13 | };
14 | Q_ENUM(Type)
15 | };
16 |
17 | enum AlgoType {
18 | HanukkahAlgo,
19 | SprederAlgo
20 | };
21 |
22 | enum AnalyticsAlgoType {
23 | TrendSearcherAlgo
24 | };
25 |
26 | #endif // ENUMS_H
27 |
--------------------------------------------------------------------------------
/resources/ui_icons/folder.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/models/trading_pairs_proxy_model.h:
--------------------------------------------------------------------------------
1 | #ifndef TRADINGPAIRSPROXYMODEL_H
2 | #define TRADINGPAIRSPROXYMODEL_H
3 | #include
4 |
5 | class TradingPairsProxyModel final : public QSortFilterProxyModel
6 | {
7 | Q_OBJECT
8 | public:
9 | explicit TradingPairsProxyModel(QObject *parent = nullptr) noexcept;
10 | protected:
11 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept override;
12 | };
13 |
14 | #endif // TRADINGPAIRSPROXYMODEL_H
15 |
--------------------------------------------------------------------------------
/resources/qml/ModelViews/qmldir:
--------------------------------------------------------------------------------
1 | module ModelViews
2 | BalanceView 1.0 BalanceView.qml
3 | OpenOrdersView 1.0 OpenOrdersView.qml
4 | OrdersListView 1.0 OrdersListView.qml
5 | OrdersView 1.0 OrdersView.qml
6 | SpreadMarketsView 1.0 SpreadMarketsView.qml
7 | TradePairPopup 1.0 TradePairPopup.qml
8 | TradingHistorySelectedPairView 1.0 TradingHistorySelectedPairView.qml
9 | TradingHistoryView 1.0 TradingHistoryView.qml
10 | TradingPairsView 1.0 TradingPairsView.qml
11 | VolumeMarketsView 1.0 VolumeMarketsView.qml
12 |
--------------------------------------------------------------------------------
/resources/ui_icons/smartphone.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/up-arrow.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/common/constants.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | static const QString CONST_BTC{QStringLiteral("BTC")};
4 | static const qint32 CONST_BTC_ID{1};
5 | static const qint32 CONST_MIN_TIMEOUT{1000};
6 | static const qreal PRECISSION{0.00000001};
7 | static const qint32 CONST_ORDERS_COUNT{5};
8 | static const qreal BINANCE_FEE{0.00075}; //NOTE: комиссия по BNB
9 |
10 | static const QString GLOBAL_APP_NAME{QStringLiteral("CryptoShloma")};
11 | #define DOUBLE_TO_STR(val) QString::number(val, 'f', 8)
12 |
--------------------------------------------------------------------------------
/resources/qml/ExchangePageSection.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.12
2 | import QtQuick.Controls 2.12
3 | import BaseElements 1.0
4 |
5 | GroupBox {
6 | spacing: 0
7 | padding: 0
8 | label: EmptyLabel {
9 | x: parent.leftPadding
10 | width: parent.availableWidth
11 | text: parent.title
12 | horizontalAlignment: Text.AlignLeft
13 | elide: Text.ElideLeft
14 | }
15 | background: Rectangle {
16 | color: "transparent"
17 | border.width: 0
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/resources/ui_icons/cursor.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/bookmark.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/cancel.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/monitor.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/algo/hanukkah/zero_step.h:
--------------------------------------------------------------------------------
1 | #ifndef ZEROSTEP_H
2 | #define ZEROSTEP_H
3 | #include "i_step.h"
4 |
5 | class ZeroStep final : public IStep
6 | {
7 | public:
8 | ZeroStep(const qreal &declinePerc,
9 | const qreal &getGrowth,
10 | Hanukkah * const parentAlgo,
11 | const Market::ConstPtr &market,
12 | bool buyBlocked = false,
13 | bool sellBlocked = false) noexcept;
14 | void executeBuyLogic() noexcept override;
15 | void executeSellLogic() noexcept override;
16 | };
17 |
18 | #endif // ZEROSTEP_H
19 |
--------------------------------------------------------------------------------
/src/boilerplate/base_entry.h:
--------------------------------------------------------------------------------
1 | #ifndef BASE_ENTRY_H
2 | #define BASE_ENTRY_H
3 | #include "strong_typedef.h"
4 |
5 | namespace Boilerplate {
6 |
7 | template<
8 | typename TYPE,
9 | typename ID
10 | >
11 | class BaseEntry
12 | {
13 | public:
14 | virtual ~BaseEntry() = default;
15 | using ConstPtr = QSharedPointer;
16 | using Ptr = QSharedPointer;
17 | using Container = QList;
18 | using ConstContainer = QList;
19 | using Id = Boilerplate::StrongTypedef;
20 | };
21 | }
22 |
23 | #endif // BASE_ENTRY_H
24 |
--------------------------------------------------------------------------------
/resources/ui_icons/settings-2.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/default.cfg:
--------------------------------------------------------------------------------
1 | EnableTestData: false;
2 | TradeBaseSumm: 0.0006;
3 | MinSpread: 0.00000001;
4 | MinProfit: 1;
5 | MinBaseVolume: 5;
6 | MinCoinPrice: 0.000001;
7 | TradeDifference: 0.00000001;
8 |
9 | Hanukkah/HanukkahTable: [{\"step\":0,\"growth\":0},{\"step\":3,\"growth\":2},{\"step\":6,\"growth\":3},{\"step\":11,\"growth\":7},{\"step\":17,\"growth\":12},{\"step\":23,\"growth\":17},{\"step\":30,\"growth\":21},{\"step\":33,\"growth\":27}];
10 | Hanukkah/HanukkahMaxSteps: 4;
11 |
12 | Binance/BinanceEnabled: true;
13 | Binance/BinanceAPIKey: xxxxxxx;
14 | Binance/BinanceSecretKey: xxxxxxx;
15 |
--------------------------------------------------------------------------------
/resources/exchange_logos/binance.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/installer/installer.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = aux
2 |
3 | INSTALLER = CryptoShloma-installer-v0.3
4 |
5 | INPUT = $$PWD/config/config.xml $$PWD/packages
6 | installer.input = INPUT
7 | installer.output = $$INSTALLER
8 | installer.commands = ~/Qt/Tools/QtInstallerFramework/4.0/bin/binarycreator --offline-only -c $$PWD/config/config.xml -r $$PWD/resources/cryptoshloma.qrc -p $$PWD/packages ${QMAKE_FILE_OUT}
9 | installer.CONFIG += target_predeps no_link combine
10 |
11 | QMAKE_EXTRA_COMPILERS += installer
12 |
13 | OTHER_FILES += packages/cryptoshloma/meta/package.xml
14 |
15 | RESOURCES += resources/cryptoshloma.qrc
16 |
--------------------------------------------------------------------------------
/resources/ui_icons/search.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/models/spread_markets_proxy_model.h:
--------------------------------------------------------------------------------
1 | #ifndef SPREADMARKETSPROXYMODEL_H
2 | #define SPREADMARKETSPROXYMODEL_H
3 | #include
4 |
5 | class SpreadMarketsProxyModel final : public QSortFilterProxyModel
6 | {
7 | Q_OBJECT
8 | public:
9 | explicit SpreadMarketsProxyModel(QObject *parent = nullptr) noexcept;
10 | protected:
11 | bool lessThan( const QModelIndex & left, const QModelIndex & right ) const noexcept override;
12 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept override;
13 | };
14 |
15 | #endif // SPREADMARKETSPROXYMODEL_H
16 |
--------------------------------------------------------------------------------
/src/models/volume_markets_proxy_model.h:
--------------------------------------------------------------------------------
1 | #ifndef VOLUMEMARKETSPROXYMODEL_H
2 | #define VOLUMEMARKETSPROXYMODEL_H
3 | #include
4 |
5 | class VolumeMarketsProxyModel final : public QSortFilterProxyModel
6 | {
7 | Q_OBJECT
8 | public:
9 | explicit VolumeMarketsProxyModel(QObject *parent = nullptr) noexcept;
10 | protected:
11 | bool lessThan( const QModelIndex & left, const QModelIndex & right ) const noexcept override;
12 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept override;
13 | };
14 |
15 | #endif // VOLUMEMARKETSPROXYMODEL_H
16 |
--------------------------------------------------------------------------------
/resources/ui_icons/layer.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/refresh.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/remove.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/video-camera.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/algo/hanukkah/step.h:
--------------------------------------------------------------------------------
1 | #ifndef STEP_H
2 | #define STEP_H
3 | #include "i_step.h"
4 |
5 | class Step final : public IStep
6 | {
7 | public:
8 | Step(const qreal &declinePerc,
9 | const qreal &getGrowth,
10 | Hanukkah * const parentAlgo,
11 | const Market::ConstPtr &market,
12 | bool buyBlocked = false,
13 | bool sellBlocked = false) noexcept;
14 | void executeBuyLogic() noexcept override;
15 | void executeSellLogic() noexcept override;
16 | private:
17 | qreal calculatePrevVolume(const Order::ConstContainer &container) noexcept;
18 | };
19 |
20 | #endif // STEP_H
21 |
--------------------------------------------------------------------------------
/src/models/buy_orders_proxy_model.h:
--------------------------------------------------------------------------------
1 | #ifndef BUYORDERSPROXYMODEL_H
2 | #define BUYORDERSPROXYMODEL_H
3 | #include
4 |
5 | class BuyOrdersProxyModel final : public QSortFilterProxyModel
6 | {
7 | Q_OBJECT
8 | public:
9 | explicit BuyOrdersProxyModel(QObject *parent = nullptr) noexcept;
10 | // Q_INVOKABLE void refresh() noexcept;
11 | protected:
12 | bool lessThan(const QModelIndex &left, const QModelIndex &right) const noexcept override;
13 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept override;
14 | };
15 |
16 | #endif // BUYORDERSPROXYMODEL_H
17 |
--------------------------------------------------------------------------------
/resources/ui_icons/prohibition.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/push-pin.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/models/sell_orders_proxy_model.h:
--------------------------------------------------------------------------------
1 | #ifndef SELLORDERSPROXYMODEL_H
2 | #define SELLORDERSPROXYMODEL_H
3 | #include
4 |
5 | class SellOrdersProxyModel final: public QSortFilterProxyModel
6 | {
7 | Q_OBJECT
8 | public:
9 | explicit SellOrdersProxyModel(QObject *parent = nullptr) noexcept;
10 | // Q_INVOKABLE void refresh() noexcept;
11 | protected:
12 | bool lessThan(const QModelIndex &left, const QModelIndex &right) const noexcept override;
13 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept override;
14 | };
15 |
16 | #endif // SELLORDERSPROXYMODEL_H
17 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/ListViewStyled.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.12
2 | import QtQuick.Controls 2.12
3 |
4 | ListView {
5 | property bool busyEnabled: true
6 | BusyIndicatorStyled {
7 | id: indicator
8 | }
9 |
10 | onCountChanged: {
11 | indicator.running = (count > 0 ? false : true) && busyEnabled
12 | }
13 |
14 | clip: true
15 | contentWidth: headerItem.width
16 | flickableDirection: Flickable.VerticalFlick
17 | ScrollIndicator.vertical: ScrollIndicator { }
18 | // focus: true
19 | headerPositioning: ListView.OverlayHeader
20 | boundsBehavior: Flickable.StopAtBounds
21 | }
22 |
--------------------------------------------------------------------------------
/resources/ui_icons/headphones.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/unlock.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/qmldir:
--------------------------------------------------------------------------------
1 | module BaseElements
2 | BusyIndicatorStyled 1.0 BusyIndicatorStyled.qml
3 | DoubleSpinBox2Prec 1.0 DoubleSpinBox2Prec.qml
4 | DoubleSpinBox8Prec 1.0 DoubleSpinBox8Prec.qml
5 | EmptyLabel 1.0 EmptyLabel.qml
6 | HeaderLabel 1.0 HeaderLabel.qml
7 | ListViewDelegateStyled 1.0 ListViewDelegateStyled.qml
8 | ListViewHeaderStyled 1.0 ListViewHeaderStyled.qml
9 | ListViewStyled 1.0 ListViewStyled.qml
10 | PasswordField 1.0 PasswordField.qml
11 | Separator 1.0 Separator.qml
12 | TabBarIcon 1.0 TabBarIcon.qml
13 | TableToolButton 1.0 TableToolButton.qml
14 | ToolBarIcon 1.0 ToolBarIcon.qml
15 | SearchField 1.0 SearchField.qml
16 |
--------------------------------------------------------------------------------
/resources/ui_icons/credit-card.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/heart.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/launcher/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "ProcessObserver.h"
3 | #include
4 | #include
5 | #include
6 |
7 | int main(int argc, char *argv[])
8 | {
9 | QCoreApplication app(argc, argv);
10 |
11 | app.setApplicationName("Launcher");
12 | app.setOrganizationName(GLOBAL_APP_NAME);
13 |
14 | initLogger(&app, Logger::Debug);
15 |
16 | ProcessObserver observer(app.applicationDirPath() + "/" + GLOBAL_APP_NAME, app.arguments());
17 | observer.start();
18 | QObject::connect(&app, &QCoreApplication::aboutToQuit, &observer, &ProcessObserver::deleteLater);
19 | return app.exec();
20 | }
21 |
--------------------------------------------------------------------------------
/resources/ui_icons/moon.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/forward.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/rewind.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/clock.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/menu.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/resources/ui_icons/profile.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/magnet.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/video.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/lightning.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/left-arrow-1.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/play-button.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/shield.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/add.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/right-arrow-1.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/algo/trend_searcher.h:
--------------------------------------------------------------------------------
1 | #ifndef TRENDSEARCHER_H
2 | #define TRENDSEARCHER_H
3 | #include "i_analytics_algo.h"
4 |
5 | class TrendSearcher final: public AbstractAnalyticsAlgorithm
6 | {
7 | Q_OBJECT
8 | public:
9 | explicit TrendSearcher(QObject *parent = nullptr) noexcept;
10 | private slots:
11 | void timerEvent(QTimerEvent *event) noexcept override final;
12 | bool start() noexcept override final;
13 | bool stop() noexcept override final;
14 | private:
15 | qreal calcPerc(const qreal &a, const qreal &b) const noexcept;
16 | qreal findFirstSellPrice(const Order::ConstContainer &model, const QDateTime &cycleTimeStart) noexcept;
17 | qint32 m_TimerId{0};
18 | };
19 |
20 | #endif // TRENDSEARCHER_H
21 |
--------------------------------------------------------------------------------
/resources/ui_icons/bluetooth.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/edit.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/info.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/resources/ui_icons/cursor-1.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/power.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/switch.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/models/balances_proxy_model.h:
--------------------------------------------------------------------------------
1 | #ifndef BALANCESPROXYMODEL_H
2 | #define BALANCESPROXYMODEL_H
3 | #include
4 |
5 | class BalancesProxyModel final: public QSortFilterProxyModel
6 | {
7 | Q_OBJECT
8 | public:
9 | explicit BalancesProxyModel(QObject *parent = nullptr) noexcept;
10 | // Q_INVOKABLE void refresh() noexcept;
11 | // void setFilterMarketId(const Market::MarketId &id) noexcept;
12 | protected:
13 | bool lessThan(const QModelIndex &left, const QModelIndex &right) const noexcept override;
14 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept override;
15 | //private:
16 | // Market::MarketId m_marketId;
17 | };
18 | #endif // BALANCESPROXYMODEL_H
19 |
--------------------------------------------------------------------------------
/resources/ui_icons/download.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/zoom-out.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/include/Models:
--------------------------------------------------------------------------------
1 | #include "../src/models/markets_model.h"
2 | #include "../src/models/spread_markets_proxy_model.h"
3 | #include "../src/models/volume_markets_proxy_model.h"
4 | #include "../src/models/market_orders_model.h"
5 | #include "../src/models/market_orders_proxy_model.h"
6 | #include "../src/models/open_orders_model.h"
7 | #include "../src/models/open_orders_proxy_model.h"
8 | #include "../src/models/balances_model.h"
9 | #include "../src/models/balances_proxy_model.h"
10 | #include "../src/models/buy_orders_proxy_model.h"
11 | #include "../src/models/sell_orders_proxy_model.h"
12 | #include "../src/models/trading_pairs_proxy_model.h"
13 | #include "../src/models/trade_history_model.h"
14 | #include "../src/models/trade_history_proxy_model.h"
15 |
--------------------------------------------------------------------------------
/resources/ui_icons/pause.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/resources/ui_icons/bag.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/DoubleSpinBox8Prec.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.12
2 | import QtQuick.Controls 2.12
3 |
4 | SpinBox {
5 | id: spinbox
6 | from: 0
7 | value: 0
8 | to: 100000000
9 | stepSize: 1
10 | editable: true
11 |
12 | property int decimals: 8
13 | property real realValue: value / 100000000
14 |
15 | validator: DoubleValidator {
16 | bottom: Math.min(spinbox.from, spinbox.to)
17 | top: Math.max(spinbox.from, spinbox.to)
18 | }
19 |
20 | textFromValue: function(value, locale) {
21 | return Number(value / 100000000).toFixed(spinbox.decimals)
22 | }
23 |
24 | valueFromText: function(text, locale) {
25 | return Number.fromLocaleString(locale, text) * 100000000
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/resources/ui_icons/volume.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/models/market_orders_proxy_model.h:
--------------------------------------------------------------------------------
1 | #ifndef MARKERORDERSPROXYMODEL_H
2 | #define MARKERORDERSPROXYMODEL_H
3 | #include
4 | #include
5 |
6 | class MarketOrdersProxyModel;
7 | #pragma pack (push, 1)
8 | class MarketOrdersProxyModel final: public QSortFilterProxyModel
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit MarketOrdersProxyModel(QObject *parent = nullptr) noexcept;
13 | public slots:
14 | void setFilterMarketId(const Market::MarketId &id = Market::MarketId()) noexcept;
15 | protected:
16 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept override;
17 | private:
18 | Market::MarketId m_marketId{};
19 | };
20 | #pragma pack (pop)
21 | #endif // MARKERORDERSPROXYMODEL_H
22 |
--------------------------------------------------------------------------------
/resources/ui_icons/map.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/DoubleSpinBox2Prec.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.12
2 | import QtQuick.Controls 2.12
3 |
4 | SpinBox {
5 | id: spinbox
6 | from: 0
7 | to: 100 * 100
8 | stepSize: 100
9 | // anchors.centerIn: parent
10 |
11 | property int decimals: 2
12 | property real realValue: value / 100
13 |
14 | validator: DoubleValidator {
15 | bottom: Math.min(spinbox.from, spinbox.to)
16 | top: Math.max(spinbox.from, spinbox.to)
17 | }
18 |
19 | textFromValue: function(value, locale) {
20 | return Number(value / 100).toLocaleString(locale, 'f', spinbox.decimals)
21 | }
22 |
23 | valueFromText: function(text, locale) {
24 | return Number.fromLocaleString(locale, text) * 100
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/resources/ui_icons/cloud.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/cancel-1.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/hourglass.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/visible.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/api/i_exchange_api_entry.h:
--------------------------------------------------------------------------------
1 | #ifndef I_EXCHANGE_API_ENTRY_H
2 | #define I_EXCHANGE_API_ENTRY_H
3 | #include
4 | #include
5 |
6 | namespace exchange {
7 | struct MarketEntry
8 | {
9 | Currency::CurrencyId tradeCurrencyId{};
10 | Currency::CurrencyId baseCurrencyId{};
11 | Market::Config params{};
12 | };
13 | struct OrderEntry
14 | {
15 | Market::MarketId marketId{};
16 | Order::Config params{};
17 | };
18 |
19 | struct BalanceEntry
20 | {
21 | Currency::CurrencyId currencyId{};
22 | Balance::Config params{};
23 | };
24 |
25 | using MarketEntryPtr = QSharedPointer;
26 | using OrderEntryPtr = QSharedPointer;
27 | using BalanceEntryPtr = QSharedPointer;
28 | }
29 | #endif // I_EXCHANGE_API_ENTRY_H
30 |
--------------------------------------------------------------------------------
/resources/ui_icons/cut.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/export.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/paint.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/battery.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/resources/ui_icons/favorite.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/home.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/cutlery.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/speech-bubble.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/resources/ui_icons/briefcase.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/cryptoshloma.h:
--------------------------------------------------------------------------------
1 | #ifndef CRYPTOSHLOMA_H
2 | #define CRYPTOSHLOMA_H
3 | #include
4 | #include "models/exchange_pool.h"
5 | #include "include/version.hpp"
6 |
7 | class CryptoShloma final: public QObject
8 | {
9 | Q_OBJECT
10 | Q_PROPERTY(QString softwareVersion READ getSoftwareVersion CONSTANT)
11 | public:
12 | explicit CryptoShloma(QObject *parent = nullptr);
13 | ~CryptoShloma() noexcept;
14 | bool init();
15 | const QString getSoftwareVersion() const { return cryptoShlomaVersionStr(); }
16 | public slots:
17 | void reloadSettings(const bool initial = false) noexcept;
18 | void restartEmulation() noexcept;
19 | private:
20 | void qmlRegistration() noexcept;
21 |
22 | QQmlApplicationEngine m_Engine{};
23 | ExchangePool m_exchangePool{};
24 | };
25 |
26 | #endif // CRYPTOSHLOMA_H
27 |
--------------------------------------------------------------------------------
/resources/ui_icons/correct.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/garbage.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/src/models/trading_pairs_proxy_model.cpp:
--------------------------------------------------------------------------------
1 | #include "trading_pairs_proxy_model.h"
2 | #include "markets_model.h"
3 |
4 | TradingPairsProxyModel::TradingPairsProxyModel(QObject *parent) noexcept :
5 | QSortFilterProxyModel(parent)
6 | {
7 | setDynamicSortFilter(true);
8 | }
9 |
10 | bool TradingPairsProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept
11 | {
12 | const QModelIndex &indexRow = sourceModel()->index(sourceRow, 0, sourceParent);
13 | if ( !indexRow.isValid() ) {
14 | return false;
15 | }
16 | const auto &variant = sourceModel()->data( indexRow, MarketsModel::MarketRole );
17 | Q_ASSERT_X(variant.canConvert< Market * >(), "QVariant convert", "TradingPairsProxyModel::filterAcceptsRow" );
18 | const auto &market = variant.value< Market * >();
19 |
20 | return market->getIsTradable();
21 | }
22 |
--------------------------------------------------------------------------------
/resources/ui_icons/printer.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/zoom.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/voice-recorder.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/clip.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/bell.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/.github/workflows/install_qt.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: Install Qt
4 |
5 | # Controls when the action will run.
6 | on:
7 | # Allows you to run this workflow manually from the Actions tab
8 | workflow_dispatch:
9 |
10 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
11 | jobs:
12 | # This workflow contains a single job called "build"
13 | build:
14 | # The type of runner that the job will run on
15 | runs-on: ubuntu-latest
16 |
17 | # Steps represent a sequence of tasks that will be executed as part of the job
18 | steps:
19 | - name: Install Qt
20 | uses: jurplel/install-qt-action@v2
21 | with:
22 | version: '5.12.8'
23 | host: 'linux'
24 | target: 'desktop'
25 | install-deps: 'true'
26 | cached: 'false'
27 | setup-python: 'true'
28 |
--------------------------------------------------------------------------------
/resources/ui_icons/screen.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/resources/ui_icons/tag.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/share.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/waiting.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/crud.h:
--------------------------------------------------------------------------------
1 | #ifndef CRUD_H
2 | #define CRUD_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | class Crud : public QObject
10 | {
11 | Q_OBJECT
12 | Q_PROPERTY(bool isOpen READ getIsOpen NOTIFY isOpenChanged)
13 |
14 | Crud (const Crud &) noexcept;
15 | Crud &operator = (const Crud &) noexcept;
16 | explicit Crud(QObject *parent = nullptr) noexcept;
17 | ~Crud() noexcept;
18 | static Crud *m_Crud;
19 | public:
20 | static Crud *getInstance();
21 | static void drop();
22 | void openDatabase();
23 | void closeDatabase();
24 | bool getIsOpen() const;
25 | QSqlQuery executeQuery(const QString &sql);
26 | signals:
27 | void isOpenChanged();
28 | private:
29 | QSqlDatabase m_Database{};
30 | mutable QReadWriteLock mutex{};
31 | bool m_isOpen{false};
32 | };
33 |
34 | #endif // CRUD_H
35 |
--------------------------------------------------------------------------------
/resources/ui_icons/target.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # C++ objects and libs
2 | *.slo
3 | *.lo
4 | *.o
5 | *.a
6 | *.la
7 | *.lai
8 | *.so
9 | *.so.*
10 | *.dll
11 | *.dylib
12 |
13 | # Qt-es
14 | object_script.*.Release
15 | object_script.*.Debug
16 | *_plugin_import.cpp
17 | /.qmake.cache
18 | /.qmake.stash
19 | *.pro.user
20 | *.pro.user.*
21 | *.qbs.user
22 | *.qbs.user.*
23 | *.moc
24 | moc_*.cpp
25 | moc_*.h
26 | qrc_*.cpp
27 | ui_*.h
28 | *.qmlc
29 | *.jsc
30 | Makefile*
31 | *build-*
32 | *.qm
33 | *.prl
34 |
35 | # Qt unit tests
36 | target_wrapper.*
37 |
38 | # QtCreator
39 | *.autosave
40 |
41 | # QtCreator Qml
42 | *.qmlproject.user
43 | *.qmlproject.user.*
44 |
45 | # QtCreator CMake
46 | CMakeLists.txt.user*
47 |
48 | # QtCreator 4.8< compilation database
49 | compile_commands.json
50 |
51 | # QtCreator local machine specific files for imported projects
52 | *creator.user*
53 |
54 | #Project files
55 | include/version.hpp
56 | installer/packages/cryptoshloma/data/CryptoShloma.7z
57 |
--------------------------------------------------------------------------------
/resources/ui_icons/shutter.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/file.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/resources/ui_icons/gamepad.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/resources/ui_icons/placeholder.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/timer.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/calendar.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/resources/ui_icons/padnote.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/resources/ui_icons/layout.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/src/models/open_orders_proxy_model.h:
--------------------------------------------------------------------------------
1 | #ifndef OPENORDERSPROXYMODEL_H
2 | #define OPENORDERSPROXYMODEL_H
3 | #include
4 | #include
5 |
6 | class OpenOrdersProxyModel;
7 | #pragma pack (push, 1)
8 | class OpenOrdersProxyModel final: public QSortFilterProxyModel
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit OpenOrdersProxyModel(QObject *parent = nullptr) noexcept;
13 | public slots:
14 | void setFilterOrderType(const Order::OrderType type) noexcept;
15 | void setFilterMarketId(const Market::MarketId &id) noexcept;
16 | // void refresh() noexcept;
17 | protected:
18 | bool lessThan(const QModelIndex &left, const QModelIndex &right) const noexcept override;
19 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept override;
20 | private:
21 | Order::OrderType m_OrderTypeFilter{Order::None};
22 | Market::MarketId m_marketId{};
23 | };
24 | #pragma pack (pop)
25 |
26 | #endif // OPENORDERSPROXYMODEL_H
27 |
--------------------------------------------------------------------------------
/resources/ui_icons/logout.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/qml/Emulation.qml:
--------------------------------------------------------------------------------
1 | import QtQuick.Dialogs 1.3
2 | import QtQuick 2.12
3 | import QtQuick.Controls 2.12
4 | import QtQuick.Controls.Material 2.12
5 |
6 | Popup {
7 | property alias dialog: fileDialog
8 | width: 250
9 | height: 70
10 | Material.theme: Material.Dark
11 | modal: false
12 |
13 | FileDialog {
14 | id: fileDialog
15 | title: qsTr("Please choose a file")
16 | folder: shortcuts.home
17 | nameFilters: [qsTr("Comma-Separated Values (*.csv)")]
18 | onAccepted: {
19 | var exchange = pageRepeater.itemAt(mainWrapper.currentIndex)
20 | if (exchange.item !== undefined && exchange.status === Loader.Ready)
21 | exchange.item.api.emulator.loadMarketOrders(fileDialog.fileUrl)
22 | }
23 | }
24 |
25 | Column {
26 | anchors.fill: parent
27 | ToolButton {
28 | text: qsTr("Load market orders")
29 | onClicked: fileDialog.open()
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/storage/balances_storage.h:
--------------------------------------------------------------------------------
1 | #ifndef BALANCES_STORAGE_H
2 | #define BALANCES_STORAGE_H
3 |
4 | #include
5 | #include
6 | class IExchangeAPI;
7 |
8 | class BalancesStorage final : public QObject
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit BalancesStorage(IExchangeAPI *parent = nullptr) noexcept;
13 | explicit BalancesStorage(const BalancesStorage &o) noexcept = delete;
14 | BalancesStorage& operator=(const BalancesStorage &o) noexcept = delete ;
15 | public:
16 | Balance::ConstPtr find(const Currency::ConstPtr ¤cy) const noexcept;
17 | Balance::ConstPtr find(const Currency::CurrencyId &id) const noexcept;
18 | Balance::ConstPtr btcBalance() const noexcept; //TODO: deprecated
19 | public slots:
20 | void merge(const QList &data) noexcept;
21 | private:
22 | QList m_Data{};
23 | IExchangeAPI * const m_api;
24 | QReadWriteLock lock{};
25 | };
26 |
27 | #endif // BALANCES_STORAGE_H
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/resources/ui_icons/photo-camera.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/cmake/utils.cmake:
--------------------------------------------------------------------------------
1 | # Влючение всех предупреждений
2 | macro(enable_all_warnings)
3 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Weffc++ -Woverloaded-virtual -Wctor-dtor-privacy -Wnon-virtual-dtor -Wold-style-cast -Wconversion -Wsign-conversion -Winit-self -Wunreachable-code")
5 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
6 | if (CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
7 | string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
8 | else ()
9 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
10 | endif ()
11 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic") #TODO
13 | else ()
14 | message(SEND_ERROR "Включение всех предупреждений для используемой версии компилятора не реализовано")
15 | endif ()
16 | add_definitions(-DQT_DEPRECATED_WARNINGS)
17 | endmacro(enable_all_warnings)
18 |
--------------------------------------------------------------------------------
/cmake/version.in:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | /*! Вовзарщает Major версию*/
6 | #define CryptoShloma_MAJOR_VERSION @CryptoShloma_VERSION_MAJOR@
7 |
8 | /*! Возвращает Minor версию */
9 | #define CryptoShloma_MINOR_VERSION @CryptoShloma_VERSION_MINOR@
10 |
11 | #define CryptoShloma_PATCH_VERSION @CryptoShloma_VERSION_PATCH@
12 |
13 | #define CryptoShloma_REVISION @CryptoShloma_REVISION@
14 |
15 | #define CryptoShloma_BRANCH "@CryptoShloma_BRANCH@"
16 |
17 | #define CryptoShloma_FULL_VERSION "@CryptoShloma_VERSION@"
18 |
19 | #define CryptoShloma_DB_VERSION "@CryptoShloma_DB@"
20 |
21 | /*! \brief Возвращает текущую версию в виде строки
22 | */
23 | inline QString cryptoShlomaVersionStr() noexcept
24 | {
25 | return QString( CryptoShloma_FULL_VERSION );
26 | }
27 |
28 | /*! \brief Возвращает текущую версию бд виде строки
29 | */
30 | inline QString cryptoShlomaDatabaseVersionStr() noexcept
31 | {
32 | return QString( CryptoShloma_DB_VERSION );
33 | }
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/installer/packages/cryptoshloma/meta/installscript.qs:
--------------------------------------------------------------------------------
1 | function Component()
2 | {
3 | // default constructor
4 | }
5 |
6 | Component.prototype.createOperations = function()
7 | {
8 | // call default implementation to actually install README.txt!
9 | component.createOperations();
10 |
11 | if (systemInfo.productType === "windows") {
12 | component.addOperation("CreateShortcut", "@TargetDir@/Launcher.exe", "@StartMenuDir@/CryptoShloma.lnk",
13 | "workingDirectory=@TargetDir@", "iconPath=@TargetDir@/Launcher.exe",
14 | "iconId=0", "description=CryptoShloma");
15 | component.addOperation("CreateShortcut",
16 | "@TargetDir@/Launcher.exe",// target
17 | "@DesktopDir@/CryptoShloma.lnk",// link-path
18 | "workingDirectory=@TargetDir@",// working-dir
19 | "iconPath=@TargetDir@/Launcher.exe", "iconId=0",// icon
20 | "description=CryptoShloma");// description
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/resources/ui_icons/gallery.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/resources/ui_icons/presentation.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/storage/trade_history_storage.h:
--------------------------------------------------------------------------------
1 | #ifndef TRADE_HISTORY_STORAGE_H
2 | #define TRADE_HISTORY_STORAGE_H
3 |
4 | #include
5 | #include
6 | class IExchangeAPI;
7 |
8 | class TradeHistoryStorage final: public QObject
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit TradeHistoryStorage(IExchangeAPI *parent = nullptr) noexcept;
13 | explicit TradeHistoryStorage(const TradeHistoryStorage &o) noexcept = delete;
14 | TradeHistoryStorage& operator=(const TradeHistoryStorage &o) noexcept = delete;
15 | Order::ConstContainer filter(const Market::MarketId &marketId) const noexcept;
16 | public slots:
17 | void insert(const Market::MarketId &id) noexcept;
18 | void merge(const QList &data) noexcept;
19 | void remove(const Market::MarketId &id) noexcept;
20 | private:
21 | Order::Container m_Data{};
22 | QList m_Filters{};
23 | IExchangeAPI * const m_api;
24 | QReadWriteLock lock{};
25 | };
26 |
27 | #endif // TRADE_HISTORY_STORAGE_H
28 |
--------------------------------------------------------------------------------
/launcher/ProcessObserver.h:
--------------------------------------------------------------------------------
1 | #ifndef PROCESSOBSERVER_H
2 | #define PROCESSOBSERVER_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | class ProcessObserver : public QObject
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit ProcessObserver(const QString& path, const QStringList& arguments);
13 | ~ProcessObserver();
14 |
15 | public slots:
16 | void start();
17 | private:
18 | void saveAndExit();
19 | private slots:
20 | void onFinished(int exitCode, QProcess::ExitStatus exitStatus);
21 | void onStarted();
22 | void onCheckProcess();
23 | private:
24 | QProcess m_process{}; /// < Процесс, который будем запускать
25 | QString m_processPath;
26 | QStringList m_arguments;
27 | QTime m_elapsedTime{}; /// < Время работы процесса
28 | bool m_wasStarted; /// < Флаг того, что процесс был запущен
29 | QTimer m_checkTimer{}; /// < Таймер проверки наличия процесса
30 | };
31 |
32 | #endif // PROCESSOBSERVER_H
33 |
--------------------------------------------------------------------------------
/resources/ui_icons/shopping-cart.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/upload.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/storage/market_orders_storage.h:
--------------------------------------------------------------------------------
1 | #ifndef MARKET_ORDERS_STORAGE_H
2 | #define MARKET_ORDERS_STORAGE_H
3 |
4 | #include
5 | #include
6 | class IExchangeAPI;
7 |
8 | class MarketOrdersStorage final : public QObject
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit MarketOrdersStorage(IExchangeAPI *parent) noexcept;
13 | explicit MarketOrdersStorage(const MarketOrdersStorage &o) noexcept = delete;
14 | MarketOrdersStorage& operator=(const MarketOrdersStorage &o) noexcept = delete;
15 | Order::ConstContainer filter(const Market::MarketId &marketId, const Order::OrderType orderType) const noexcept;
16 | public slots:
17 | void insert(const Market::MarketId &id) noexcept;
18 | void merge(const QList &data) noexcept;
19 | void remove(const Market::MarketId &id) noexcept;
20 | private:
21 | Order::Container m_Data{};
22 | QList m_Filters{};
23 | IExchangeAPI * const m_api;
24 | QReadWriteLock lock{};
25 | };
26 |
27 | #endif // MARKET_ORDERS_STORAGE_H
28 |
--------------------------------------------------------------------------------
/resources/ui_icons/stats.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
--------------------------------------------------------------------------------
/src/storage/open_orders_storage.h:
--------------------------------------------------------------------------------
1 | #ifndef OPEN_ORDERS_STORAGE_H
2 | #define OPEN_ORDERS_STORAGE_H
3 |
4 | #include
5 | #include
6 | class IExchangeAPI;
7 |
8 | class OpenOrdersStorage final : public QObject
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit OpenOrdersStorage(IExchangeAPI *parent) noexcept;
13 | explicit OpenOrdersStorage(const OpenOrdersStorage &o) noexcept = delete;
14 | OpenOrdersStorage& operator=(const OpenOrdersStorage &o) noexcept = delete;
15 | Order::ConstContainer filter(const Market::MarketId &marketId, const Order::OrderType orderType) const noexcept;
16 | qint32 count() const noexcept;
17 | public:
18 | Order::ConstContainer ordersByMarketId(const Market::MarketId &id) const noexcept;
19 | public slots:
20 | void merge(const QList &data) noexcept;
21 | void remove(const QList &data) noexcept;
22 | private:
23 | Order::Container m_Data{};
24 | IExchangeAPI * const m_api;
25 | QReadWriteLock lock{};
26 | };
27 |
28 | #endif // OPEN_ORDERS_STORAGE_H
29 |
--------------------------------------------------------------------------------
/resources/ui_icons/settings.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/src/models/market_orders_proxy_model.cpp:
--------------------------------------------------------------------------------
1 | #include "market_orders_proxy_model.h"
2 | #include "market_orders_model.h"
3 |
4 | MarketOrdersProxyModel::MarketOrdersProxyModel(QObject *parent) noexcept :
5 | QSortFilterProxyModel(parent)
6 | {
7 | setDynamicSortFilter(true);
8 | }
9 |
10 | void MarketOrdersProxyModel::setFilterMarketId(const Market::MarketId &id) noexcept
11 | {
12 | m_marketId = id;
13 | invalidateFilter();
14 | }
15 |
16 | bool MarketOrdersProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept
17 | {
18 | const QModelIndex &rowIndex = sourceModel()->index(sourceRow, 0, sourceParent);
19 | if ( !rowIndex.isValid() ) {
20 | return false;
21 | }
22 | const auto &variant = sourceModel()->data( rowIndex, MarketOrdersModel::OrderRole );
23 | Q_ASSERT_X(variant.canConvert< Order * >(), "QVariant convert", "MarkerOrdersProxyModel::filterAcceptsRow" );
24 |
25 | const auto &order = variant.value< Order * >();
26 |
27 | if ( m_marketId.isValid() )
28 | return order->getMarket()->getId() == m_marketId;
29 | else return false;
30 | }
31 |
--------------------------------------------------------------------------------
/resources/ui_icons/link.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/envelope.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/resources/ui_icons/wifi.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/src/models/balances_model.h:
--------------------------------------------------------------------------------
1 | #ifndef BALANCESMODEL_H
2 | #define BALANCESMODEL_H
3 | #include
4 | #include
5 |
6 | class BalancesModel;
7 | class ExchangeEntry;
8 | //TODO: сделать final, убрать include balance
9 | class BalancesModel : public QAbstractListModel
10 | {
11 | Q_OBJECT
12 | public:
13 | enum BalancesModelRoles {
14 | BalanceRole = Qt::UserRole + 1
15 | };
16 |
17 | explicit BalancesModel(ExchangeEntry *parent = nullptr) noexcept;
18 | explicit BalancesModel(const BalancesModel &o) noexcept = delete;
19 | BalancesModel& operator=(const BalancesModel &o) noexcept = delete;
20 | private:
21 | int rowCount(const QModelIndex &parent = QModelIndex()) const noexcept override;
22 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const noexcept override;
23 | QHash roleNames() const noexcept override;
24 | public slots:
25 | void merge(const QList &data) noexcept;
26 | void refresh() noexcept;
27 | private:
28 | QList m_Data{};
29 | ExchangeEntry const * m_entry;
30 | };
31 | #endif // BALANCESMODEL_H
32 |
--------------------------------------------------------------------------------
/resources/ui_icons/speedometer.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/models/open_orders_model.h:
--------------------------------------------------------------------------------
1 | #ifndef OPENORDERSMODEL_H
2 | #define OPENORDERSMODEL_H
3 | #include
4 | #include
5 |
6 | class OpenOrdersModel;
7 | class ExchangeEntry;
8 | //TODO: сделать final
9 | class OpenOrdersModel : public QAbstractListModel
10 | {
11 | Q_OBJECT
12 | public:
13 | enum OpenOrdersModelRoles {
14 | OrderRole = Qt::UserRole + 1
15 | };
16 |
17 | explicit OpenOrdersModel(ExchangeEntry *parent = nullptr) noexcept;
18 | explicit OpenOrdersModel(const OpenOrdersModel &o) noexcept = delete;
19 | OpenOrdersModel& operator=(const OpenOrdersModel &o) noexcept = delete;
20 | private:
21 | int rowCount(const QModelIndex &parent = QModelIndex()) const noexcept override;
22 | QVariant data(const QModelIndex &index, int role = Qt::UserRole) const noexcept override;
23 | QHash roleNames() const noexcept override;
24 |
25 | public slots:
26 | void merge(const QList &data) noexcept;
27 | void remove(const QList &data) noexcept;
28 | void refresh() noexcept;
29 | private:
30 | Order::Container m_Data{};
31 | ExchangeEntry const * m_entry;
32 | };
33 | #endif // OPENORDERSMODEL_H
34 |
--------------------------------------------------------------------------------
/resources/ui_icons/puzzle.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/api/binance_api_controller.h:
--------------------------------------------------------------------------------
1 | #ifndef BINANCE_API_CONTROLLER_H
2 | #define BINANCE_API_CONTROLLER_H
3 | #include "i_exchange_api_controller.h"
4 |
5 | class BinanceAPIController final : public IExchangeApiController
6 | {
7 | Q_OBJECT
8 | public:
9 | explicit BinanceAPIController(IExchangeAPI *api) noexcept;
10 | ~BinanceAPIController() noexcept override;
11 | private slots:
12 | void run() noexcept final;
13 | void timerEvent(QTimerEvent *event) noexcept override final;
14 | void appendMarket(const Market::MarketId &marketId,
15 | const Market::UserConfig &config) override final;
16 | void appendMarketsGroup(const MarketsGroup &group) override final;
17 | void removeMarket(const Market::MarketId &marketId) override final;
18 | void cancelAllOrders() override final;
19 | void cancelOrder(const Market::MarketId &marketId,
20 | const Order::OrderId &orderId) override final;
21 | void submitOrder(const Market::MarketId &marketId,
22 | const qreal &price,
23 | const qreal ¤cyVolume) override final;
24 | void dropCoin(const Currency::CurrencyId ¤cyId) override final;
25 | private:
26 | qint32 m_marketInfoTimerId = 0;
27 | };
28 |
29 | #endif // BINANCE_API_CONTROLLER_H
30 |
--------------------------------------------------------------------------------
/src/models/trade_history_proxy_model.h:
--------------------------------------------------------------------------------
1 | #ifndef TRADEHISTORYPROXYMODEL_H
2 | #define TRADEHISTORYPROXYMODEL_H
3 | #include
4 | #include
5 |
6 | class TradeHistoryProxyModel;
7 | #pragma pack (push, 1)
8 | class TradeHistoryProxyModel : public QSortFilterProxyModel
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit TradeHistoryProxyModel(QObject *parent = nullptr) noexcept;
13 | public slots:
14 | void setFilterOrderType(const Order::OrderType type) noexcept;
15 | void setFilterMarketId(const Market::MarketId &id = Market::MarketId()) noexcept;
16 | protected:
17 | bool lessThan(const QModelIndex &left, const QModelIndex &right) const noexcept override;
18 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept override;
19 | protected:
20 | Market::MarketId m_marketId{};
21 | private:
22 | Order::OrderType m_OrderTypeFilter{Order::None};
23 | };
24 |
25 | class TradeHistorySelectedPairsProxyModel final: public TradeHistoryProxyModel
26 | {
27 | Q_OBJECT
28 | public:
29 | explicit TradeHistorySelectedPairsProxyModel(QObject *parent = nullptr) noexcept;
30 | protected:
31 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept override;
32 | };
33 | #pragma pack (pop)
34 | #endif // TRADEHISTORYPROXYMODEL_H
35 |
--------------------------------------------------------------------------------
/src/models/market_orders_model.h:
--------------------------------------------------------------------------------
1 | #ifndef MARKETORDERSMODEL_H
2 | #define MARKETORDERSMODEL_H
3 | #include
4 | #include
5 |
6 | class MarketOrdersModel;
7 | class ExchangeEntry;
8 | //TODO: сделать final
9 | class MarketOrdersModel : public QAbstractListModel
10 | {
11 | Q_OBJECT
12 | public:
13 | enum MarketOrdersModelRoles {
14 | OrderRole = Qt::UserRole + 1
15 | };
16 |
17 | explicit MarketOrdersModel(ExchangeEntry *parent = nullptr) noexcept;
18 | explicit MarketOrdersModel(const MarketOrdersModel &o) noexcept = delete;
19 | MarketOrdersModel& operator=(const MarketOrdersModel &o) noexcept = delete;
20 | private:
21 | int rowCount(const QModelIndex &parent = QModelIndex()) const noexcept override;
22 | QVariant data(const QModelIndex &index, int role = Qt::UserRole) const noexcept override;
23 | QHash roleNames() const noexcept override;
24 |
25 | public slots:
26 | void insert(const Market::MarketId &id) noexcept;
27 | void merge(const QList &data) noexcept;
28 | void remove(const Market::MarketId &id) noexcept;
29 | void refresh() noexcept;
30 | private:
31 | Order::Container m_Data{};
32 | QList m_Filters{};
33 | ExchangeEntry const *m_entry;
34 | };
35 | #endif // MARKETORDERSMODEL_H
36 |
--------------------------------------------------------------------------------
/share/sql/dbCryptoShloma.sqlite.sql:
--------------------------------------------------------------------------------
1 | BEGIN TRANSACTION;
2 | CREATE TABLE IF NOT EXISTS `markets_cache` (
3 | `market_id` TEXT NOT NULL UNIQUE,
4 | `min_trend` REAL NOT NULL,
5 | `cur_trend_rate` REAL NOT NULL,
6 | `sell_mode` INTEGER,
7 | `pause_mode` INTEGER,
8 | `percentage_profit` REAL,
9 | `trade_summ` REAL,
10 | `is_volume_trading` INTEGER,
11 | `meta_config` TEXT,
12 | `exchange` INTEGER,
13 | `timestamp` TEXT NOT NULL,
14 | PRIMARY KEY(`market_id`, `exchange`)
15 | );
16 |
17 | CREATE TABLE IF NOT EXISTS `trade_journal` (
18 | `id` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
19 | `market_id` TEXT NOT NULL,
20 | `type` TEXT NOT NULL,
21 | `top_rate` REAL,
22 | `rate` REAL,
23 | `stop_loss` REAL,
24 | `balance` REAL,
25 | `amount` REAL,
26 | `total` REAL,
27 | `exchange` INTEGER,
28 | `timestamp` TEXT NOT NULL
29 | );
30 | CREATE TABLE IF NOT EXISTS `errors` (
31 | `id` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
32 | `type` TEXT NOT NULL,
33 | `text` TEXT NOT NULL,
34 | `request` BLOB,
35 | `result` BLOB,
36 | `exchange` INTEGER,
37 | `timestamp` TEXT NOT NULL
38 | );
39 | CREATE TABLE IF NOT EXISTS `variables` (
40 | `key` TEXT PRIMARY KEY,
41 | `value` TEXT
42 | );
43 | COMMIT;
44 |
--------------------------------------------------------------------------------
/installer/config/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | CryptoShloma
4 | 0.3
5 | Installer of CryptoShloma
6 | Man-k28
7 | https://github.com/man-k28/CryptoShloma
8 | CryptoShloma
9 | @ApplicationsDir@/CryptoShloma
10 | rabbi.png
11 | rabbi.png
12 | rabbi.png
13 | Updater
14 |
15 |
16 |
17 |
36 |
--------------------------------------------------------------------------------
/src/models/trade_history_model.h:
--------------------------------------------------------------------------------
1 | #ifndef TRADEHISTORYMODEL_H
2 | #define TRADEHISTORYMODEL_H
3 | #include
4 | #include
5 |
6 | class TradeHistoryModel;
7 | class ExchangeEntry;
8 | //TODO: сделать final
9 | class TradeHistoryModel : public QAbstractListModel
10 | {
11 | Q_OBJECT
12 | public:
13 | enum TradeHistoryModelRoles {
14 | OrderRole = Qt::UserRole + 1
15 | };
16 |
17 | explicit TradeHistoryModel(ExchangeEntry *parent = nullptr) noexcept;
18 | explicit TradeHistoryModel(const TradeHistoryModel &o) noexcept = delete;
19 | TradeHistoryModel& operator=(const TradeHistoryModel &o) noexcept = delete;
20 | const Order::ConstPtr findByIndex(const qint32 index) const noexcept;
21 | private:
22 | int rowCount(const QModelIndex &parent = QModelIndex()) const noexcept override;
23 | QVariant data(const QModelIndex &index, int role = Qt::UserRole) const noexcept override;
24 | QHash roleNames() const noexcept override;
25 | public slots:
26 | void insert(const Market::MarketId &id) noexcept;
27 | void merge(const QList &data) noexcept;
28 | void remove(const Market::MarketId &id) noexcept;
29 | void refresh() noexcept;
30 | private:
31 | Order::Container m_Data{};
32 | QList m_Filters{};
33 | ExchangeEntry const * m_entry;
34 | };
35 | #endif // TRADEHISTORYMODEL_H
36 |
--------------------------------------------------------------------------------
/resources/ui_icons/rocket-launch.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/src/algo/i_trade_algo.h:
--------------------------------------------------------------------------------
1 | #ifndef ITRADEALGORITHM_H
2 | #define ITRADEALGORITHM_H
3 | #include
4 | #include
5 | #include
6 |
7 | class IExchangeAPI;
8 |
9 | #pragma pack (push, 1)
10 | class ITradeAlgorithm : public QObject, public QRunnable
11 | {
12 | Q_OBJECT
13 | public:
14 | using ConstPtr = QSharedPointer;
15 | using Ptr = QSharedPointer;
16 | public:
17 | explicit ITradeAlgorithm(QObject *parent = nullptr) noexcept;
18 | virtual ~ITradeAlgorithm() noexcept override = default;
19 |
20 | static Ptr createAlgo(const AlgoType type, const Exchange::Type exchType) noexcept;
21 | void setApi(const QSharedPointer &api) noexcept;
22 |
23 | inline const QSharedPointer &api() const noexcept
24 | {
25 | return m_Api;
26 | }
27 | public:
28 | void run() noexcept override final;
29 | public slots:
30 | void init() noexcept;
31 | virtual bool start() = 0;
32 | //TODO: пока не обрабатывается
33 | virtual bool stop() = 0;
34 | virtual bool restart() = 0;
35 | virtual void reconfigure() = 0;
36 | virtual void removeMarket(const Market::MarketId &) {}
37 | signals:
38 | void updateMarketConfig(const Market::MarketId &marketId, const Market::UserConfig &config);
39 | void ready();
40 | void finished();
41 | private:
42 | QSharedPointer m_Api = {};
43 | };
44 | #pragma pack (pop)
45 | #endif // ITRADEALGORITHM_H
46 |
--------------------------------------------------------------------------------
/src/algo/i_analytics_algo.h:
--------------------------------------------------------------------------------
1 | #ifndef ABSTRACTANALYTICSALGORITHM_H
2 | #define ABSTRACTANALYTICSALGORITHM_H
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | class ITradeAlgorithm;
9 |
10 | #pragma pack (push, 1)
11 | class AbstractAnalyticsAlgorithm : public QObject, public QRunnable
12 | {
13 | Q_OBJECT
14 | public:
15 | explicit AbstractAnalyticsAlgorithm(QObject *parent = nullptr) noexcept;
16 | virtual ~AbstractAnalyticsAlgorithm() noexcept override = default;
17 | using Ptr = QSharedPointer;
18 | static Ptr createAlgo(const AnalyticsAlgoType type) noexcept;
19 |
20 | void setTradeAlgo(const QSharedPointer &algo) noexcept;
21 |
22 | QSharedPointer tradeAlgo() const;
23 | public:
24 | void run() noexcept override final;
25 | public slots:
26 | virtual bool start() = 0;
27 | //TODO: пока не обрабатывается
28 | virtual bool stop() = 0;
29 | signals:
30 | void ready();
31 | void finished();
32 | void updateMarketConfig(const Market::MarketId &marketId, const Market::UserConfig &config);
33 | void cancelOrderId(const Market::MarketId &marketId, const Order::OrderId &id);
34 | QT_DEPRECATED void submitSellOrderToBuyPrice(const Market::MarketId &id, const qreal &price, const qreal ¤cyVolume);
35 | protected:
36 | QSharedPointer m_TradeAlgo = {};
37 | };
38 | #pragma pack (pop)
39 | #endif // ABSTRACTANALYTICSALGORITHM_H
40 |
--------------------------------------------------------------------------------
/src/emulator.h:
--------------------------------------------------------------------------------
1 | #ifndef EMULATOR_H
2 | #define EMULATOR_H
3 |
4 | #include
5 |
6 | class IExchangeAPI;
7 |
8 | class Emulator : public QObject
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit Emulator(IExchangeAPI *parent) noexcept;
13 |
14 | public slots:
15 | void loadMarketOrders(const QUrl &url) noexcept;
16 |
17 | void submitOrder(const Market::MarketId &marketId,
18 | const Order::OrderId &orderId,
19 | const Order::OrderType side,
20 | const qreal &price,
21 | const qreal &baseVolume,
22 | const qreal ¤cyVolume = 0.) noexcept;
23 | void cancelOrder(const Order::OrderId &orderId = Order::OrderId(0),
24 | const Market::MarketId &marketId = Market::MarketId()) noexcept;
25 | void sellOrder(const Market::MarketId &marketId,
26 | const Order::OrderId &orderId,
27 | const qreal &price,
28 | const qreal &baseVolume,
29 | const qreal ¤cyVolume) noexcept;
30 | signals:
31 | void loadedMarketOrders(const QList &list);
32 | void loadedUserOpenOrders(const QList &list);
33 | void loadedBalance(const QList &list);
34 | void loadedUserTradeHistory(const QList &list);
35 | void loadedCanceledOrders(const QList &ids);
36 | };
37 |
38 | #endif // EMULATOR_H
39 |
--------------------------------------------------------------------------------
/cmake/VersionResource.rc:
--------------------------------------------------------------------------------
1 | #include "VersionInfo.h"
2 |
3 | #if defined(__MINGW64__) || defined(__MINGW32__)
4 | // MinGW-w64, MinGW
5 | #if defined(__has_include) && __has_include()
6 | #include
7 | #else
8 | #include
9 | #include
10 | #endif
11 | #else
12 | // MSVC, Windows SDK
13 | #include
14 | #endif
15 |
16 | IDI_ICON1 ICON PRODUCT_ICON
17 |
18 | LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
19 |
20 | VS_VERSION_INFO VERSIONINFO
21 | FILEVERSION FILE_VERSION_RESOURCE
22 | PRODUCTVERSION PRODUCT_VERSION_RESOURCE
23 | FILEFLAGSMASK 0x3fL
24 | #ifdef _DEBUG
25 | FILEFLAGS 0x1L
26 | #else
27 | FILEFLAGS 0x0L
28 | #endif
29 | FILEOS 0x4L
30 | FILETYPE 0x1L
31 | FILESUBTYPE 0x0L
32 | BEGIN
33 | BLOCK "StringFileInfo"
34 | BEGIN
35 | BLOCK "000904b0"
36 | BEGIN
37 | VALUE "Comments", PRODUCT_COMMENTS
38 | VALUE "CompanyName", PRODUCT_COMPANY_NAME
39 | VALUE "FileDescription", PRODUCT_FILE_DESCRIPTION
40 | VALUE "FileVersion", FILE_VERSION_RESOURCE_STR
41 | VALUE "InternalName", PRODUCT_INTERNAL_NAME
42 | VALUE "LegalCopyright", PRODUCT_COMPANY_COPYRIGHT
43 | VALUE "OriginalFilename", PRODUCT_ORIGINAL_FILENAME
44 | VALUE "ProductName", PRODUCT_BUNDLE
45 | VALUE "ProductVersion", PRODUCT_VERSION_RESOURCE_STR
46 | END
47 | END
48 | BLOCK "VarFileInfo"
49 | BEGIN
50 | VALUE "Translation", 0x9, 1200
51 | END
52 | END
53 |
--------------------------------------------------------------------------------
/resources/ui_icons/sun.svg:
--------------------------------------------------------------------------------
1 |
2 |
17 |
--------------------------------------------------------------------------------
/resources/qml/ModelViews/OrdersListView.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.12
2 | import QtQuick.Controls 2.12
3 | import QtQuick.Controls.Material 2.12
4 | import CryptoShloma.Gui 1.0
5 | import CryptoShloma.Common 1.0
6 | import CommonLibs 1.0
7 | import BaseElements 1.0
8 |
9 | ListViewStyled {
10 | header: ListViewHeaderStyled {
11 | property var view: ListView.view
12 | width: view.width
13 | Row {
14 | spacing: 1
15 | HeaderLabel {
16 | text: qsTr("Price")
17 | width: 70
18 | }
19 |
20 | HeaderLabel {
21 | text: qsTr("Volume")
22 | width: 110
23 | }
24 |
25 | HeaderLabel {
26 | text: qsTr("Total")
27 | width: 80
28 | }
29 | }
30 | }
31 |
32 | delegate: ListViewDelegateStyled {
33 | property var view: ListView.view
34 | property int row: index
35 | Column {
36 | Row {
37 | spacing: 1
38 | EmptyLabel {
39 | text: CommonLibs.toDouble(model.order.price);
40 | width: 70
41 | }
42 | EmptyLabel {
43 | text: CommonLibs.toDouble(model.order.currencyVolume);
44 | width: 100
45 | }
46 | EmptyLabel {
47 | text: CommonLibs.toDouble(model.order.baseVolume);
48 | width: 80
49 | }
50 | }
51 |
52 | Separator {}
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/algo/i_analytics_algo.cpp:
--------------------------------------------------------------------------------
1 | #include "i_analytics_algo.h"
2 | #include "i_trade_algo.h"
3 | #include
4 |
5 | #include "trend_searcher.h"
6 | #include
7 |
8 | AbstractAnalyticsAlgorithm::AbstractAnalyticsAlgorithm(QObject *parent) noexcept :
9 | QObject(parent)
10 | {
11 | connect(this, &AbstractAnalyticsAlgorithm::ready, this, &AbstractAnalyticsAlgorithm::start);
12 | }
13 |
14 | AbstractAnalyticsAlgorithm::Ptr AbstractAnalyticsAlgorithm::createAlgo(const AnalyticsAlgoType type) noexcept
15 | {
16 | switch (type) {
17 | case TrendSearcherAlgo:
18 | return QSharedPointer::create();
19 | }
20 | return nullptr;
21 | }
22 |
23 | void AbstractAnalyticsAlgorithm::run() noexcept
24 | {
25 | emit ready();
26 | }
27 |
28 | void AbstractAnalyticsAlgorithm::setTradeAlgo(const QSharedPointer &algo) noexcept
29 | {
30 | m_TradeAlgo = algo;
31 |
32 | auto marketsStorage = m_TradeAlgo->api()->marketsStorage();
33 | assert(marketsStorage);
34 | connect(this, &AbstractAnalyticsAlgorithm::updateMarketConfig, marketsStorage, &MarketsStorage::updateMarketUserConfig, Qt::QueuedConnection);
35 |
36 | connect(this, &AbstractAnalyticsAlgorithm::cancelOrderId, m_TradeAlgo->api()->controller().get(), &IExchangeApiController::cancelOrder);
37 | connect(this, &AbstractAnalyticsAlgorithm::submitSellOrderToBuyPrice, m_TradeAlgo->api()->controller().get(), &IExchangeApiController::submitOrder);
38 | }
39 |
40 | QSharedPointer AbstractAnalyticsAlgorithm::tradeAlgo() const
41 | {
42 | return m_TradeAlgo;
43 | }
44 |
--------------------------------------------------------------------------------
/src/network/http_client.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBCLIENT_H
2 | #define WEBCLIENT_H
3 | #include
4 |
5 | class QSslError;
6 | class QAuthenticator;
7 | class QNetworkReply;
8 | class QNetworkSession;
9 |
10 | class WebClient final : public QObject
11 | {
12 | Q_OBJECT
13 | public:
14 | explicit WebClient (QObject *parent = nullptr) noexcept;
15 | explicit WebClient(const WebClient &o) noexcept = delete;
16 | WebClient& operator=(const WebClient &o) noexcept = delete;
17 | ~WebClient() override;
18 | QNetworkReply * head(const QNetworkRequest &request) noexcept;
19 | QNetworkReply * get(const QNetworkRequest &request) noexcept;
20 | QNetworkReply * post(const QNetworkRequest &request, const QByteArray &data) noexcept;
21 | QNetworkReply * put(const QNetworkRequest &request, const QByteArray &data) noexcept;
22 | QNetworkReply * del(const QNetworkRequest &request) noexcept;
23 | inline quint32 requestCount() const noexcept {
24 | return m_requestCount;
25 | }
26 | private slots:
27 | void slotAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator) noexcept;
28 | #ifndef QT_NO_SSL
29 | void sslErrors(QNetworkReply *, const QList &errors) noexcept;
30 | #endif
31 | void timerEvent(QTimerEvent *event) noexcept final;
32 | private:
33 | inline void incRequestCount() noexcept {
34 | m_requestCount++;
35 | }
36 | bool isOnline();
37 | QNetworkAccessManager m_NetworkAccessManager{};
38 | QNetworkSession *m_session = nullptr;
39 | quint32 m_requestCount{0};
40 | qint32 m_GlobalRequestCountTimerId{0};
41 | };
42 |
43 | #endif // WEBCLIENT_H
44 |
--------------------------------------------------------------------------------
/include/init_logger.h:
--------------------------------------------------------------------------------
1 | #ifndef INIT_LOGGER_H
2 | #define INIT_LOGGER_H
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | void initLogger(QCoreApplication *app, const Logger::LogLevel level)
12 | {
13 | #ifndef QT_NO_DEBUG
14 | const QString logDirName{app->applicationDirPath() + QStringLiteral("/logs")};
15 | #else
16 | const QString logDirName{QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QString(QStringLiteral("/.%1/logs")).arg(GLOBAL_APP_NAME)};
17 | #endif
18 | QDir logDir{logDirName};
19 | if ( !logDir.exists() )
20 | logDir.mkpath(logDirName);
21 |
22 | const QString logFormat{QStringLiteral("[%{time}{dd-MM-yyyy HH:mm:ss}] [%{type}] <%{function}:%{line}> %{message}\n")};
23 | const QString &fileFormat = QString("%1/%2.log")
24 | .arg(logDirName)
25 | .arg(app->applicationName());
26 | #ifndef QT_NO_DEBUG
27 | ConsoleAppender *consoleAppender = new ConsoleAppender();
28 | consoleAppender->setFormat(logFormat);
29 | consoleAppender->setDetailsLevel(level);
30 | cuteLogger->registerAppender(consoleAppender);
31 | #endif
32 | RollingFileAppender *rollingFileAppender = new RollingFileAppender(fileFormat);
33 | rollingFileAppender->setFormat(logFormat);
34 | rollingFileAppender->setDetailsLevel(level);
35 | rollingFileAppender->setDatePattern(RollingFileAppender::DailyRollover);
36 | cuteLogger->registerAppender(rollingFileAppender);
37 | }
38 | #endif // INIT_LOGGER_H
39 |
--------------------------------------------------------------------------------
/src/models/markets_model.h:
--------------------------------------------------------------------------------
1 | #ifndef MARKETSMODEL_H
2 | #define MARKETSMODEL_H
3 | #include
4 | #include
5 |
6 | class MarketsModel : public QAbstractListModel
7 | {
8 | Q_OBJECT
9 | public:
10 | enum MarketsModelRoles {
11 | MarketRole = Qt::UserRole + 1,
12 | IsTradableRole
13 | };
14 |
15 | explicit MarketsModel(QObject *parent = nullptr) noexcept;
16 | const Market::ConstPtr findMarketById(const Market::MarketId &id) const noexcept;
17 | const Currency::ConstPtr findCurrencyById(const Currency::CurrencyId &id) const noexcept;
18 | private:
19 | int rowCount(const QModelIndex &parent = QModelIndex()) const noexcept override;
20 | QVariant data(const QModelIndex &index, int role = Qt::UserRole) const noexcept override;
21 | bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) noexcept override;
22 | QHash roleNames() const noexcept override;
23 | public slots:
24 | void mergeCurrencies(const QList &data) noexcept;
25 | void mergeMarketInfo(const QList &data) noexcept;
26 | void mergeMarketData(const QList &data) noexcept;
27 | void refresh() noexcept;
28 | void updateMarketConfig(const Market::MarketId &marketId, const Market::UserConfig &config) noexcept;
29 | signals:
30 | void removeTradePairIdFromTrading(const Market::MarketId &id);
31 | void mergeCompeleted();
32 | private slots:
33 | void cancelTradingMarket(const Market::MarketId &id) noexcept;
34 | private:
35 | Market::Container m_Data{};
36 | Currency::Container m_Currencys{};
37 | };
38 | #endif // MARKETSMODEL_H
39 |
--------------------------------------------------------------------------------
/launcher/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.11)
2 |
3 | project(Launcher LANGUAGES CXX)
4 | set(TARGET_NAME ${PROJECT_NAME})
5 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
6 | set(CMAKE_INCLUDE_CURRENT_DIR ON)
7 | set(CMAKE_AUTOMOC ON)
8 | set(CMAKE_CXX_STANDARD 17)
9 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
10 |
11 | include(../cmake/utils.cmake)
12 | enable_all_warnings()
13 |
14 | find_package(Qt5 5.12.10 REQUIRED COMPONENTS Core)
15 | file(GLOB_RECURSE HEADER_FILES "*.h")
16 | file(GLOB_RECURSE SOURCE_FILES "*.cpp" )
17 |
18 | if(WIN32)
19 | include(../cmake/generate_product_version.cmake)
20 |
21 | get_filename_component(ICON_PATH
22 | "${CMAKE_CURRENT_SOURCE_DIR}/../resources/ui_icons/rabbi.ico"
23 | ABSOLUTE)
24 |
25 | generate_product_version(
26 | VersionFilesOutputVariableLauncher
27 | NAME "${PROJECT_NAME}"
28 | ICON "${ICON_PATH}"
29 | VERSION_MAJOR ${${PROJECT_NAME}_VERSION_MAJOR}
30 | VERSION_MINOR ${${PROJECT_NAME}_VERSION_MINOR}
31 | VERSION_PATCH ${${PROJECT_NAME}_VERSION_PATCH}
32 | COMPANY_COPYRIGHT "https://github.com/man-k28/CryptoShloma"
33 | )
34 | add_executable(${PROJECT_NAME} WIN32 ${HEADER_FILES} ${SOURCE_FILES} ${VersionFilesOutputVariableLauncher})
35 | target_link_options(${TARGET_NAME} PRIVATE -mwindows)
36 | else()
37 | add_executable(${PROJECT_NAME} ${HEADER_FILES} ${SOURCE_FILES})
38 | endif()
39 | target_compile_definitions(${PROJECT_NAME} PRIVATE $<$,$>:QT_QML_DEBUG>)
40 | target_include_directories(${PROJECT_NAME} PRIVATE ../src ../include)
41 | target_link_libraries(${PROJECT_NAME} PRIVATE
42 | Qt5::Core
43 | CuteLogger
44 | )
45 |
--------------------------------------------------------------------------------
/src/models/buy_orders_proxy_model.cpp:
--------------------------------------------------------------------------------
1 | #include "buy_orders_proxy_model.h"
2 | #include "market_orders_model.h"
3 |
4 | BuyOrdersProxyModel::BuyOrdersProxyModel(QObject *parent) noexcept :
5 | QSortFilterProxyModel(parent)
6 | {
7 | setDynamicSortFilter(true);
8 | sort(0, Qt::DescendingOrder);
9 | }
10 |
11 | //void BuyOrdersProxyModel::refresh() noexcept
12 | //{
13 | // qobject_cast(sourceModel())->refresh();
14 | //}
15 |
16 | bool BuyOrdersProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const noexcept
17 | {
18 | const auto & leftVariant = sourceModel()->data( left, MarketOrdersModel::OrderRole );
19 | const auto & rightVariant = sourceModel()->data( right, MarketOrdersModel::OrderRole );
20 | Q_ASSERT_X(leftVariant.canConvert< Order * >() && rightVariant.canConvert< Order * >(), "QVariant convert", "BuyOrdersProxyModel::lessThan" );
21 |
22 | const auto & leftOrder = leftVariant.value< Order * >();
23 | const auto & rightOrder = rightVariant.value< Order * >();
24 |
25 | return leftOrder->getPrice() < rightOrder->getPrice(); //FIXME: double compare
26 | }
27 |
28 | bool BuyOrdersProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept
29 | {
30 | const QModelIndex &buyTypeIndex = sourceModel()->index(sourceRow, 0, sourceParent);
31 | if ( !buyTypeIndex.isValid() ) {
32 | return false;
33 | }
34 | const auto &variant = sourceModel()->data( buyTypeIndex, MarketOrdersModel::OrderRole );
35 | Q_ASSERT_X(variant.canConvert< Order * >(), "QVariant convert", "BuyOrdersProxyModel::filterAcceptsRow" );
36 |
37 | const auto &order = variant.value< Order * >();
38 |
39 | return ( order->getType() == Order::Buy);
40 | }
41 |
--------------------------------------------------------------------------------
/src/models/sell_orders_proxy_model.cpp:
--------------------------------------------------------------------------------
1 | #include "sell_orders_proxy_model.h"
2 | #include "market_orders_model.h"
3 |
4 | SellOrdersProxyModel::SellOrdersProxyModel(QObject *parent) noexcept :
5 | QSortFilterProxyModel(parent)
6 | {
7 | setDynamicSortFilter(true);
8 | sort(0, Qt::AscendingOrder);
9 | }
10 |
11 | //void SellOrdersProxyModel::refresh() noexcept
12 | //{
13 | // qobject_cast(sourceModel())->refresh();
14 | //}
15 |
16 | bool SellOrdersProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const noexcept
17 | {
18 | const auto & leftVariant = sourceModel()->data( left, MarketOrdersModel::OrderRole );
19 | const auto & rightVariant = sourceModel()->data( right, MarketOrdersModel::OrderRole );
20 | Q_ASSERT_X(leftVariant.canConvert< Order * >() && rightVariant.canConvert< Order * >(), "QVariant convert", "SellOrdersProxyModel::lessThan" );
21 |
22 | const auto & leftOrder = leftVariant.value< Order * >();
23 | const auto & rightOrder = rightVariant.value< Order * >();
24 |
25 | return leftOrder->getPrice() < rightOrder->getPrice(); //FIXME: double compare
26 | }
27 |
28 | bool SellOrdersProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept
29 | {
30 | const QModelIndex &sellTypeIndex = sourceModel()->index(sourceRow, 0, sourceParent);
31 | if ( !sellTypeIndex.isValid() ) {
32 | return false;
33 | }
34 | const auto &variant = sourceModel()->data( sellTypeIndex, MarketOrdersModel::OrderRole );
35 | Q_ASSERT_X(variant.canConvert< Order * >(), "QVariant convert", "SellOrdersProxyModel::filterAcceptsRow" );
36 |
37 | const auto &order = variant.value< Order * >();
38 |
39 | return ( order->getType() == Order::Sell );
40 | }
41 |
--------------------------------------------------------------------------------
/resources/qml/BaseElements/BusyIndicatorStyled.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.12
2 | import QtQuick.Controls 2.12
3 | import QtQuick.Controls.Material 2.12
4 |
5 | BusyIndicator {
6 | anchors.horizontalCenter: parent.horizontalCenter
7 | anchors.verticalCenter: parent.verticalCenter
8 | id: indicator
9 |
10 | contentItem: Item {
11 | id: item
12 | x: parent.width / 2 - 32
13 | y: parent.height / 2 - 32
14 | implicitWidth: 64
15 | implicitHeight: 64
16 | width: 64
17 | height: 64
18 | opacity: indicator.running ? 1 : 0
19 |
20 | Behavior on opacity {
21 | OpacityAnimator {
22 | duration: 250
23 | }
24 | }
25 |
26 | RotationAnimator {
27 | target: item
28 | running: indicator.visible && indicator.running
29 | from: 0
30 | to: 360
31 | loops: Animation.Infinite
32 | duration: 1250
33 | }
34 |
35 | Repeater {
36 | id: repeater
37 | model: 6
38 |
39 | Rectangle {
40 | x: item.width / 2 - width / 2
41 | y: item.height / 2 - height / 2
42 | implicitWidth: 10
43 | implicitHeight: 10
44 | radius: 5
45 | color: Material.color(Material.Green)
46 | transform: [
47 | Translate {
48 | y: -Math.min(item.width, item.height) * 0.5 + 5
49 | },
50 | Rotation {
51 | angle: index / repeater.count * 360
52 | origin.x: 5
53 | origin.y: 5
54 | }
55 | ]
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/algo/hanukkah.h:
--------------------------------------------------------------------------------
1 | #ifndef HANUKKAH_H
2 | #define HANUKKAH_H
3 | #include "i_trade_algo.h"
4 | #include "hanukkah/i_step.h"
5 | #include
6 | #include
7 |
8 | class Hanukkah;
9 | #pragma pack (push, 1)
10 | class Hanukkah final: public ITradeAlgorithm
11 | {
12 | Q_OBJECT
13 | public:
14 | explicit Hanukkah(QObject *parent = nullptr) noexcept;
15 | ~Hanukkah() noexcept override;
16 | void unlockAllSteps(const Market::MarketId &id) noexcept;
17 | private slots:
18 | bool start() noexcept override final;
19 | bool stop() noexcept override final;
20 | bool restart() noexcept override final;
21 | void reconfigure() noexcept override final;
22 | void timerEvent(QTimerEvent *event) noexcept override final;
23 | void removeMarket(const Market::MarketId &id) noexcept override final;
24 | private:
25 | void execLogic() noexcept;
26 | private:
27 | class StepGenerator
28 | {
29 | public:
30 | explicit StepGenerator() = default;
31 | explicit StepGenerator(const QJsonArray &data, Hanukkah * const parentAlgo, const Market::ConstPtr &market) noexcept;
32 | explicit StepGenerator(const StepGenerator &o) noexcept;
33 | StepGenerator& operator=(const StepGenerator &o) noexcept;
34 | bool update(const QJsonArray &data) noexcept;
35 | QJsonArray metaConfig = {};
36 | IStep::StepContainer container = {};
37 | Market::ConstPtr market() const;
38 | private:
39 | void setup() noexcept;
40 | Hanukkah * m_parentAlgo = nullptr;
41 | Market::ConstPtr m_market = {};
42 | };
43 |
44 | using SessionContainer = QMap;
45 | SessionContainer m_sessionContainer = {};
46 | qint32 m_timerId = 0;
47 | };
48 | #pragma pack (pop)
49 |
50 | #endif // HANUKKAH_H
51 |
--------------------------------------------------------------------------------
/src/storage/markets_storage.h:
--------------------------------------------------------------------------------
1 | #ifndef MARKETS_STORAGE_H
2 | #define MARKETS_STORAGE_H
3 |
4 | #include
5 | #include
6 | class MarketsStorage final : public QObject
7 | {
8 | Q_OBJECT
9 | public:
10 | explicit MarketsStorage(QObject *parent = nullptr) noexcept;
11 | public:
12 | const Currency::ConstPtr findCurrencyById(const Currency::CurrencyId &id) const noexcept;
13 | const Currency::ConstPtr findCurrencyBySymbol(const QString &symbol) const noexcept;
14 | const Market::ConstPtr findMarketById(const Market::MarketId &id) const noexcept;
15 | const Market::ConstPtr findMarketByCurrencyId(const Currency::CurrencyId &id) const noexcept;
16 | const Market::ConstPtr findMarketBySymbol(const QString &symbol) const noexcept;
17 | const Market::ConstPtr findMarketByLabel(const QString &label) const noexcept;
18 | const Market::MarketId findMarketIdBySymbol(const QString &symbol) const noexcept;
19 |
20 | const Market::Container filterTradingPairs() const noexcept;
21 | // quint32 getCurrencysSequential() const noexcept;
22 | // quint32 getMarketsSequential() const noexcept;
23 | public slots:
24 | void mergeCurrencies(const QList &data) noexcept;
25 | void mergeMarketInfo(const QList &data) noexcept;
26 | void mergeMarketData(const QList &data) noexcept;
27 | void updateMarketUserConfig(const Market::MarketId &marketId, const Market::UserConfig &config) noexcept;
28 | signals:
29 | void removeTradePairIdFromTrading(const Market::MarketId &id);
30 | private slots:
31 | void cancelTradingMarket(const Market::MarketId &id) noexcept;
32 | private:
33 | Market::Container m_Data{};
34 | Currency::Container m_Currencys{};
35 | QReadWriteLock lock{};
36 | };
37 |
38 | #endif // MARKETS_STORAGE_H
39 |
--------------------------------------------------------------------------------
/src/api/temporary_orders_table.h:
--------------------------------------------------------------------------------
1 | #ifndef TEMPORARYORDERSTABLE_H
2 | #define TEMPORARYORDERSTABLE_H
3 |
4 | #include
5 |
6 | class TemporaryOrdersTable final : public QObject
7 | {
8 | Q_OBJECT
9 | public:
10 | struct OrderRecord {
11 | /*!
12 | * \brief For create new
13 | */
14 | explicit OrderRecord(const Market::MarketId &marketId,
15 | Order::OrderType type,
16 | const qreal &price,
17 | const qreal &baseVolume,
18 | const qreal &volume = 0.) noexcept;
19 | /*!
20 | * \brief For update exist
21 | */
22 | explicit OrderRecord(const Market::MarketId &marketId,
23 | const Order::OrderId &orderId,
24 | const QDateTime ×tamp,
25 | const qreal &price,
26 | const qreal &baseVolume,
27 | Order::OrderType type,
28 | const qreal &volume) noexcept;
29 | Market::MarketId marketId = {};
30 | Order::OrderId orderId = {};
31 | Order::OrderType orderType = Order::Buy;
32 | qreal volume = 0.;
33 | qreal baseVolume = 0.;
34 | qreal price = 0.;
35 | QDateTime timestamp = {};
36 | };
37 | public:
38 | explicit TemporaryOrdersTable(QObject *parent = nullptr) noexcept;
39 | bool submitOrder(const OrderRecord &record);
40 | public slots:
41 | void updatePlaceOrder(const OrderRecord &record);
42 | void updateEraseOrder(const OrderRecord &record); //Для данных из submitOrder
43 | void updateEraseOrder(const Order::OrderId &orderId); //Для данных с истории торгов
44 | private:
45 | QList m_data = {};
46 | };
47 |
48 | #endif // TEMPORARYORDERSTABLE_H
49 |
--------------------------------------------------------------------------------
/resources/ui_icons/settings-1.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/models/balances_proxy_model.cpp:
--------------------------------------------------------------------------------
1 | #include "balances_proxy_model.h"
2 | #include "balances_model.h"
3 |
4 | BalancesProxyModel::BalancesProxyModel(QObject *parent) noexcept :
5 | QSortFilterProxyModel(parent)
6 | {
7 | setDynamicSortFilter(true);
8 | sort(0, Qt::AscendingOrder);
9 | }
10 |
11 | //void BalancesProxyModel::refresh() noexcept
12 | //{
13 | // qobject_cast(sourceModel())->refresh();
14 | //}
15 |
16 | //void BalancesProxyModel::setFilterMarketId(const Market::MarketId &id) noexcept
17 | //{
18 | // m_marketId = id;
19 | // invalidateFilter();
20 | //}
21 |
22 | bool BalancesProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const noexcept
23 | {
24 | const auto & leftVariant = sourceModel()->data( left, BalancesModel::BalanceRole );
25 | const auto & rightVariant = sourceModel()->data( right, BalancesModel::BalanceRole );
26 | Q_ASSERT_X(leftVariant.canConvert< Balance * >() && rightVariant.canConvert< Balance * >(), "QVariant convert", "BalancesProxyModel::lessThan" );
27 |
28 | const auto & leftBalance = leftVariant.value< Balance * >();
29 | const auto & rightBalance = rightVariant.value< Balance * >();
30 |
31 | return leftBalance->getCurrency()->getId() < rightBalance->getCurrency()->getId();
32 | }
33 |
34 | bool BalancesProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept
35 | {
36 | const QModelIndex &rowIndex = sourceModel()->index(sourceRow, 0, sourceParent);
37 | if ( !rowIndex.isValid() ) {
38 | return false;
39 | }
40 | const auto &variant = sourceModel()->data( rowIndex, BalancesModel::BalanceRole );
41 | Q_ASSERT_X(variant.canConvert< Balance * >(), "QVariant convert", "BalancesProxyModel::filterAcceptsRow" );
42 |
43 | const auto &balance = variant.value< Balance * >();
44 |
45 | return !qFuzzyIsNull(balance->getTotal());
46 | }
47 |
--------------------------------------------------------------------------------
/src/api/i_exchange_api_controller.h:
--------------------------------------------------------------------------------
1 | #ifndef I_EXCHANGE_API_CONTROLLER_H
2 | #define I_EXCHANGE_API_CONTROLLER_H
3 | #include "base/order.h"
4 | class IExchangeAPI;
5 |
6 | class IExchangeApiController : public QObject
7 | {
8 | Q_OBJECT
9 | public:
10 | using Ptr = QSharedPointer;
11 | using ConstPtr = QSharedPointer;
12 | using MarketsGroup = QHash;
13 | public:
14 | explicit IExchangeApiController(IExchangeAPI *api) noexcept
15 | : QObject()
16 | , m_api(api) {}
17 | explicit IExchangeApiController(const IExchangeApiController &o) noexcept = delete;
18 | IExchangeApiController& operator=(const IExchangeApiController &o) noexcept = delete;
19 | ~IExchangeApiController() override = default;
20 | public slots:
21 | virtual void run() noexcept = 0;
22 | virtual void appendMarket(const Market::MarketId &marketId,
23 | const Market::UserConfig &config) = 0;
24 | virtual void appendMarketsGroup(const MarketsGroup &group) = 0;
25 | virtual void removeMarket(const Market::MarketId &marketId) = 0;
26 | virtual void cancelAllOrders() = 0;
27 | virtual void cancelOrder(const Market::MarketId &marketId,
28 | const Order::OrderId &orderId) = 0;
29 | virtual void submitOrder(const Market::MarketId &marketId,
30 | const qreal &price,
31 | const qreal ¤cyVolume) = 0;
32 | virtual void dropCoin(const Currency::CurrencyId ¤cyId) = 0;
33 | signals:
34 | void appendedMarket(const Market::MarketId &);
35 | void removedMarket(const Market::MarketId &);
36 | void updateMarketConfig(const Market::MarketId &id, const Market::UserConfig &config);
37 | protected:
38 | IExchangeAPI * m_api;
39 | };
40 |
41 | #endif // I_EXCHANGE_API_CONTROLLER_H
42 |
--------------------------------------------------------------------------------
/src/common/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef UTILS_H
2 | #define UTILS_H
3 | #include
4 | #include
5 |
6 | namespace CryptoShloma {
7 | namespace Utils {
8 | inline QString toDoublePrec8(const qreal &val) noexcept
9 | {
10 | return QString::number(val, 'f', 8);
11 | }
12 |
13 | inline QString toULongLong(const qreal &val) noexcept //TODO: deprecated
14 | {
15 | return QString::number(static_cast(val));
16 | }
17 |
18 | inline QString toDoublePrec1(const qreal &val) noexcept //TODO: deprecated
19 | {
20 | return QString::number(val, 'f', 1);
21 | }
22 |
23 | inline qreal toDouble(const QJsonValue &val) noexcept
24 | {
25 | return val.toString().toDouble(); //FIXME: добавлено из-за того, что QJSonValue.toDouble() теряет точность при уже при 7 знаках, может баг Qt
26 | }
27 |
28 | inline qreal roundingFloor(const qreal &value, const qreal &rounding)
29 | {
30 | Q_ASSERT_X(!qFuzzyIsNull(value), "devide", "Devision by zero");
31 | const qreal devide = rounding / value;
32 | const qreal round = std::floor(devide);
33 | const qreal ret = round * value;
34 | return ret;
35 | }
36 |
37 | inline qreal roundingCeil(const qreal &value, const qreal &rounding)
38 | {
39 | Q_ASSERT_X(!qFuzzyIsNull(value), "devide", "Devision by zero");
40 | const qreal devide = rounding / value;
41 | const qreal round = std::ceil(devide);
42 | const qreal ret = round * value;
43 | return ret;
44 | }
45 |
46 | inline qreal rounding(const qreal &value, const qreal &rounding)
47 | {
48 | Q_ASSERT_X(!qFuzzyIsNull(value), "devide", "Devision by zero");
49 | qint64 round = static_cast((rounding * std::pow(10,8)) / (value * std::pow(10,8)));
50 | return static_cast(round )* value;
51 | }
52 | }
53 | }
54 | #endif // UTILS_H
55 |
--------------------------------------------------------------------------------
/src/algo/spreder.h:
--------------------------------------------------------------------------------
1 | #ifndef SPREDER_H
2 | #define SPREDER_H
3 | #include "i_trade_algo.h"
4 | #include
5 |
6 | class Spreder final: public ITradeAlgorithm
7 | {
8 | Q_OBJECT
9 | public:
10 | explicit Spreder(QObject *parent = nullptr) noexcept;
11 | ~Spreder() override = default;
12 | private slots:
13 | bool start() noexcept override final;
14 | bool stop() noexcept override final;
15 | bool restart() noexcept override final;
16 | void reconfigure() noexcept override final;
17 | void timerEvent(QTimerEvent *event) noexcept final;
18 | private:
19 | void startSubmitOrders(const Market::ConstPtr &market, const bool sellMode);
20 | void dropCoin(const Market::ConstPtr &market);
21 |
22 | struct Historydata {
23 | qreal amountBtc{0.};
24 | qreal rate{0.};
25 | qreal fee{0.};
26 | qreal amountCurrency{0.};
27 | };
28 |
29 | qreal calculateProfit(const qreal &bid, const qreal &ask, const qreal &fee) const;
30 | qreal calculateStopLoss(const qreal &oldBid,
31 | const qreal &oldFee,
32 | const qreal &oldAmountBtc,
33 | const qreal &fee,
34 | const qreal &oldAmountCurrency,
35 | const qreal &pairProfit) const;
36 | qreal calculateBuyIn(const qreal &oldBid,
37 | const qreal &oldFee,
38 | const qreal &fee,
39 | const qreal &oldAmountCurrency,
40 | const qreal &pairProfit,
41 | const qreal &step) const;
42 |
43 | Historydata findPreviousBuyOrders(const Order::ConstContainer &container) const noexcept;
44 | QPair getStepMerchant(const qreal &trend) const;
45 | void searchAndCancelOrders(const Order::ConstContainer &container) noexcept;
46 | };
47 |
48 | #endif // SPREDER_H
49 |
--------------------------------------------------------------------------------
/resources/ui_icons/store.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/resources/ui_icons/bitcoin.svg:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/.github/workflows/cmake.yml:
--------------------------------------------------------------------------------
1 | name: CMake
2 |
3 | on: [workflow_dispatch]
4 |
5 | env:
6 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
7 | BUILD_TYPE: Release
8 |
9 | jobs:
10 | build:
11 | # The CMake configure and build commands are platform agnostic and should work equally
12 | # well on Windows or Mac. You can convert this to a matrix build if you need
13 | # cross-platform coverage.
14 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 |
20 | - name: Create Build Environment
21 | # Some projects don't allow in-source building, so create a separate build directory
22 | # We'll use this as our working directory for all subsequent commands
23 | #run: cmake -E make_directory ${{runner.workspace}}/build
24 |
25 | #- name: Configure CMake
26 | # Use a bash shell so we can use the same syntax for environment variable
27 | # access regardless of the host operating system
28 | #shell: bash
29 | #working-directory: ${{runner.workspace}}/build
30 | # Note the current convention is to use the -S and -B options here to specify source
31 | # and build directories, but this is only available with CMake 3.13 and higher.
32 | # The CMake binaries on the Github Actions machines are (as of this writing) 3.12
33 | run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE
34 |
35 | - name: Build
36 | #working-directory: ${{runner.workspace}}/build
37 | #shell: bash
38 | # Execute the build. You can specify a specific target with "--target "
39 | run: cmake --build . --config $BUILD_TYPE
40 |
41 | #- name: Test
42 | # working-directory: ${{runner.workspace}}/build
43 | # shell: bash
44 | # # Execute tests defined by the CMake configuration.
45 | # # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
46 | # run: ctest -C $BUILD_TYPE
47 |
--------------------------------------------------------------------------------
/src/models/spread_markets_proxy_model.cpp:
--------------------------------------------------------------------------------
1 | #include "spread_markets_proxy_model.h"
2 | #include "markets_model.h"
3 | #include
4 |
5 | SpreadMarketsProxyModel::SpreadMarketsProxyModel(QObject *parent) noexcept :
6 | QSortFilterProxyModel(parent)
7 | {
8 | setDynamicSortFilter(true);
9 | sort(0, Qt::DescendingOrder);
10 | }
11 |
12 | bool SpreadMarketsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const noexcept
13 | {
14 | const auto & leftVariant = sourceModel()->data( left, MarketsModel::MarketRole );
15 | const auto & rightVariant = sourceModel()->data( right, MarketsModel::MarketRole );
16 | Q_ASSERT_X(leftVariant.canConvert< Market * >() && rightVariant.canConvert< Market * >(), "QVariant convert", "SpreadMarketsProxyModel::lessThan" );
17 |
18 | const auto & leftMarket = leftVariant.value< Market * >();
19 | const auto & rightMarket = rightVariant.value< Market * >();
20 |
21 | return leftMarket->getSpread() < rightMarket->getSpread(); //FIXME: double compare
22 | }
23 |
24 | bool SpreadMarketsProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept
25 | {
26 | const QModelIndex &indexRow = sourceModel()->index(sourceRow, 0, sourceParent);
27 | if ( !indexRow.isValid() ) {
28 | return false;
29 | }
30 | const auto &variant = sourceModel()->data( indexRow, MarketsModel::MarketRole );
31 | Q_ASSERT_X(variant.canConvert< Market * >(), "QVariant convert", "SpreadMarketsProxyModel::filterAcceptsRow" );
32 |
33 | const auto &market = variant.value< Market * >();
34 | bool filterText = true;
35 | const auto &pattern = filterRegExp().pattern();
36 | if ( !pattern.isEmpty() )
37 | filterText = market->getId().get().contains(pattern, Qt::CaseInsensitive);
38 |
39 | return ( market->getBaseVolume() > SettingsManager::get(SettingsManager::MinBaseVolume).toReal() ) &&
40 | ( market->getSpread() > 0 ) &&
41 | ( market->getStatus() == Market::Ok ) &&
42 | ( !market->getIsTradable() &&
43 | filterText);
44 | }
45 |
--------------------------------------------------------------------------------
/resources/ui_icons/clock-1.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/algo/i_trade_algo.cpp:
--------------------------------------------------------------------------------
1 | #include "i_trade_algo.h"
2 | #include
3 | #include "hanukkah.h"
4 | #include "spreder.h"
5 | #include
6 | #include
7 |
8 | ITradeAlgorithm::ITradeAlgorithm(QObject *parent) noexcept
9 | : QObject(parent)
10 | {
11 | connect(this, &ITradeAlgorithm::ready, this, &ITradeAlgorithm::start, Qt::QueuedConnection);
12 | }
13 |
14 | ITradeAlgorithm::Ptr ITradeAlgorithm::createAlgo(const AlgoType type, const Exchange::Type exchType) noexcept
15 | {
16 | auto api = IExchangeAPI::createExchangeApi(exchType);
17 | api->setAutoDelete(false);
18 | QSharedPointer algo;
19 | switch (type) {
20 | case SprederAlgo:
21 | algo = QSharedPointer::create();
22 | break;
23 | case HanukkahAlgo:
24 | algo = QSharedPointer::create();
25 | break;
26 | }
27 |
28 | // QObject::connect(api.get(), &IExchangeAPI::destroyed, algo.get(), [&algo](){algo.clear();});
29 | algo->setApi(api);
30 | return algo;
31 | }
32 |
33 | void ITradeAlgorithm::run() noexcept
34 | {
35 | QThreadPool::globalInstance()->start(m_Api.get());
36 | connect(this, &ITradeAlgorithm::ready, m_Api->controller().get(), &IExchangeApiController::run);
37 | emit ready();
38 | }
39 |
40 | void ITradeAlgorithm::setApi(const QSharedPointer &api) noexcept
41 | {
42 | m_Api = api;
43 | auto marketsStorage = api->marketsStorage();
44 | assert(marketsStorage);
45 | connect(m_Api->controller().get(), &IExchangeApiController::updateMarketConfig, marketsStorage, &MarketsStorage::updateMarketUserConfig, Qt::QueuedConnection);
46 | connect(m_Api->controller().get(), &IExchangeApiController::removedMarket, this, &ITradeAlgorithm::removeMarket);
47 | connect(this, &ITradeAlgorithm::updateMarketConfig, api->marketsStorage(), &MarketsStorage::updateMarketUserConfig, Qt::QueuedConnection);
48 | }
49 |
50 | void ITradeAlgorithm::init() noexcept
51 | {
52 | connect(m_Api->marketsStorage(), &MarketsStorage::removeTradePairIdFromTrading, m_Api->controller().get(), &IExchangeApiController::removeMarket);
53 | }
54 |
--------------------------------------------------------------------------------
/src/models/volume_markets_proxy_model.cpp:
--------------------------------------------------------------------------------
1 | #include "volume_markets_proxy_model.h"
2 | #include "markets_model.h"
3 | #include
4 |
5 | VolumeMarketsProxyModel::VolumeMarketsProxyModel(QObject *parent) noexcept :
6 | QSortFilterProxyModel(parent)
7 | {
8 | setDynamicSortFilter(true);
9 | sort(0, Qt::DescendingOrder);
10 | }
11 |
12 | bool VolumeMarketsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const noexcept
13 | {
14 | const auto & leftVariant = sourceModel()->data( left, MarketsModel::MarketRole );
15 | const auto & rightVariant = sourceModel()->data( right, MarketsModel::MarketRole );
16 | Q_ASSERT_X(leftVariant.canConvert< Market * >() && rightVariant.canConvert< Market * >(), "QVariant convert", "VolumeMarketsProxyModel::lessThan" );
17 |
18 | const auto & leftMarket = leftVariant.value< Market * >();
19 | const auto & rightMarket = rightVariant.value< Market * >();
20 |
21 | return leftMarket->getBaseVolume() < rightMarket->getBaseVolume(); //FIXME: double compare
22 | }
23 |
24 | bool VolumeMarketsProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const noexcept
25 | {
26 | const QModelIndex &indexRow = sourceModel()->index(sourceRow, 0, sourceParent);
27 | if ( !indexRow.isValid() ) {
28 | return false;
29 | }
30 | const auto &variant = sourceModel()->data( indexRow, MarketsModel::MarketRole );
31 | Q_ASSERT_X(variant.canConvert< Market * >(), "QVariant convert", "VolumeMarketsProxyModel::filterAcceptsRow" );
32 | const auto &market = variant.value< Market * >();
33 | bool filterText = true;
34 | const auto &pattern = filterRegExp().pattern();
35 | if ( !pattern.isEmpty() )
36 | filterText = market->getId().get().contains(pattern, Qt::CaseInsensitive);
37 |
38 | return ( market->getLastPrice() > SettingsManager::get(SettingsManager::MinCoinPrice).toReal() ) &&
39 | ( market->getBaseVolume() > SettingsManager::get(SettingsManager::MinBaseVolume).toReal() ) &&
40 | ( market->getStatus() == Market::Ok ) &&
41 | ( !market->getIsTradable() &&
42 | filterText );
43 | }
44 |
--------------------------------------------------------------------------------
/src/network/websocket_client.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBSOCKETCLIENT_H
2 | #define WEBSOCKETCLIENT_H
3 |
4 | #include
5 | #include
6 |
7 | class QElapsedTimer;
8 | class QSslError;
9 | class QNetworkSession;
10 | class QTimer;
11 |
12 | class WebSocketClient final: public QObject
13 | {
14 | Q_OBJECT
15 | public:
16 | explicit WebSocketClient(QObject *parent = nullptr);
17 | explicit WebSocketClient(const WebSocketClient &o) noexcept = delete;
18 | WebSocketClient& operator=(const WebSocketClient &o) noexcept = delete;
19 | ~WebSocketClient();
20 | public slots:
21 | void open();
22 | void close();
23 | void ping();
24 | public:
25 | void setBaseTemplate(const QString &baseTempl) noexcept;
26 | void addStreamTemplate(const QString &templ) noexcept;
27 | void removeStreamTemplate(const QString &templ, bool tryReconnect = true) noexcept;
28 |
29 | const QWebSocket *get() noexcept;
30 | bool isConnected() const noexcept;
31 | bool isOpen() const noexcept;
32 | const QNetworkSession * session() noexcept;
33 | private slots:
34 | void onConnected();
35 | void onDisconnected();
36 | void onPong(quint64 elapsedTime, const QByteArray &payload);
37 | void onTextMessageReceived(const QString &message);
38 | void onBinaryMessageReceived(const QByteArray &message);
39 | // void onBinaryFrameReceived(const QByteArray &message);
40 | // void onTextFrameReceived(const QString &frame, bool isLastFrame);
41 | void onError(QAbstractSocket::SocketError error);
42 | private slots:
43 | void onNetworkSessionOpened();
44 | void onNetworkSessionClosed();
45 | void onNetworkSessionError(QNetworkSession::SessionError error);
46 | #ifndef QT_NO_SSL
47 | void onSslErrors(const QList &errors);
48 | #endif
49 | private:
50 | bool isOnline();
51 | void reconnect() noexcept;
52 | private:
53 | QWebSocket *m_WebSocket;
54 | QThread *m_thread;
55 | QUrl m_url{};
56 | QNetworkSession *m_session = nullptr;
57 | QStringList m_streamTemplates{};
58 | QString m_baseWebSocketTemplate{};
59 | QTimer *m_pongTimer = nullptr;
60 | };
61 |
62 | #endif // WEBSOCKETCLIENT_H
63 |
--------------------------------------------------------------------------------
/src/boilerplate/singly_linked_stack.h:
--------------------------------------------------------------------------------
1 | #ifndef SINGLY_LINKED_STACK_H
2 | #define SINGLY_LINKED_STACK_H
3 | #include
4 | #include
5 |
6 | template
7 | class SinglyLinkedElement
8 | {
9 | public:
10 | SinglyLinkedElement() = default;
11 | virtual ~SinglyLinkedElement() = default;
12 | void setNext(const Y &next);
13 | inline Y getNext() const
14 | {
15 | return m_next;
16 | }
17 | private:
18 | Y m_next = nullptr;
19 | };
20 |
21 | template< typename Y >
22 | void SinglyLinkedElement< Y >::setNext(const Y &next)
23 | {
24 | m_next = next;
25 | }
26 |
27 | template
28 | class SinglyLinkedStack final : public QStack
29 | {
30 | public:
31 | SinglyLinkedStack();
32 | ~SinglyLinkedStack();
33 |
34 | void insert_back(const T &t);
35 | void remove();
36 | void setHead(const T &head);
37 | private:
38 | T m_head = nullptr;
39 | };
40 |
41 | template< typename T >
42 | SinglyLinkedStack< T >::SinglyLinkedStack() : m_head( nullptr ) {
43 | }
44 |
45 | template< typename T >
46 | SinglyLinkedStack< T >::~SinglyLinkedStack() {
47 | while( m_head ) {
48 | remove();
49 | }
50 | }
51 |
52 | template< typename T >
53 | void SinglyLinkedStack< T >::insert_back( const T &t ) {
54 | // Новый узел привязывается к старому головному элементу
55 | if( !m_head.isNull() ) {
56 | t->setNext(m_head->getNext());
57 | m_head->setNext(t);
58 | }
59 | // Новый узел сам становится головным элементом
60 | setHead(t);
61 | QStack::push(t);
62 | }
63 |
64 | template< typename T >
65 | void SinglyLinkedStack< T >::remove() {
66 | if( !m_head.isNull() ) { // Если список не пуст:
67 | // Сохраняем указатель на второй узел, который станет новым головным элементом
68 | auto newHead = m_head->getNext();
69 | QStack::pop();
70 | m_head.clear();
71 |
72 | // Назначаем новый головной элемент
73 | m_head = newHead;
74 | } // Иначе могли бы возбудить исключение
75 | }
76 |
77 | template< typename T >
78 | void SinglyLinkedStack< T >::setHead(const T &head)
79 | {
80 | m_head = head;
81 | }
82 |
83 | #endif // SINGLY_LINKED_STACK_H
84 |
--------------------------------------------------------------------------------
/resources/ui_icons/big-database.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
51 |
--------------------------------------------------------------------------------
/cmake/stacktrace.cmake:
--------------------------------------------------------------------------------
1 | option( Use_BreakPad "Use Google BreakPad" OFF )
2 | if ( Use_BreakPad )
3 | add_definitions(-DBREAKPAD_ENABLED)
4 | # - Find Breakpad
5 | #
6 | # BREAKPAD_FOUND - True if Breakpad has been found.
7 | # BREAKPAD_INCLUDE_DIRS - Breakpad include directory
8 | # BREAKPAD_LIBRARIES - List of libraries when using Breakpad.
9 | # BREAKPAD_LIBRARY_DIRS - Breakpad library directories
10 |
11 | if(WIN32)
12 | find_path(BREAKPAD_INCLUDE_DIRS
13 | HINTS
14 | "${CMAKE_CURRENT_SOURCE_DIR}/breakpad/prefix/include/breakpad")
15 |
16 | set(BREAKPAD_LIBRARY_NAMES
17 | BREAKPAD_CLIENT
18 | BREAKPAD)
19 |
20 | set(BREAKPAD_LIBRARIES "")
21 | set(BREAKPAD_LIBRARIES_VARS "")
22 | foreach(libname ${BREAKPAD_LIBRARY_NAMES})
23 | find_library(BREAKPAD_LIBRARY_${libname}
24 | ${libname}
25 | HINTS
26 | "${CMAKE_CURRENT_SOURCE_DIR}/breakpad/prefix/lib")
27 |
28 | list(APPEND BREAKPAD_LIBRARIES ${BREAKPAD_LIBRARY_${libname}})
29 | list(APPEND BREAKPAD_LIBRARIES_VARS "BREAKPAD_LIBRARY_${libname}")
30 | endforeach()
31 |
32 | set(BREAKPAD_LIBRARY_DIRS "")
33 | else()
34 | set(BREAKPAD_CMAKE_PREFIX_PATH_TEMP ${CMAKE_PREFIX_PATH})
35 | list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/breakpad/prefix")
36 | set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${PKG_CONFIG_PATH}")
37 | find_package(PkgConfig REQUIRED)
38 | pkg_search_module(BREAKPAD REQUIRED breakpad-client)
39 |
40 | # reset CMAKE_PREFIX_PATH
41 | set(CMAKE_PREFIX_PATH ${BREAKPAD_CMAKE_PREFIX_PATH_TEMP})
42 | mark_as_advanced(BREAKPAD_CMAKE_PREFIX_PATH_TEMP)
43 | endif()
44 |
45 | include(FindPackageHandleStandardArgs)
46 | find_package_handle_standard_args(BREAKPAD REQUIRED_VARS BREAKPAD_LIBRARIES BREAKPAD_INCLUDE_DIRS)
47 |
48 | mark_as_advanced(BREAKPAD_LIBRARIES_VARS)
49 | endif()
50 |
--------------------------------------------------------------------------------
/resources/qml/TopBar.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.12
2 | import QtQuick.Controls 2.12
3 | import QtQuick.Controls.Material 2.12
4 | import CryptoShloma.Gui 1.0
5 | import CryptoShloma.Common 1.0
6 | import BaseElements 1.0
7 |
8 | ToolBar {
9 | Material.background: "#303030"
10 | property alias currentIndex: bar.currentIndex
11 | TabBar {
12 | width: parent.width - rightMenu.width
13 | id: bar
14 | Repeater {
15 | model: ExchangePool
16 |
17 | delegate: TabBarIcon {
18 | id: icon
19 | icon.color: model.exchange.api.isOnline ? Material.color(Material.Green) : Material.color(Material.Red)
20 | states: [
21 | State {
22 | when: model.exchange.api.type == ExchangeType.Binance
23 | PropertyChanges {
24 | target: icon
25 | icon.source: "qrc:/ui/exchange_logos/resources/exchange_logos/binance.svg"
26 | ToolTip.text: qsTr("Binance")
27 | }
28 | }
29 | ]
30 | }
31 | }
32 | }
33 |
34 | Row {
35 | id: rightMenu
36 | anchors.right: parent.right
37 |
38 | ToolBarIcon {
39 | property bool isEnabled: SettingsManager.get(SettingsManager.EnableTestData) === 'true'
40 | icon.source: "qrc:/ui/icons/resources/ui_icons/speedometer.svg"
41 | icon.color: Material.color(Material.Green)
42 | ToolTip.text: qsTr("Open emulator")
43 | onClicked: {
44 | emulatorWindow.dialog.open()
45 | }
46 | visible: isEnabled
47 | }
48 |
49 | ToolBarIcon {
50 | icon.source: "qrc:/ui/icons/resources/ui_icons/big-database.svg"
51 | icon.color: Crud.isOpen ? Material.color(Material.Green) : Material.color(Material.Red)
52 | ToolTip.text: qsTr("Database")
53 | }
54 |
55 | ToolBarIcon {
56 | icon.source: "qrc:/ui/icons/resources/ui_icons/settings.svg"
57 | icon.color: Material.color(Material.Green)
58 | ToolTip.text: qsTr("Settings")
59 | onClicked: settingsWindow.open()
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/storage/trade_history_storage.cpp:
--------------------------------------------------------------------------------
1 | #include "trade_history_storage.h"
2 | #include
3 | #include
4 | #include "markets_storage.h"
5 |
6 | TradeHistoryStorage::TradeHistoryStorage(IExchangeAPI *parent) noexcept
7 | : QObject()
8 | , m_api(parent)
9 | {
10 | }
11 |
12 | Order::ConstContainer TradeHistoryStorage::filter(const Market::MarketId &marketId) const noexcept
13 | {
14 | Order::ConstContainer filtered;
15 |
16 | std::copy_if(m_Data.begin(), m_Data.end(),std::back_inserter(filtered), [&marketId](const Order::Ptr &order){
17 | return order->getMarket()->getId() == marketId;
18 | });
19 | std::sort(filtered.begin(), filtered.end(),[](const Order::ConstPtr &leftOrder, const Order::ConstPtr &rightOrder){
20 | return leftOrder->getTimeStamp() > rightOrder->getTimeStamp();
21 | });
22 | return filtered;
23 | }
24 |
25 | void TradeHistoryStorage::insert(const Market::MarketId &id) noexcept
26 | {
27 | QReadLocker locked(&lock);
28 | if ( !m_Filters.contains(id) )
29 | m_Filters << id;
30 | }
31 |
32 | void TradeHistoryStorage::merge(const QList &data) noexcept
33 | {
34 | LOG_TRACE_TIME();
35 | QReadLocker locked(&lock);
36 | for (const auto &item : data) {
37 | auto found = std::find_if(m_Data.begin(), m_Data.end(),
38 | [ &item ]( const decltype( m_Data )::value_type &order ) noexcept
39 | {
40 | return order->getOrderId() == item.params.orderId;
41 | });
42 | if ( found == m_Data.end() ) {
43 | if ( m_Filters.contains(item.marketId) ) {
44 | auto market = m_api->marketsStorage()->findMarketById(item.marketId);
45 | if ( !market.isNull() ) {
46 | auto order = Order::Ptr::create(item.params);
47 | order->setMarket(market);
48 | m_Data.append(order);
49 | }
50 | }
51 | }
52 | }
53 | }
54 |
55 | void TradeHistoryStorage::remove(const Market::MarketId &id) noexcept
56 | {
57 | LOG_TRACE_TIME();
58 | QReadLocker locked(&lock);
59 | m_Filters.removeAll(id);
60 | for (auto item = m_Data.begin(); item != m_Data.end();) {
61 | if ( item->get()->getMarket()->getId() == id )
62 | item = m_Data.erase(item);
63 | else
64 | ++item;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/common/settings_manager.h:
--------------------------------------------------------------------------------
1 | #ifndef SETTINGSMANAGER_H
2 | #define SETTINGSMANAGER_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "constants.h"
9 |
10 | class QQmlEngine;
11 | class QJSEngine;
12 |
13 | class SettingsManager final: public QObject
14 | {
15 | Q_OBJECT
16 |
17 | static SettingsManager *m_SettingsManager;
18 | explicit SettingsManager(QObject *parent = nullptr) noexcept;
19 | SettingsManager(const SettingsManager &) noexcept = delete;
20 | SettingsManager &operator = (const SettingsManager &) noexcept = delete;
21 | public:
22 | enum Section {
23 | General,
24 | Hanukkah,
25 | Binance
26 | };
27 | Q_ENUM(Section)
28 |
29 | enum Key {
30 | TradeBaseSumm,
31 | MinSpread,
32 | MinProfit,
33 | MinBaseVolume,
34 | MinCoinPrice,
35 | TradeDifference, //NOTE: нужно для того, что бы выставлять +- от лучших ордеров по рынку
36 | HanukkahTable,
37 | HanukkahMaxSteps,
38 | BinanceEnabled,
39 | BinanceAPIKey,
40 | BinanceSecretKey,
41 | EnableTestData
42 | };
43 | Q_ENUM(Key)
44 |
45 | static void setDefaults(const QString &str) noexcept;
46 | Q_INVOKABLE static QVariant get(const Key k, const Section s = General) noexcept;
47 | Q_INVOKABLE static void set(const Key k, const Section s = General, const QVariant &data = QVariant()) noexcept;
48 | //Метод с макросом Q_INVOKABLE, возвращающий кастомный тип не работает, должен возвращаться QVariant!
49 | //static ValueRef set(Key, Section s = General);
50 | #ifdef QT_QML_LIB
51 | static QObject *qobject_settingsmanager_provider(QQmlEngine *engine, QJSEngine *scriptEngine) noexcept;
52 | #endif
53 | static SettingsManager *getInstance() noexcept;
54 | static void drop() noexcept;
55 | private:
56 |
57 | QString keyPath(const Section s, const Key k) noexcept;
58 | QMetaEnum m_Keys{};
59 | QMetaEnum m_Sections{};
60 | QMap defaults{};
61 | QMap conf_cache{};
62 | #ifndef QT_NO_DEBUG
63 | QSettings conf {qApp->applicationDirPath() + "/config.ini", QSettings::IniFormat};
64 | #else
65 | QSettings conf {QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QString("/.%1/config.ini").arg(GLOBAL_APP_NAME), QSettings::IniFormat};
66 | #endif
67 | };
68 |
69 | #endif // SETTINGSMANAGER_H
70 |
--------------------------------------------------------------------------------
/src/base/currency.cpp:
--------------------------------------------------------------------------------
1 | #include "currency.h"
2 |
3 | Currency::Currency(QObject *parent)
4 | : QObject(parent)
5 | , m_config(Config())
6 | {}
7 |
8 | Currency::Currency(const Currency::Config &config)
9 | {
10 | setId(config.id);
11 | setConfig(config);
12 | }
13 |
14 | Currency::Currency(const Currency &o)
15 | : QObject(o.parent())
16 | , m_config(o.m_config)
17 | {}
18 |
19 | Currency::Currency(Currency &&o) noexcept
20 | : QObject(o.parent())
21 | , m_config(std::move(o.m_config))
22 | {}
23 |
24 | const QString &Currency::getName() const noexcept
25 | {
26 | return m_config.name;
27 | }
28 |
29 | void Currency::setName(const QString &value) noexcept
30 | {
31 | if ( m_config.name != value) {
32 | m_config.name = value;
33 | emit nameChanged();
34 | }
35 | }
36 |
37 | const QString &Currency::getSymbol() const noexcept
38 | {
39 | return m_config.id.get();
40 | }
41 |
42 | const QString &Currency::getStatusMessage() const noexcept
43 | {
44 | return m_config.statusMessage;
45 | }
46 |
47 | void Currency::setStatusMessage(const QString &value) noexcept
48 | {
49 | if ( m_config.statusMessage != value ) {
50 | m_config.statusMessage = value;
51 | emit statusChanged();
52 | }
53 | }
54 |
55 | const Currency::CurrencyId &Currency::getId() const noexcept
56 | {
57 | return m_config.id;
58 | }
59 |
60 | void Currency::setId(const CurrencyId &value) noexcept
61 | {
62 | if ( m_config.id != value ) {
63 | m_config.id = value;
64 | emit idChanged();
65 | }
66 | }
67 |
68 | Currency::CurrencyStatusListing Currency::getListingStatus() const noexcept
69 | {
70 | return m_config.listingStatus;
71 | }
72 |
73 | void Currency::setListingStatus(const CurrencyStatusListing value) noexcept
74 | {
75 | if ( m_config.listingStatus != value ) {
76 | m_config.listingStatus = value;
77 | emit listingStatusChanged();
78 | }
79 | }
80 |
81 | Currency::CurrencyStatus Currency::getStatus() const noexcept
82 | {
83 | return m_config.status;
84 | }
85 |
86 | void Currency::setStatus(const CurrencyStatus value) noexcept
87 | {
88 | if ( m_config.status != value ) {
89 | m_config.status = value;
90 | emit statusChanged();
91 | }
92 | }
93 |
94 | void Currency::setConfig(const Config &config) noexcept
95 | {
96 | setName(config.name);
97 | setStatusMessage(config.statusMessage);
98 | setStatus(config.status);
99 | setListingStatus(config.listingStatus);
100 | }
101 |
--------------------------------------------------------------------------------
/src/storage/market_orders_storage.cpp:
--------------------------------------------------------------------------------
1 | #include "market_orders_storage.h"
2 | #include "markets_storage.h"
3 | #include
4 | #include
5 | #include
6 |
7 | MarketOrdersStorage::MarketOrdersStorage(IExchangeAPI *parent) noexcept
8 | : QObject()
9 | , m_api(parent)
10 | {
11 | }
12 |
13 | Order::ConstContainer MarketOrdersStorage::filter(const Market::MarketId &marketId, const Order::OrderType orderType) const noexcept
14 | {
15 | Order::ConstContainer filtered;
16 |
17 | std::copy_if(m_Data.begin(), m_Data.end(),std::back_inserter(filtered), [&marketId, orderType](const Order::Ptr &order){
18 | return (order->getMarket()->getId() == marketId) && (order->getType() == orderType);
19 | });
20 | std::sort(filtered.begin(), filtered.end(),[](const Order::ConstPtr &leftOrder, const Order::ConstPtr &rightOrder){
21 | return leftOrder->getTimeStamp() > rightOrder->getTimeStamp();
22 | });
23 | return filtered;
24 | }
25 |
26 | void MarketOrdersStorage::insert(const Market::MarketId &id) noexcept
27 | {
28 | QReadLocker locked(&lock);
29 | if ( !m_Filters.contains(id) )
30 | m_Filters << id;
31 | }
32 |
33 | void MarketOrdersStorage::merge(const QList &data) noexcept
34 | {
35 | LOG_TRACE_TIME();
36 | QReadLocker locked(&lock);
37 | QList ids;
38 | for (auto i = data.cbegin(); i != data.cend(); ++i) {
39 | const auto &id = (*i).marketId;
40 | if ( !ids.contains(id) )
41 | ids << id;
42 | }
43 | for (auto item = m_Data.begin(); item != m_Data.end();) {
44 | if ( ids.contains(item->get()->getMarket()->getId()))
45 | item = m_Data.erase(item);
46 | else
47 | ++item;
48 | }
49 |
50 | for (auto item : data ) {
51 | if ( m_Filters.contains(item.marketId) ) {
52 | auto market = m_api->marketsStorage()->findMarketById(item.marketId);
53 | if ( !market.isNull() ) {
54 | auto order = Order::Ptr::create(item.params);
55 | order->setMarket(market);
56 | m_Data.append(order);
57 | }
58 | }
59 | }
60 | }
61 |
62 | void MarketOrdersStorage::remove(const Market::MarketId &id) noexcept
63 | {
64 | LOG_TRACE_TIME();
65 | QReadLocker locked(&lock);
66 | m_Filters.removeAll(id);
67 | for (auto item = m_Data.begin(); item != m_Data.end();) {
68 | if ( item->get()->getMarket()->getId() == id ) {
69 | item = m_Data.erase(item);
70 | } else
71 | ++item;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/algo/hanukkah/i_step.h:
--------------------------------------------------------------------------------
1 | #ifndef I_STEP_H
2 | #define I_STEP_H
3 | #include
4 | #include
5 |
6 | class Hanukkah;
7 | class IStep;
8 | using StepPtr = QSharedPointer;
9 |
10 | #pragma pack (push, 1)
11 | class IStep : public SinglyLinkedElement
12 | {
13 | public:
14 | using StepContainer = SinglyLinkedStack;
15 | explicit IStep(const qreal &declinePerc,
16 | const qreal &growth,
17 | Hanukkah * const parentAlgo,
18 | const Market::ConstPtr &market,
19 | bool buyBlocked,
20 | bool sellBlocked) noexcept;
21 | IStep(const IStep &other) noexcept = delete;
22 | IStep & operator=(const IStep &other) noexcept = delete;
23 |
24 | virtual ~IStep();
25 |
26 | inline qreal getDeclinePerc() const noexcept
27 | {
28 | return m_declinePerc;
29 | }
30 |
31 | inline qreal getGrowth() const noexcept
32 | {
33 | return m_growth;
34 | }
35 | virtual void executeBuyLogic() = 0;
36 | virtual void executeSellLogic() = 0;
37 | inline bool isBuyBlocked() const noexcept
38 | {
39 | return m_isBuyBlocked;
40 | }
41 | inline bool isSellBlocked() const noexcept
42 | {
43 | return m_isSellBlocked;
44 | }
45 |
46 | void setBuyBlocked(bool isBlocked) noexcept;
47 | void setSellBlocked(bool isBlocked) noexcept;
48 | protected:
49 | struct AverageData {
50 | qreal baseVolume{0.};
51 | qreal price{0.};
52 | qreal fee{0.};
53 | qreal volume{0.};
54 | quint16 ordersCount{0};
55 | };
56 | static AverageData calculateAverate(const Order::ConstContainer &container,
57 | const QDateTime &cycleTimeStart) noexcept;
58 | static qreal calculateStopLoss(const qreal &price,
59 | const qreal &oldFee,
60 | const qreal &baseVolume,
61 | const qreal &fee,
62 | const qreal &volume,
63 | const qreal &profit);
64 | void unlock() noexcept;
65 | void updateMarketMetaConfig(bool isBuyCompleted, const QDateTime &cycleTimeStamp = QDateTime());
66 | protected:
67 | Hanukkah * const m_parentAlgo = nullptr;
68 | Market::ConstPtr m_market = {};
69 | private:
70 | qreal m_declinePerc = 0.;
71 | qreal m_growth = 0.;
72 | bool m_isBuyBlocked = false;
73 | bool m_isSellBlocked = false;
74 | };
75 | #pragma pack (pop)
76 | #endif // I_STEP_H
77 |
--------------------------------------------------------------------------------
/resources/qml/ModelViews/OrdersView.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.12
2 | import QtQuick.Controls 2.12
3 | import QtQuick.Controls.Material 2.12
4 | import BaseElements 1.0
5 |
6 | Item {
7 | property alias buyModel: buyView.model
8 | property alias sellModel: sellView.model
9 | property alias title: title.text
10 | EmptyLabel {
11 | id: helpIndicator
12 | text: qsTr("Please, select trading coin")
13 | visible: false
14 | anchors.horizontalCenter: parent.horizontalCenter
15 | anchors.verticalCenter: parent.verticalCenter
16 | color: Material.color(Material.Grey)
17 | }
18 |
19 | id: itemView
20 | EmptyLabel {
21 | id: title
22 | text: ""
23 | anchors.horizontalCenter: parent.horizontalCenter
24 | }
25 | Row {
26 | spacing: 15
27 |
28 | GroupBox {
29 | spacing: 0
30 | padding: 0
31 | title: qsTr("Sell orders")
32 | label: EmptyLabel {
33 | x: parent.leftPadding
34 | width: parent.availableWidth
35 | text: parent.title
36 | elide: Text.ElideRight
37 | }
38 | background: Rectangle {
39 | color: "transparent"
40 | border.width: 0
41 | }
42 | Column {
43 | OrdersListView {
44 | onCountChanged: {
45 | helpIndicator.visible = (count > 0 ? false : true)
46 | }
47 | busyEnabled: false
48 | id: sellView
49 | height: 205
50 | width: 255
51 | }
52 | }
53 | }
54 |
55 | GroupBox {
56 | spacing: 0
57 | padding: 0
58 | title: qsTr("Buy orders")
59 | label: EmptyLabel {
60 | x: parent.rightPadding
61 | width: parent.availableWidth
62 | text: parent.title
63 | horizontalAlignment: Text.AlignRight
64 | elide: Text.ElideRight
65 | }
66 | background: Rectangle {
67 | color: "transparent"
68 | border.width: 0
69 | }
70 | Column {
71 | OrdersListView {
72 | onCountChanged: {
73 | helpIndicator.visible = (count > 0 ? false : true)
74 | }
75 | busyEnabled: false
76 | id: buyView
77 | height: 205
78 | width: 255
79 | }
80 | }
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------