From 79f2f7839250b027ff0a353202c16e8c350fdb40 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 10 May 2023 21:17:27 +0300 Subject: [PATCH 1/3] diff percent with fill --- common/chart.cpp | 57 ++++++- common/chart.h | 22 +++ common/csvmodel.cpp | 3 - common/mainwindow.cpp | 59 +++++-- common/mainwindow.h | 10 ++ lib/common/CMakeLists.txt | 2 +- lib/common/dca.cpp | 4 +- lib/common/dca.h | 166 +++++++++++++------- lib/common/future.h | 313 ++++++++++++++++++++++++++++++++++++++ lib/common/logger.h | 57 ++++--- 10 files changed, 595 insertions(+), 98 deletions(-) create mode 100644 lib/common/future.h diff --git a/common/chart.cpp b/common/chart.cpp index be30971..54f24ac 100755 --- a/common/chart.cpp +++ b/common/chart.cpp @@ -54,7 +54,62 @@ void Graph::buildBarChart(const std::map &data) { }); axisY->setRange(0, max->second + min->second); - axisY->setTickCount(10); + axisY->setTickCount(data.size() * 1.5); + + axisY->setTitleText(titleAxisY); + chart->legend()->setVisible(true); + chart->legend()->setAlignment(Qt::AlignBottom); + chart->addAxis(axisY, Qt::AlignLeft); + series->attachAxis(axisY); + + setChartView(chart); + +} + + +void Graph::buildBarChartDiffDepo(const std::map &data) +{ + + QBarSet *set[data.size()]; + auto depo = data.begin()->second; + QStackedBarSeries *series = new QStackedBarSeries(); + int i = 0; + for (auto&& [key, value] : data) { + set[i] = new QBarSet(key); + *set[i] <append(set[i]); + i++; + } + + QChart *chart = new QChart(); + chart->addSeries(series); + chart->setTitle(title); + chart->setAnimationOptions(QChart::SeriesAnimations); + + QStringList categories; + for (auto&& [key, value] : data) { + categories << key; + } + + QBarCategoryAxis *axisX = new QBarCategoryAxis(); + axisX->append(categories); + chart->addAxis(axisX, Qt::AlignBottom); + series->attachAxis(axisX); + + QValueAxis *axisY = new QValueAxis(); + auto max = std::max_element(data.begin(), data.end(), + [](const std::pair &p1, const std::pair &p2) { + return p1.second < p2.second; + }); + auto min = std::min_element(data.begin(), data.end(), + [](const std::pair &p1, const std::pair &p2) { + return p1.second < p2.second; + }); + +// axisY->setRange(0, max->second + min->second); +// axisY->setTickCount(data.size() * 1.5); axisY->setTitleText(titleAxisY); chart->legend()->setVisible(true); diff --git a/common/chart.h b/common/chart.h index d50f250..8d5f8c1 100755 --- a/common/chart.h +++ b/common/chart.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include +#include class Graph { public: @@ -35,6 +37,7 @@ class Graph { } void buildBarChart(const std::map &data); + void buildBarChartDiffDepo(const std::map &data); void buildLineChart(const std::map &data); /** @@ -52,6 +55,25 @@ class Graph { // buildLineChart(dataset); // } + +// template +// void build( T& dataset) +// { +// if(m_type == TypeChart::BarChart) +// buildBarChart(dataset); +// if(m_type == TypeChart::LineChart) +// buildLineChart(dataset); +// } + +// template<> +// void build>(std::map& dataset) +// { +// if(m_type == TypeChart::BarChart) +// buildBarChart(dataset); +// } + + + protected: void setChartView(QChart *chart); diff --git a/common/csvmodel.cpp b/common/csvmodel.cpp index af788ff..52ddfb2 100644 --- a/common/csvmodel.cpp +++ b/common/csvmodel.cpp @@ -15,9 +15,6 @@ void CsvModel::build(const std::string filename, char delimeter) { auto column = reader_csv.getSizeGrid().first; auto rows = reader_csv.getSizeGrid().second; - std::cout << "Counter column: " << column << "\n"; - std::cout << "Counter rows: " << rows << "\n"; - QDialog *dlg = new QDialog(); dlg->setWindowTitle(QString::fromStdString(m_titleWindow)); diff --git a/common/mainwindow.cpp b/common/mainwindow.cpp index 68f8286..55db701 100644 --- a/common/mainwindow.cpp +++ b/common/mainwindow.cpp @@ -29,15 +29,16 @@ MainWindow::MainWindow(QWidget *parent) : }); connect(ui->btnDiffPercent, &QPushButton::clicked, [this]() { + + resultDiffPercent.clear(); double depo = ui->spnDepoDiffPerc->value(); double percentage = ui->spnDiffPercentInMonth->value(); - resultDiffPercent.clear(); - for(auto counter_month = 1; counter_month <= ui->spnDiffPercentDuration->value(); counter_month++) { - Strategy::DiffPercent diff(depo, percentage, counter_month); - auto overdeposit = Strategy::calculateDiffPercent(diff); - resultDiffPercent.emplace(counter_month, overdeposit); - ui->lblResultDiffPercent->setText(QString::number(overdeposit, 'f', 2)); - } + int period = ui->spnDiffPercentDuration->value(); + + resultDiffPercent = Strategy::calculateDiffPercentPeriod(depo, percentage, period); +// resultDiffPercent = Strategy::calculateDiffPercentPeriodAddStock(depo,50,percentage,period); + + ui->lblResultDiffPercent->setText(QString::number(std::prev(resultDiffPercent.end())->second, 'f', 2)); getDiffPercentDetails(); }); @@ -126,7 +127,7 @@ void MainWindow::detailDCA() { rowData << new QStandardItem(QString("%1").arg(item.first)); rowData << new QStandardItem(QString("%1").arg(item.second)); rowData << new QStandardItem(QString("%1").arg(item.second * item.first)); - rowData << new QStandardItem(QString("%1").arg(-100 + (item.second * 100 / result.price))); + rowData << new QStandardItem(QString("%1").arg((item.second * 100 / result.price) - 100)); model->appendRow(rowData); } @@ -384,9 +385,9 @@ void MainWindow::getDiffPercentDetails() { auto filename_with_date = current_data.toStdString() + "_" + current_filename; logger->settings(dump_dir, filename_with_date); // logger->Log(std::string ("Month"),std::string("Depo"), std::string("Profit") ,std::string("Percent"), std::string("Percent on Depo")); - logger->Log("Month","Depo","Profit" ,"Percent","Percent on Depo"); + logger->add("Month","Depo","Profit" ,"Percent","Percent on Depo"); for(auto items:data) - logger->Log(items); + logger->add(items); }); //Save csv to file @@ -399,8 +400,37 @@ void MainWindow::getDiffPercentDetails() { container.push_back(data.at(rows).at(items)); grid.setDataGrid(container); +// for(const auto &[range_assets, range_price] :grid.byColumns(0,1)) +// { +// qDebug() << "X: " < need_data1 = grid.byColumns(0,1); +// std::map> need_data {need_data1}; + +// std::map> need_data {need_data1}; + auto need_data2 = invert(need_data1); +// qDebug() <<"Invert data"; +// for(const auto &[range_assets, range_price] :need_data2) +// { +// qDebug() << "X: " <b.data(); +// } +// ); - auto need_data = grid.byColumns(0,1); std::map data_convert; std::map data_convert1; for(const auto &[range_assets, range_price] : need_data) @@ -410,11 +440,12 @@ void MainWindow::getDiffPercentDetails() { } std::unique_ptr graph = std::make_unique(); - graph->setType(Graph::TypeChart::LineChart); + graph->setType(Graph::TypeChart::BarChart); graph->setTitleGraph("Diff Percentage", "Month", "Depo"); -// graph->buildBarChart(data_convert); - graph->buildLineChart(data_convert1); + graph->buildBarChart(data_convert); +// graph->buildBarChartDiffDepo(data_convert); +// graph->buildLineChart(data_convert1); //View csv data from file char delim = ';'; diff --git a/common/mainwindow.h b/common/mainwindow.h index 2a811d4..a55069d 100644 --- a/common/mainwindow.h +++ b/common/mainwindow.h @@ -53,4 +53,14 @@ class MainWindow : public QMainWindow }; + template + std::map invert(const std::map data) + { + std::map invert_map; + for(const auto &item:data) + invert_map[item.second] = item.first; + return invert_map; + } + + #endif // MAINWINDOW_H diff --git a/lib/common/CMakeLists.txt b/lib/common/CMakeLists.txt index 1c90a4f..18ace67 100644 --- a/lib/common/CMakeLists.txt +++ b/lib/common/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 17) add_compile_options(-Wall -Wextra -Wno-unused-function) -add_library(${PROJECT_NAME} SHARED dca.cpp grid.h logger.h) +add_library(${PROJECT_NAME} SHARED dca.cpp grid.h logger.h future.h) add_library(lib::common ALIAS common) target_include_directories( ${PROJECT_NAME} diff --git a/lib/common/dca.cpp b/lib/common/dca.cpp index df5780b..6e5d325 100644 --- a/lib/common/dca.cpp +++ b/lib/common/dca.cpp @@ -16,11 +16,12 @@ void dca::clear() goal_range.clear(); } -DiffPercent::DiffPercent(double depo, double percent, double counterMonth) +DiffPercent::DiffPercent(double depo, double percent, double counterMonth, double refill) { deposit = depo; m_percent = percent; step = counterMonth; + m_refill = refill; } void DiffPercent::convertPercentage() @@ -56,5 +57,6 @@ void DiffPercent::clear() m_percent = 0; step = 0; } + } diff --git a/lib/common/dca.h b/lib/common/dca.h index c002990..f1cb2f9 100644 --- a/lib/common/dca.h +++ b/lib/common/dca.h @@ -13,20 +13,19 @@ namespace Strategy { -template -bool isBoundRange(const T low, const T high, const T value) { - return ((low <= value) && (value <= high )); -} - static inline std::vector> make_sub_range(int range) - { - int number_of_elements { range}; - auto num_pthread {std::thread::hardware_concurrency() - 1 }; - auto number_of_period {num_pthread}; - std::vector> sub_range; - - auto found_count_pthread =[&]() { - for(auto i = num_pthread; i < num_pthread * 2 ; i++) - { + template + bool isBoundRange(const T low, const T high, const T value) { + return ((low <= value) && (value <= high)); + } + + static inline std::vector> make_sub_range(int range) { + int number_of_elements{range}; + auto num_pthread{std::thread::hardware_concurrency() - 1}; + auto number_of_period{num_pthread}; + std::vector> sub_range; + + auto found_count_pthread = [&]() { + for (auto i = num_pthread; i < num_pthread * 2; i++) { if (number_of_elements % number_of_period == 0) return number_of_period; else @@ -38,77 +37,126 @@ bool isBoundRange(const T low, const T high, const T value) { found_count_pthread(); - for(unsigned int period = 1; period <= number_of_period; period++) - sub_range.push_back(std::make_pair(number_of_elements/number_of_period * (period - 1 ), (number_of_elements/number_of_period * period))); + for (unsigned int period = 1; period <= number_of_period; period++) + sub_range.push_back(std::make_pair(number_of_elements / number_of_period * (period - 1), + (number_of_elements / number_of_period * period))); return sub_range; } //namespace container{} -struct dca { - double assets {0}; - double price {0}; - double goal_price {0}; - std::map< double, double> goal_range; + struct dca { + double assets{0}; + double price{0}; + double goal_price{0}; + std::map goal_range; + + dca() = default; - dca() = default; - explicit dca(double assets, double price, double goal_price); - void clear(); -}; + explicit dca(double assets, double price, double goal_price); + + void clear(); + }; /** * @brief The diffPercent struct * @note calculate for month */ -struct DiffPercent -{ - DiffPercent(double depo, double percent, double counterMonth); - double deposit; - double m_percent; - double step; - - void convertPercentage(); - void clear (); -}; - - -double static calculateDiffPercent(DiffPercent &dps) -{ - dps.convertPercentage(); - double result = dps.deposit * pow(dps.m_percent, dps.step - 1); - return result; -} + struct DiffPercent { + DiffPercent(double depo, double percent, double counterMonth, double refill = 0.00L); -void static calculateDCA(dca & res, int min_range = 0, int max_range = 0) { + double deposit; + double m_percent; + double step; + double m_refill; // add advanced asset - auto first_total_sum = res.assets * res.price; - res.goal_range.clear(); + void convertPercentage(); - assert(max_range != 0 && " max_range <= min_range"); + void clear(); + }; - for( ; min_range < max_range ; min_range ++) { - for(auto range_price = 0; range_price <= res.goal_price; range_price++) { - auto range_sum = min_range * range_price; - auto total_sum = range_sum + first_total_sum; - auto find_down_price = total_sum /(res.assets + min_range); + double static calculateDiffPercent(DiffPercent &dps) { + dps.convertPercentage(); + double result = dps.deposit * pow(dps.m_percent, dps.step - 1); +// double result = dps.deposit * pow(1 + dps.m_percent / dps.step, dps.step); + return result; + } - auto diff_price = res.goal_price - find_down_price; - //todo: поменять допустимый диапазон [отклонение] расхождение - if(diff_price == 0 ) - { - res.goal_range[min_range] = range_price; - } + //todo: перепроверить , процент с пополнением + double static calculateDiffPercentAddStock(DiffPercent &dps) { + dps.convertPercentage(); + double result = (dps.deposit + dps.m_refill) * pow(dps.m_percent, dps.step - 1); +// double refill = dps.m_refill * pow(dps.m_percent, dps.step - 1); +// std::cout<<"Refill calc: " << refill <<"\n"; + +// return (double)(result + refill); + return result; + } + + + std::map static + calculateDiffPercentPeriod(const double depo, const double percentage, const int period) { + + std::map resultDiffPercent; + + for(auto counter_month = 1; counter_month <= period; counter_month++) + { + Strategy::DiffPercent diff(depo, percentage, counter_month); + auto overdeposit = Strategy::calculateDiffPercent(diff); + resultDiffPercent.emplace(counter_month, overdeposit); + std::cout << counter_month << ":" << overdeposit << "\n"; } + + return resultDiffPercent; } + + std::map static + calculateDiffPercentPeriodAddStock(const double depo, const double refill, const double percentage, const int period) { + + std::map resultDiffPercent; + + for(auto counter_month = 1; counter_month <= period; counter_month++) { + auto add_stock_period = refill; + Strategy::DiffPercent diff(depo, percentage, counter_month, add_stock_period ); + auto overdepositrefill = Strategy::calculateDiffPercentAddStock(diff) + refill *counter_month; + resultDiffPercent.emplace(counter_month, overdepositrefill); + std::cout << counter_month << ":" << overdepositrefill << " \t refill " < +#include +#include +#include +#include +#include +#include + + +template +auto match(const R& range, Ts ...ts) +{ + + return (std::count(std::begin(range), std::end(range), ts) + ...); +} + +template< typename T,typename ... Ts> +bool within(T min, T max, Ts ...ts) +{ + return ((min <= ts && ts<=max)&& ...); +} + +template +std::map invert(const std::map data) +{ + std::map invert_map; + for(const auto &item:data) + invert_map[item.second] = item.first; + return invert_map; +} + + + +// calculate SMA usage history data [json, etc.] and period {example 20, 50, 100 } +// usage price closing +float sma(std::vector price_closing, int period = 0) { + if(period > price_closing.size() || period < 0) + return 0L; + if(period != price_closing.size() && period != 0) + price_closing.resize(period); + return (float)std::accumulate(price_closing.begin(), price_closing.end(), 0) / price_closing.size(); +} + +float avg(std::vector data) +{ + return std::accumulate(data.begin(), data.end(), 0) /data.size(); +} + +//Moving average +float MA(std::vector data) +{ + return std::accumulate(data.begin(), data.end(), 0) /data.size(); +} + + +// standart deviation for vector of prices +float std_dev(const std::vector &data) +{ + float dev_mean = MA(data); + float mean = 0L; + for(const auto &item:data ) + mean += std::pow(dev_mean - item, 2); + + float dev = mean/data.size() ; + return std::sqrt(dev); +} + +//fill partS of vector +auto subset(int first, int last, std::vector vec) +{ + std::vector::const_iterator begin = vec.begin()+ first; + std::vector::const_iterator end = vec.end() + last; + + std::vector subset { begin, end}; + return subset; +} + + +// Defines the Bollinger bands +void bands(std::vector prices, float standard_devs) +{ + auto top_band = MA(prices) + std_dev(prices) * standard_devs; + auto bottom_band = MA(prices) - std_dev(prices) * standard_devs; + + std::vector top_band_vec, bottom_band_vec; + //Fills in the vectors used for graphing. + top_band_vec.push_back(top_band); + bottom_band_vec.push_back(bottom_band); +} + +bool buy_signal() +{ + bool signal { false }; + + return signal; +} +bool sell_signal(){ + bool signal {false}; + return signal; +} + + +// weight for every indicators +class Indicator +{ + enum Type { + BB, + MA, + RSI, + ATR, + MACD, + DI, + }; + +}; + +//common interface for all +class IStartegy{ + virtual void run() = 0; +}; + +class Strategy final : public IStartegy +{ + enum Type { + Scalping , // 0.5% - 1% with big volume + DayTrade, //IntraDay + BigVolume, + Grid, //trader by grid price assets + Swing, + Investment + }; + enum Trend { //global trend old timeframes [12h,1d,1w,1m] and local trend [4h,1h]; + Up, + Down, + Flat, //sideways + }; +public: + Strategy() = default; + void run() override {} +private: + bool signal { false }; +}; + +//order ID or hash ID? +//for our ticker own ID +class Order { + enum Type { + Buy = 1, + Sell, + None //[hold] keep position + }; + enum Attribute { + Market = 1, + StopLimit, + StopLoss, + TakeProfit, + Trailing, + OCO + }; + //maybe type stop_loss, take_profit, market + enum Status { + Done, + PartDone, + Pendind, + Cancelled, + NoNe + }; + struct Config { + double currency_asset; + double profit; + double leverage; + double asset; + std::string_view asset_symbol; // ticker, symbol + long timestamp; //time order to set + long expiration_data;// data order is rancid + long updateTimestamp; + }; + long static ID; //orderID + using OrderType = Type; +public: + OrderType orderType; + Status status {NoNe}; + std::string toOrderTypeString(OrderType type) + { + return type == Buy? std::string("buy"):std::string("sell"); + } +}; + +class OrderHistory { +public: + OrderHistory () = default; +private: + std::vector m_order; +}; + + +// here must have wallet? +class BalanceInfo { +public: + BalanceInfo () = default; +private: + double currency_balance; + std::string asset; //ticker?; +}; + + +class Transaction { + enum TypeOperation { + Refill = 1, + Withdraw, + Trade + }; +}; + +class Wallet { + enum Symbol + { + USD, + EUR, + GBR, + CNY, + RUB + }; +public: + std::vector m_wallet; + long commonDeposit; //basesum in baseSymbol; + Symbol baseSymbol; // for convert +}; + +class Market { + enum Status { + Open = 1, + Closed, + Paused + }; + struct Config { + double bid {0.}; + double ask {0.}; + double volume {0.}; + double open {0.}; + double close {0.}; + double lastPrice {0.}; + double baseVolume {0.}; + double spread {0.}; + double priceTickSize {0.}; + }; +public: + Market() = default; + +private: + Status marketStatus; + +}; + + +/** + * @brief необходимо знать параметры сделки + * [общий депозит, размер стопа для выхода из сделки + * тип сделки - от тренда, тип стратегии и т.д.] + * \note обычный риск 1 к 3, т.е при риски в 1% сделки закладывается 3% прибыли + * параметры + * необходимо учитывать налоги по сделке, чтобы вся прибыль не съедалась комиссиями биржи. налогами + */ +class RiskManagement { +public: + RiskManagement() noexcept{} + void run(){}; +private: + const double base_risk_level { 3 } ; //in percentage допустимый уровень риска 1 к 3 [1] long and 1 к 3 при short + double tax_broker; // налог брокера + double tax_market;// налог биржи + double tax_profit;// налог на прибыль + double common_tax; // общий налог + Order m_order; + +}; + + + +//TODO: отдельные модули тестирования работы алгоритмов на исторических данных [analyze, work with machine learning] +// модуль налог по текущим транзакциям и "распечатка" в pdf +//optional module history price data [data set] +/** + * @brief тестирование алгоритма на исторических данных [fix/fast] + * \ результат список транзакций при работе определенного.алгоритма общий фин. результат + */ +class BackTest{ //Emulator +public: + BackTest() = default; + void setData() {} + void getProviderData() {} + void loadOrders(){} + void loadBalance(){} + void run(){} +private: + +}; + + + + + + + + + +#endif //SSM_FUTURE_H diff --git a/lib/common/logger.h b/lib/common/logger.h index 1370d39..49d759e 100644 --- a/lib/common/logger.h +++ b/lib/common/logger.h @@ -19,9 +19,10 @@ #define DEFAULT_DIR "/.ssm" template< typename VALUE, typename SFINAE = void > -struct StrongTypedefValidator; +struct StrongTypedefValidator {}; -template<> + +template<> [[maybe_unused]] struct StrongTypedefValidator< std::string, std::enable_if< true >::type > final { bool operator ()( const std::string & value ) const noexcept @@ -30,7 +31,8 @@ struct StrongTypedefValidator< std::string, std::enable_if< true >::type > final } }; -template<> + +template<> [[maybe_unused]] struct StrongTypedefValidator< QString, std::enable_if< true >::type > final { bool operator ()( const QString & value ) const noexcept @@ -64,6 +66,13 @@ typedef std::vector FieldQType ; Fatal }; + enum Type { + None, + Console, + File, + CSV + }; + std::string static levelToString(Logger::LogLevel logLevel) { switch (logLevel) @@ -111,12 +120,12 @@ class ConsoleLogger; /** * @brief The Logger class * @note usage default type string, QString, const char * ... + * @todo refact base class or funct with param pack move to library? */ class Logger { public: virtual ~Logger() = default; - /** *@brief get first element from pack params */ @@ -132,8 +141,6 @@ class Logger { return {data...}; } - - template auto prepareData(std::vector data)->decltype(FieldType()) { return data; @@ -152,27 +159,35 @@ class Logger { template void show(Types... data) { auto message = Logger::prepareData(data...); + std::cout< + [[maybe_unused]] void add(T... data) { } std::string inline getName() { return "FileLogger"; } - + Type inline getType() override{ return Type::File;} }; -class ConsoleLogger : public Logger { +class ConsoleLogger final: public Logger { public: static ConsoleLogger * p_instanse; - static ConsoleLogger* LoggerInstance() { + static ConsoleLogger * LoggerInstance() { if(p_instanse) p_instanse = new ConsoleLogger(); return p_instanse; @@ -185,6 +200,8 @@ class ConsoleLogger : public Logger { } std::string inline getName() { return "ConsoleLogger"; } + Type inline getType() override{ return Type::Console;} + }; class CSVLogger final : public Logger @@ -253,7 +270,7 @@ class CSVLogger final : public Logger } template - void Log(T... data) { + void add(T... data) { FieldType param = Logger::prepareData(data...); addData(param); } @@ -261,13 +278,15 @@ class CSVLogger final : public Logger template void operator()(T... data) { - Log(data...); + add(data...); } string inline getNameLogger () { return "CSVLogger"; } + + Type inline getType() override { return Type::CSV;} }; @@ -327,13 +346,13 @@ void CSVLogger::addData(const T &data) using ConsoleLogger = Common::Logger::ConsoleLogger; using Loglevel = Common::Logger::LogLevel; -#define cuteLogger LoggerInstance() +#define cuteLogger ConsoleLogger::LoggerInstance() -#define LOG_TRACE(args...) ConsoleLogger::LoggerInstance()->write(Loglevel::Trace, __FILE__, __LINE__, __FUNCTION__, args); -#define LOG_DEBUG (args...) ConsoleLogger::LoggerInstance()->write(Loglevel::Debug, __FILE__, __LINE__, __FUNCTION__, args); -#define LOG_INFO(args...) ConsoleLogger::LoggerInstance()->write(Loglevel::Info, __FILE__, __LINE__, __FUNCTION__, args); -#define LOG_WARNING(args...) ConsoleLogger::LoggerInstance()->write(Loglevel::Warning, __FILE__, __LINE__, __FUNCTION__, args); -#define LOG_ERROR(args...) ConsoleLogger::LoggerInstance()->write(Loglevel::Error, __FILE__, __LINE__, __FUNCTION__, args); +#define LOG_TRACE(args...) cuteLogger->write(Loglevel::Trace, __FILE__, __LINE__, __FUNCTION__, args); +#define LOG_DEBUG (args...) cuteLogger->write(Loglevel::Debug, __FILE__, __LINE__, __FUNCTION__, args); +#define LOG_INFO(args...) cuteLogger->write(Loglevel::Info, __FILE__, __LINE__, __FUNCTION__, args); +#define LOG_WARNING(args...) cuteLogger->write(Loglevel::Warning, __FILE__, __LINE__, __FUNCTION__, args); +#define LOG_ERROR(args...) cuteLogger->write(Loglevel::Error, __FILE__, __LINE__, __FUNCTION__, args); From 172068abb26f540307c7103f3cc7fe9228c5fa41 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Tue, 27 Jun 2023 18:44:31 +0300 Subject: [PATCH 2/3] first wrapper class for market --- common/chart.cpp | 80 ++++-- common/chart.h | 37 ++- lib/common/future.h | 688 +++++++++++++++++++++++++++++--------------- lib/common/grid.h | 1 + main.cpp | 18 +- 5 files changed, 542 insertions(+), 282 deletions(-) diff --git a/common/chart.cpp b/common/chart.cpp index 54f24ac..16ec97f 100755 --- a/common/chart.cpp +++ b/common/chart.cpp @@ -1,6 +1,12 @@ #include "chart.h" QT_CHARTS_USE_NAMESPACE + +Graph::Graph() { + + m_datetimeFormat = "yyyy-MM-dd HH:mm:ss"; +} + void Graph::setChartView(QChart *chart) { QChartView *chartView = new QChartView(chart); @@ -8,7 +14,7 @@ void Graph::setChartView(QChart *chart) chartView->setRubberBand(QChartView::HorizontalRubberBand); //for zoom graph QDialog *dialog = new QDialog(); - dialog->setWindowTitle(title); + dialog->setWindowTitle(m_title); QVBoxLayout *mainlayout = new QVBoxLayout(); mainlayout->addWidget(chartView); @@ -33,30 +39,23 @@ void Graph::buildBarChart(const std::map &data) { QChart *chart = new QChart(); chart->addSeries(series); - chart->setTitle(title); + chart->setTitle(m_title); chart->setAnimationOptions(QChart::SeriesAnimations); QStringList categories; - categories << titleAxisX; + categories << m_titleAxisX; QBarCategoryAxis *axisX = new QBarCategoryAxis(); axisX->append(categories); chart->addAxis(axisX, Qt::AlignBottom); series->attachAxis(axisX); QValueAxis *axisY = new QValueAxis(); - auto max = std::max_element(data.begin(), data.end(), - [](const std::pair &p1, const std::pair &p2) { - return p1.second < p2.second; - }); - auto min = std::min_element(data.begin(), data.end(), - [](const std::pair &p1, const std::pair &p2) { - return p1.second < p2.second; - }); - - axisY->setRange(0, max->second + min->second); + auto param = min_max_range_element(data); + axisY->setRange(0, param.first + param.second); + axisY->setTickCount(data.size() * 1.5); - axisY->setTitleText(titleAxisY); + axisY->setTitleText(m_titleAxisY); chart->legend()->setVisible(true); chart->legend()->setAlignment(Qt::AlignBottom); chart->addAxis(axisY, Qt::AlignLeft); @@ -85,7 +84,7 @@ void Graph::buildBarChartDiffDepo(const std::map &data) QChart *chart = new QChart(); chart->addSeries(series); - chart->setTitle(title); + chart->setTitle(m_title); chart->setAnimationOptions(QChart::SeriesAnimations); QStringList categories; @@ -99,19 +98,12 @@ void Graph::buildBarChartDiffDepo(const std::map &data) series->attachAxis(axisX); QValueAxis *axisY = new QValueAxis(); - auto max = std::max_element(data.begin(), data.end(), - [](const std::pair &p1, const std::pair &p2) { - return p1.second < p2.second; - }); - auto min = std::min_element(data.begin(), data.end(), - [](const std::pair &p1, const std::pair &p2) { - return p1.second < p2.second; - }); + auto param = min_max_range_element(data); // axisY->setRange(0, max->second + min->second); // axisY->setTickCount(data.size() * 1.5); - axisY->setTitleText(titleAxisY); + axisY->setTitleText(m_titleAxisY); chart->legend()->setVisible(true); chart->legend()->setAlignment(Qt::AlignBottom); chart->addAxis(axisY, Qt::AlignLeft); @@ -132,7 +124,7 @@ void Graph::buildLineChart(const std::map &data) { chart->legend()->hide(); chart->addSeries(series); chart->createDefaultAxes(); - chart->setTitle(titleAxisY); + chart->setTitle(m_titleAxisY); // QValueAxis *axisY = new QValueAxis(); // // axisY->setTickCount(10); @@ -146,3 +138,41 @@ void Graph::buildLineChart(const std::map &data) { setChartView(chart); } + +void Graph::buildDateTimeAxes(const std::map &data) { + + QLineSeries *series = new QLineSeries(); + + for (auto items : data) { + QDateTime momentInTime = QDateTime::fromString(items.first, m_datetimeFormat); + series->append(momentInTime.toMSecsSinceEpoch(), items.second); + } + + QChart *chart = new QChart(); + chart->legend()->hide(); + chart->addSeries(series); + chart->setTitle(m_titleAxisY); + + + QDateTimeAxis * axisX = new QDateTimeAxis; + axisX->setTickCount(10); +// axisX->setTickCount(data.size()/4); + axisX->setFormat(m_datetimeFormat); + chart->addAxis(axisX, Qt::AlignBottom); + series->attachAxis(axisX); + + + auto param = min_max_range_element(data); + + QValueAxis * axisY = new QValueAxis; + axisY->setLabelFormat(" %i"); + axisY->setRange(0, param.first + param.second); + axisY->setTickCount(10); + + axisY->setTitleText(m_titleAxisY); + chart->addAxis(axisY, Qt::AlignLeft); + series->attachAxis(axisY); + + setChartView(chart); +} + diff --git a/common/chart.h b/common/chart.h index 8d5f8c1..e82c347 100755 --- a/common/chart.h +++ b/common/chart.h @@ -16,20 +16,37 @@ #include #include + +template +auto min_max_range_element (Container &data) { + + auto max = std::max_element(data.begin(), data.end(), + [](const std::pair &p1, const std::pair &p2) { + return p1.second < p2.second; + }); + + auto min = std::min_element(data.begin(), data.end(), + [](const std::pair &p1, const std::pair &p2) { + return p1.second < p2.second; + }); + return std::make_pair(min->second, max->second); +} + class Graph { public: enum class TypeChart { BarChart, - LineChart + LineChart, + DateTimeAxesChart, }; - Graph() = default; + Graph(); void setTitleGraph(const QString title, const QString titleX, const QString titleY) { - this->title = title; - titleAxisX = titleX; - titleAxisY = titleY; + this->m_title = title; + m_titleAxisX = titleX; + m_titleAxisY = titleY; } void setType(TypeChart type ) { @@ -39,6 +56,7 @@ class Graph { void buildBarChart(const std::map &data); void buildBarChartDiffDepo(const std::map &data); void buildLineChart(const std::map &data); + void buildDateTimeAxes(const std::map &data); // build graph by timelineseries /** * @@ -78,11 +96,12 @@ class Graph { void setChartView(QChart *chart); private: - QString title; - QString titleAxisX; - QString titleAxisY; + QString m_title; + QString m_titleAxisX; + QString m_titleAxisY; + QString m_datetimeFormat; TypeChart m_type; -}; +}; #endif // CHART_H diff --git a/lib/common/future.h b/lib/common/future.h index adb6073..559d4aa 100644 --- a/lib/common/future.h +++ b/lib/common/future.h @@ -1,9 +1,6 @@ #ifndef SSM_FUTURE_H #define SSM_FUTURE_H - - - #include #include #include @@ -11,253 +8,267 @@ #include #include #include +#include -template -auto match(const R& range, Ts ...ts) -{ + namespace Market { + template + auto match(const R &range, Ts ...ts) { - return (std::count(std::begin(range), std::end(range), ts) + ...); -} + return (std::count(std::begin(range), std::end(range), ts) + ...); + } -template< typename T,typename ... Ts> -bool within(T min, T max, Ts ...ts) -{ - return ((min <= ts && ts<=max)&& ...); -} - -template -std::map invert(const std::map data) -{ - std::map invert_map; - for(const auto &item:data) - invert_map[item.second] = item.first; - return invert_map; -} + template + bool within(T min, T max, Ts ...ts) { + return ((min <= ts && ts <= max)&& ...); + } + template + std::map invert(const std::map data) { + std::map invert_map; + for (const auto &item:data) + invert_map[item.second] = item.first; + return invert_map; + } // calculate SMA usage history data [json, etc.] and period {example 20, 50, 100 } // usage price closing -float sma(std::vector price_closing, int period = 0) { - if(period > price_closing.size() || period < 0) - return 0L; - if(period != price_closing.size() && period != 0) - price_closing.resize(period); - return (float)std::accumulate(price_closing.begin(), price_closing.end(), 0) / price_closing.size(); -} - -float avg(std::vector data) -{ - return std::accumulate(data.begin(), data.end(), 0) /data.size(); -} + float sma(std::vector price_closing, int period = 0) { + if (period > price_closing.size() || period < 0) + return 0L; + if (period != price_closing.size() && period != 0) + price_closing.resize(period); + return (float) std::accumulate(price_closing.begin(), price_closing.end(), 0) / price_closing.size(); + } + + float avg(std::vector data) { + return std::accumulate(data.begin(), data.end(), 0) / data.size(); + } //Moving average -float MA(std::vector data) -{ - return std::accumulate(data.begin(), data.end(), 0) /data.size(); -} + float MA(std::vector data) { + return std::accumulate(data.begin(), data.end(), 0) / data.size(); + } // standart deviation for vector of prices -float std_dev(const std::vector &data) -{ - float dev_mean = MA(data); - float mean = 0L; - for(const auto &item:data ) - mean += std::pow(dev_mean - item, 2); - - float dev = mean/data.size() ; - return std::sqrt(dev); -} + float std_dev(const std::vector &data) { + float dev_mean = MA(data); + float mean = 0L; + for (const auto &item:data) + mean += std::pow(dev_mean - item, 2); + + float dev = mean / data.size(); + return std::sqrt(dev); + } //fill partS of vector -auto subset(int first, int last, std::vector vec) -{ - std::vector::const_iterator begin = vec.begin()+ first; - std::vector::const_iterator end = vec.end() + last; + auto subset(int first, int last, std::vector vec) { + std::vector::const_iterator begin = vec.begin() + first; + std::vector::const_iterator end = vec.end() + last; - std::vector subset { begin, end}; - return subset; -} + std::vector subset{begin, end}; + return subset; + } // Defines the Bollinger bands -void bands(std::vector prices, float standard_devs) -{ - auto top_band = MA(prices) + std_dev(prices) * standard_devs; - auto bottom_band = MA(prices) - std_dev(prices) * standard_devs; - - std::vector top_band_vec, bottom_band_vec; - //Fills in the vectors used for graphing. - top_band_vec.push_back(top_band); - bottom_band_vec.push_back(bottom_band); -} + void bands(std::vector prices, float standard_devs) { + auto top_band = MA(prices) + std_dev(prices) * standard_devs; + auto bottom_band = MA(prices) - std_dev(prices) * standard_devs; -bool buy_signal() -{ - bool signal { false }; + std::vector top_band_vec, bottom_band_vec; + //Fills in the vectors used for graphing. + top_band_vec.push_back(top_band); + bottom_band_vec.push_back(bottom_band); + } - return signal; -} -bool sell_signal(){ - bool signal {false}; - return signal; -} + bool buy_signal() { + bool signal{false}; + return signal; + } + + bool sell_signal() { + bool signal{false}; + return signal; + } -// weight for every indicators -class Indicator -{ - enum Type { - BB, - MA, - RSI, - ATR, - MACD, - DI, - }; -}; +// weight for every indicators + class Indicator { + enum Type { + BB, + MA, + RSI, + ATR, + MACD, + DI, + }; + + }; //common interface for all -class IStartegy{ - virtual void run() = 0; -}; - -class Strategy final : public IStartegy -{ - enum Type { - Scalping , // 0.5% - 1% with big volume - DayTrade, //IntraDay - BigVolume, - Grid, //trader by grid price assets - Swing, - Investment - }; - enum Trend { //global trend old timeframes [12h,1d,1w,1m] and local trend [4h,1h]; - Up, - Down, - Flat, //sideways - }; -public: - Strategy() = default; - void run() override {} -private: - bool signal { false }; -}; + class IStartegy { + virtual void run() = 0; + }; + + class Strategy final : public IStartegy { + public: + enum Type { + Scalping, // 0.5% - 1% with big volume + DayTrade, //IntraDay + BigVolume, + Grid, //trader by grid price assets + Swing, + Investment + }; + enum Trend { //global trend old timeframes [12h,1d,1w,1m] and local trend [4h,1h]; + Up, + Down, + Flat, //sideways + }; + + Strategy() = default; + void run() override {} + private: + bool signal{false}; + }; //order ID or hash ID? //for our ticker own ID -class Order { - enum Type { - Buy = 1, - Sell, - None //[hold] keep position - }; - enum Attribute { - Market = 1, - StopLimit, - StopLoss, - TakeProfit, - Trailing, - OCO - }; - //maybe type stop_loss, take_profit, market - enum Status { - Done, - PartDone, - Pendind, - Cancelled, - NoNe - }; - struct Config { - double currency_asset; - double profit; - double leverage; - double asset; - std::string_view asset_symbol; // ticker, symbol - long timestamp; //time order to set - long expiration_data;// data order is rancid - long updateTimestamp; - }; - long static ID; //orderID - using OrderType = Type; -public: - OrderType orderType; - Status status {NoNe}; - std::string toOrderTypeString(OrderType type) - { - return type == Buy? std::string("buy"):std::string("sell"); - } -}; - -class OrderHistory { -public: - OrderHistory () = default; -private: - std::vector m_order; -}; + class Order { + enum Type { + Buy = 1, + Sell, + None //[hold] keep position + }; + enum Attribute { + Market = 1, + StopLimit, + StopLoss, + TakeProfit, + Trailing, + OCO + }; + //maybe type stop_loss, take_profit, market + enum Status { + Done, + PartDone, + Pendind, + Cancelled, + NoNe + }; + struct Config { + double currency_asset; + double profit; + double leverage; + double asset; + std::string_view asset_symbol; // ticker, symbol + long timestamp; //time order to set + long expiration_data;// data order is rancid + long updateTimestamp; + }; + long static ID; //orderID + using OrderType = Type; + public: + OrderType orderType; + Status status{NoNe}; + + std::string toOrderTypeString(OrderType type) { + return type == Buy ? std::string("buy") : std::string("sell"); + } + }; + + class OrderHistory { + public: + OrderHistory() = default; + + private: + std::vector m_order; + }; // here must have wallet? -class BalanceInfo { -public: - BalanceInfo () = default; -private: - double currency_balance; - std::string asset; //ticker?; -}; - - -class Transaction { - enum TypeOperation { - Refill = 1, - Withdraw, - Trade - }; -}; - -class Wallet { - enum Symbol - { - USD, - EUR, - GBR, - CNY, - RUB - }; -public: - std::vector m_wallet; - long commonDeposit; //basesum in baseSymbol; - Symbol baseSymbol; // for convert -}; - -class Market { - enum Status { - Open = 1, - Closed, - Paused - }; - struct Config { - double bid {0.}; - double ask {0.}; - double volume {0.}; - double open {0.}; - double close {0.}; - double lastPrice {0.}; - double baseVolume {0.}; - double spread {0.}; - double priceTickSize {0.}; - }; -public: - Market() = default; - -private: - Status marketStatus; - -}; - + class BalanceInfo { + public: + BalanceInfo() = default; + + private: + double currency_balance; + std::string asset; //ticker?; + }; + + + class Transaction { + enum TypeOperation { + Refill = 1, + Withdraw, + Trade + }; + }; + + class Wallet { + enum Symbol { + USD, + EUR, + GBR, + CNY, + RUB + }; + public: + std::vector m_wallet; + long commonDeposit; //basesum in baseSymbol; + Symbol baseSymbol; // for convert + }; + + +//candlesticks +//in timeframes [1,5,15]m, [1,4,12]h and etc; + struct OHLC { + double open; + double close; + double high; + double low; + }; + + class Market { + enum Status { + Open = 1, + Closed, + Paused + }; + struct Config { + double bid{0.}; + double ask{0.}; + double volume{0.}; + double open{0.}; + double close{0.}; + double lastPrice{0.}; + double baseVolume{0.}; + double spread{0.}; + double priceTickSize{0.}; + }; + public: + Market() = default; + private: + Status marketStatus; + }; + + struct Tax { + double broker_comission; // комиссия брокера + double market_comission;// комиссия биржи + double order_comission;// комиссия на сделку [ broker_comission + market_comission] + double income_tax; // налог на прибыль + explicit Tax(const double broker_comission, const double market_comission, + const double income_tax) { + this->broker_comission = broker_comission; + this->market_comission = market_comission; + this->order_comission = broker_comission + market_comission; + this->income_tax = income_tax; + } + }; /** * @brief необходимо знать параметры сделки @@ -267,21 +278,21 @@ class Market { * параметры * необходимо учитывать налоги по сделке, чтобы вся прибыль не съедалась комиссиями биржи. налогами */ -class RiskManagement { -public: - RiskManagement() noexcept{} - void run(){}; -private: - const double base_risk_level { 3 } ; //in percentage допустимый уровень риска 1 к 3 [1] long and 1 к 3 при short - double tax_broker; // налог брокера - double tax_market;// налог биржи - double tax_profit;// налог на прибыль - double common_tax; // общий налог - Order m_order; + class RiskManagement { + public: + RiskManagement() noexcept {} + + void run() {}; + private: + const double base_risk_level{3}; //in percentage допустимый уровень риска 1 к 3 [1] long and 1 к 3 при short +// Tax tax; + Order m_order; + }; -}; + class ITradeAlgorithm; + class Scalping; //TODO: отдельные модули тестирования работы алгоритмов на исторических данных [analyze, work with machine learning] // модуль налог по текущим транзакциям и "распечатка" в pdf @@ -290,22 +301,221 @@ class RiskManagement { * @brief тестирование алгоритма на исторических данных [fix/fast] * \ результат список транзакций при работе определенного.алгоритма общий фин. результат */ -class BackTest{ //Emulator -public: - BackTest() = default; - void setData() {} - void getProviderData() {} - void loadOrders(){} - void loadBalance(){} - void run(){} -private: + class BackTest { //Emulator + public: + BackTest() = default; + + void setData() {} + + void getProviderData() {} + + void loadOrders() {} + + void loadBalance() {} + + void run() {} + + private: + ITradeAlgorithm *algo; + }; -}; + class ITradeAlgorithm { + public: + virtual void init() = 0; + virtual void start() = 0; + + virtual void restart() = 0; + + virtual void stop() = 0; + + virtual void configure() = 0; + + virtual std::shared_ptr clone() = 0; + + virtual ~ITradeAlgorithm() = default; + }; + + class Scalping final : public ITradeAlgorithm { + public: + + void init() noexcept override { std::cout<<" \n Init scalping strategy";}; + + void start() noexcept override {}; + + void restart() noexcept override {}; + + void stop() noexcept override {}; + + void configure() noexcept override {}; + + virtual std::shared_ptr clone() { + return std::make_shared(*this); + } + }; + class DayTrade final : public ITradeAlgorithm { + public: + DayTrade() = default; + void init() noexcept override { std::cout<<" \n Init intraday strategy";}; + void start() noexcept override {}; + + void restart() noexcept override {}; + + void stop() noexcept override {}; + + void configure() noexcept override {}; + + virtual std::shared_ptr clone() { + return std::make_shared(*this); + } + + }; + + class BigVolume final : public ITradeAlgorithm { + public: + BigVolume() = default; + + void init() noexcept override {}; + + void start() noexcept override {}; + + void restart() noexcept override {}; + + void stop() noexcept override {}; + + void configure() noexcept override {}; + + virtual std::shared_ptr clone() { + return std::make_shared(*this); + } + + }; + + class Grid final : public ITradeAlgorithm { + public: + Grid() = default; + + void init() noexcept override {}; + + void start() noexcept override {}; + + void restart() noexcept override {}; + + void stop() noexcept override {}; + + void configure() noexcept override {}; + + virtual std::shared_ptr clone() { + return std::make_shared(*this); + } + + }; + + class Swing final : public ITradeAlgorithm { + public: + Swing() = default; + + void init() noexcept override {}; + + void start() noexcept override {}; + + void restart() noexcept override {}; + + void stop() noexcept override {}; + + void configure() noexcept override {}; + + virtual std::shared_ptr clone() { + return std::make_shared(*this); + } + + }; + + class Investment final : public ITradeAlgorithm { + + public: + Investment() = default; + + void init() noexcept override {}; + + void start() noexcept override {}; + + void restart() noexcept override {}; + + void stop() noexcept override {}; + + void configure() noexcept override {}; + + virtual std::shared_ptr clone() { + return std::make_shared(*this); + } + + }; + + class TraderAlgorithmFactory { + using Ptr = std::shared_ptr; + public: + + TraderAlgorithmFactory() = default; + + static std::shared_ptr createAlgo(const Strategy::Type type) { +// auto createAlgo(const Strategy::Type type) { + switch (type) { + case Strategy::Type::Scalping: + return std::make_shared(); + break; + case Strategy::Type::DayTrade: + return std::make_shared(); + break; + case Strategy::Type::Grid: + return std::make_shared(); + break; + case Strategy::Type::Investment: + return std::make_shared(); + break; + case Strategy::Type::Swing: + return std::make_shared(); + break; + case Strategy::Type::BigVolume: + return std::make_shared(); + break; + } + return nullptr; + } + + private: + Ptr *algo; + }; + + +//strategy volume + +//Ind. Fibo +//Ind. Cluster charts +//Ind Zig Zag +//Ind. Delta + +//indicator OBV +//indicator Accumulation/Distribution + +/** + * @brief + */ + class AnalyzeSearch { + enum Trend { //global trend old timeframes [12h,1d,1w,1m] and local trend [4h,1h]; + Up, + Down, + Flat, //sideways + }; + public: + AnalyzeSearch() = default; + }; + +} diff --git a/lib/common/grid.h b/lib/common/grid.h index 9dd9ee8..2339ebd 100644 --- a/lib/common/grid.h +++ b/lib/common/grid.h @@ -60,6 +60,7 @@ namespace Common { return data_column; } + //todo: usage multimap auto byColumns(const int col1, const int col2) { std::map data_columns; for (size_t rows = 0; rows < getSizeGrid().second; rows++) diff --git a/main.cpp b/main.cpp index ae2fc24..829173b 100644 --- a/main.cpp +++ b/main.cpp @@ -2,6 +2,8 @@ #include +#include "future.h" + Common::Logger::ConsoleLogger * Common::Logger::ConsoleLogger::p_instanse = 0; int main(int argc, char *argv[]) @@ -9,7 +11,6 @@ int main(int argc, char *argv[]) QApplication a(argc, argv); - MainWindow app; app.show(); @@ -39,16 +40,15 @@ int main(int argc, char *argv[]) // qDebug() <<"Size ranges: " <init(); + algo = Market::TraderAlgorithmFactory::createAlgo(Market::Strategy::Type::DayTrade); + algo->init(); -// calculate SMA usage history data [json, etc.] and period {example 20, 50, 100 } -// std::vector price_closing { 3.00, 5.10, 2.45, 1.33, 2.23, 3.22 }; -// int period = 5;//not usage -// auto sma = [](const int period, std::vector price_closing) { -// return std::accumulate(price_closing.begin(), price_closing.end(), 0) / price_closing.size(); -// }; - - //calculate esma + auto algo_3 = algo->clone(); + algo_3->init(); return a.exec(); From 3671d480183493b79a8705bece7b88d33a79a128 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sun, 10 Sep 2023 20:02:42 +0300 Subject: [PATCH 3/3] add tradelog --- CMakeLists.txt | 4 +- Model/acsmodel.cpp | 4 +- README.md | 25 ++++--- common/avgcoststocks.h | 2 +- common/chart.cpp | 24 +++++- common/chart.h | 3 + common/csvreader.h | 8 +- common/mainwindow.cpp | 151 +++++++++++++++++++++++++++----------- common/mainwindow.h | 13 +++- common/mainwindow.ui | 44 ++++++++++- common/tradelog.cpp | 1 + common/tradelog.h | 65 ++++++++++++++++ lib/common/CMakeLists.txt | 4 + lib/common/dca.h | 6 +- lib/common/future.h | 80 +++++++++++++++----- 15 files changed, 343 insertions(+), 91 deletions(-) create mode 100755 common/tradelog.cpp create mode 100755 common/tradelog.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a99103..039fa70 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,7 @@ SET( SOURCE_FILES common/avgcoststocks.cpp common/chart.cpp common/csvmodel.cpp + common/tradelog.cpp main.cpp) SET( HEADER_FILES Model/acsmodel.h @@ -71,7 +72,8 @@ SET( HEADER_FILES common/threadpool.h common/timer.h common/csvreader.h - common/csvmodel.h ) + common/csvmodel.h + common/tradelog.h) #file(GLOB CLIENT_FILE *.cpp *.h) diff --git a/Model/acsmodel.cpp b/Model/acsmodel.cpp index 6ca43bf..70c9aec 100644 --- a/Model/acsmodel.cpp +++ b/Model/acsmodel.cpp @@ -60,11 +60,11 @@ QVariant ACSModel::headerData(int section, Qt::Orientation orientation, int role if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { switch (section) { case 0: - return QString("Assets"); + return QString("Amount"); case 1: return QString("Price"); case 2: - return QString("TotalAmount"); + return QString("Total"); } } diff --git a/README.md b/README.md index 07fb9de..2e66495 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ -#Service Stock Markets +## Service Stock Markets The service for calculate some parameters stock market -##Requirements -
-QT +## Requirements +
-C++17 compiler support
-Cmake +
-QT
-Doxygen -
-C++17 compiler support -##Build + +## Build git clone https://github.com/silverstringer/ssm.git mkdir build && cd build @@ -14,18 +15,24 @@ cmake .. make -j8 -##Install +## Install make install -##Run +## Run -##Usage +## Usage 1) Simple Dollar Cost Average Digital Asset( on bull market) 2) Different percentage on month 3) Calculate average price of asset -*Advanced. Save result on *.csv file, build graph +*Advanced. Save resultDCA on *.csv file, build graph + +## TODO. +1.Assets allocation by percentage [ ] +2.Import history order from broker [ ] +3.Analyze history orders, profit and loss all assets [any] +4.Usage DB sqlite for store or csv? diff --git a/common/avgcoststocks.h b/common/avgcoststocks.h index 6014b68..f2591c9 100644 --- a/common/avgcoststocks.h +++ b/common/avgcoststocks.h @@ -12,7 +12,7 @@ /** - * @brief average result of buy assets + * @brief average resultDCA of buy assets */ class AvgCostStocks : public QWidget { diff --git a/common/chart.cpp b/common/chart.cpp index 16ec97f..8b7b7f1 100755 --- a/common/chart.cpp +++ b/common/chart.cpp @@ -77,7 +77,7 @@ void Graph::buildBarChartDiffDepo(const std::map &data) set[i] = new QBarSet(key); *set[i] <append(set[i]); i++; } @@ -176,3 +176,25 @@ void Graph::buildDateTimeAxes(const std::map &data) { setChartView(chart); } +void Graph::buildPieChart(const std::map &data) { + + QPieSeries * series = new QPieSeries(); + for(auto &items: data) + series->append(items.first, items.second); + + series->setLabelsVisible(true); + series->setLabelsPosition(QPieSlice::LabelInsideHorizontal); + + QPieSlice * slice = series->slices().at(1); + for( auto slice : series->slices()) + slice->setLabel(QString("%1% %2").arg(100 * slice->percentage(), 0, 'f', 1).arg(slice->label())); + slice->setExploded(); + slice->setLabelVisible(); + slice->setPen(QPen(Qt::darkGreen,2)); + slice->setBrush(Qt::green); + + QChart *chart = new QChart(); +// chart->legend()->hide(); + chart->addSeries(series); + setChartView(chart); +} diff --git a/common/chart.h b/common/chart.h index e82c347..55bc0d5 100755 --- a/common/chart.h +++ b/common/chart.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,7 @@ class Graph { BarChart, LineChart, DateTimeAxesChart, + PieChart, }; Graph(); @@ -57,6 +59,7 @@ class Graph { void buildBarChartDiffDepo(const std::map &data); void buildLineChart(const std::map &data); void buildDateTimeAxes(const std::map &data); // build graph by timelineseries + void buildPieChart(const std::map &data); /** * diff --git a/common/csvreader.h b/common/csvreader.h index fecbc8c..0e20160 100644 --- a/common/csvreader.h +++ b/common/csvreader.h @@ -119,12 +119,12 @@ static std::vector> read_csv(std::string filename) { } //static std::vector > read_csv_map(string filename) { -// std::vector> result; +// std::vector> resultDCA; // // auto csv = read_csv(filename); // // if (csv.size() < 2) -// return result; +// return resultDCA; // // auto names = csv[0]; // for (int i = 1; i < csv.size(); i++) { @@ -137,10 +137,10 @@ static std::vector> read_csv(std::string filename) { // " file " + filename); // line[names[j]] = csv[i][j]; // } -// result.push_back(line); +// resultDCA.push_back(line); // } // -// return result; +// return resultDCA; //}; diff --git a/common/mainwindow.cpp b/common/mainwindow.cpp index 55db701..1c58164 100644 --- a/common/mainwindow.cpp +++ b/common/mainwindow.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -20,54 +21,46 @@ MainWindow::MainWindow(QWidget *parent) : ui->setupUi(this); setDefaultValue(); - m_acs = new AvgCostStocks(); - //Connect + setHotKey(); + connect(ui->spnFirstAssest, static_cast(&QDoubleSpinBox::valueChanged), [this]() { - emit (totalSumFirstOrder()); + emit totalSumFirstOrder(); }); connect(ui->btnDiffPercent, &QPushButton::clicked, [this]() { + calculateDiffPercentage(); + }); - resultDiffPercent.clear(); - double depo = ui->spnDepoDiffPerc->value(); - double percentage = ui->spnDiffPercentInMonth->value(); - int period = ui->spnDiffPercentDuration->value(); + connect(ui->spnFirstPrice, static_cast(&QDoubleSpinBox::valueChanged), [this]() { + emit totalSumFirstOrder(); + }); - resultDiffPercent = Strategy::calculateDiffPercentPeriod(depo, percentage, period); -// resultDiffPercent = Strategy::calculateDiffPercentPeriodAddStock(depo,50,percentage,period); + connect(ui->spnDeposit, static_cast(&QDoubleSpinBox::valueChanged), [this]() { - ui->lblResultDiffPercent->setText(QString::number(std::prev(resultDiffPercent.end())->second, 'f', 2)); + std::unique_ptr graph = std::make_unique(); + graph->setType(Graph::TypeChart::PieChart); + graph->setTitleGraph("Stock portfolio", "Month", "Depo"); - getDiffPercentDetails(); - }); + std::map test_data = {{"EUR", 3}, {"BLR", 6}, + {"USD", 5}, {"TRY", 12}, + {"GBR", 2}, {"CNY", 7}}; - connect(ui->spnFirstPrice, static_cast(&QDoubleSpinBox::valueChanged), [this]() { - emit (totalSumFirstOrder()); +// graph->buildPieChart(test_data); }); connect(ui->btnAvgCostStock, &QPushButton::clicked, [this]() { m_acs->show(); }); + connect(ui->btnDetail, &QPushButton::clicked, [this]() { detailDCA(); }); connect(ui->btnBackgrColor, &QPushButton::clicked, [this]() { - QList spinBox = this->findChildren(); - - if (isMoonTheme == true) { - setStyleSheet("background-color:#393C39;color: #F5F5F5;"); - } else { - setStyleSheet("background-color:#E0E0E0; color: black;"); - for (auto *items :spinBox) - items->setStyleSheet("background-color:white;color: black;"); - } - - (isMoonTheme == false) ? (isMoonTheme = true) : (isMoonTheme = false); - + setBackgroundMainWindow(); }); @@ -75,20 +68,10 @@ MainWindow::MainWindow(QWidget *parent) : if (ui->spnFirstPrice->value() < ui->spnGoalPrice->value()) ui->spnGoalPrice->setValue(ui->spnFirstPrice->value()); - }); - connect(ui->btnCalculate, &QPushButton::clicked, [this]() { - - result.assets = ui->spnFirstAssest->value(); - result.price = ui->spnFirstPrice->value(); - result.goal_price = ui->spnGoalPrice->value(); - - timer timer; - timer.start(); - calculate(result); - timer.stop().print(); - + connect(ui->btnCalculateDCA, &QPushButton::clicked, [this]() { + calculateDCA(); }); } @@ -116,18 +99,23 @@ void MainWindow::detailDCA() { // this->setCentralWidget(tv); // Configure column titles - std::vector headerDCA = { "Assets", "Price", "Sum", "%"}; + std::vector headerDCA = { "Amount", "Price", "Sum", " Down price , %", "Percentage from m_depo"}; for( size_t items = 0; items < headerDCA.size(); items++) model->setHorizontalHeaderItem(items, new QStandardItem(headerDCA.at(items))); // Add rows to the model QList rowData; - for (const auto &item:result.goal_range) { + for (const auto &item:resultDCA.goal_range) { rowData.clear(); + auto partofdepo = (item.second * item.first * 100) / m_depo; + auto dd = new QStandardItem(QString("%1").arg(partofdepo)); rowData << new QStandardItem(QString("%1").arg(item.first)); rowData << new QStandardItem(QString("%1").arg(item.second)); rowData << new QStandardItem(QString("%1").arg(item.second * item.first)); - rowData << new QStandardItem(QString("%1").arg((item.second * 100 / result.price) - 100)); + rowData << new QStandardItem(QString("%1").arg((item.second * 100 / resultDCA.price) - 100)); + rowData << dd; + (partofdepo > 100) ? (dd->setForeground(QColor(Qt::red))):( dd->setForeground(QColor(Qt::green))); + model->appendRow(rowData); } @@ -207,6 +195,10 @@ void MainWindow::setDefaultValue() { ui->spnFirstPrice->setDecimals(4); + ui->spnDeposit->setRange(0,10000000); + ui->spnDeposit->setDecimals(4); + + ui->spnTotalAsset->setRange(0, 1600000); ui->spnGoalPrice->setRange(0, 1600000); @@ -219,10 +211,12 @@ void MainWindow::setDefaultValue() { ui->spnDepoDiffPerc->setRange(0, 10000000); ui->spnDiffPercentDuration->setRange(0, 10000); + ui->spnDeposit->setRange(0, 100000000); ui->spnFirstAssest->setValue(10); ui->spnFirstPrice->setValue(100); ui->spnGoalPrice->setValue(90); + ui->spnDeposit->setValue(800); ui->spnRangeAsset->setReadOnly(true); ui->spnRangePrice->setReadOnly(true); ui->spnDepoDiffPerc->setValue(100); //default value 100 @@ -379,7 +373,7 @@ void MainWindow::getDiffPercentDetails() { std::unique_ptr logger(new Common::Logger::CSVLogger); - std::string current_filename = "diff_percent_log.csv"; + std::string current_filename = RESULT_DCA_FILE; std::string dump_dir = (getenv("HOME") != nullptr ? std::string(getenv("HOME")) : "/tmp") + std::string("/.ssm/"); auto current_data = QDateTime::currentDateTime().toString("dd-MM-yyyy"); auto filename_with_date = current_data.toStdString() + "_" + current_filename; @@ -454,3 +448,76 @@ void MainWindow::getDiffPercentDetails() { model.setTitleWindow("Strategy Difference Percentage").setHeaderTable(headerSDF).build("/tmp/log.csv", delim); }); } + +void MainWindow::calculateDiffPercentage() { + + resultDiffPercent.clear(); + double depo = ui->spnDepoDiffPerc->value(); + double percentage = ui->spnDiffPercentInMonth->value(); + int period = ui->spnDiffPercentDuration->value(); + resultDiffPercent = Strategy::calculateDiffPercentPeriod(depo, percentage, period); +// resultDiffPercent = Strategy::calculateDiffPercentPeriodAddStock(m_depo,50,percentage,period); + ui->lblResultDiffPercent->setText(QString::number(std::prev(resultDiffPercent.end())->second, 'f', 2)); + getDiffPercentDetails(); +} + +void MainWindow::calculateDCA() { + resultDCA.assets = ui->spnFirstAssest->value(); + resultDCA.price = ui->spnFirstPrice->value(); + resultDCA.goal_price = ui->spnGoalPrice->value(); + m_depo = ui->spnDeposit->value(); + + timer timer; + timer.start(); + calculate(resultDCA); + timer.stop().print(); +} + +void MainWindow::setHotKey() { + + QShortcut * shortcutDCAcalc = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_S), this); + connect(shortcutDCAcalc, &QShortcut::activated, this, [this](){ + calculateDCA(); + }); + + QShortcut * shortcutDCADetail = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_D), this); + connect(shortcutDCADetail, &QShortcut::activated, this, [this](){ + detailDCA(); + }); + + + QShortcut * shortcutMoonBackground = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_B), this); + connect(shortcutMoonBackground, &QShortcut::activated, this, [this](){ + setBackgroundMainWindow(); + }); + + + QShortcut * shortcutACSCalculate = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_A), this); + connect(shortcutACSCalculate, &QShortcut::activated, this, [this](){ + m_acs->show(); + }); + + QShortcut * shortcutDiffPercentage = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_X), this); + connect(shortcutDiffPercentage, &QShortcut::activated, this, [this](){ + calculateDiffPercentage(); + }); + +} + +void MainWindow::setBackgroundMainWindow() { + + QList spinBox = this->findChildren(); + + if (isMoonTheme == true) { + setStyleSheet("background-color:#393C39;color: #F5F5F5;"); + } else { + setStyleSheet("background-color:#E0E0E0; color: black;"); + for (auto *items :spinBox) + items->setStyleSheet("background-color:white;color: black;"); + } + + (isMoonTheme == false) ? (isMoonTheme = true) : (isMoonTheme = false); + +} + + diff --git a/common/mainwindow.h b/common/mainwindow.h index a55069d..01d208e 100644 --- a/common/mainwindow.h +++ b/common/mainwindow.h @@ -9,12 +9,13 @@ #include "grid.h" #include "chart.h" #include "csvreader.h" -#include "csvmodel.h" +#include "csvmodel.h" #include #include -#define MAX_ASSETS 10000000 //max value of assets on calculate +#define MAX_ASSETS 100000000 //max value of assets on calculate +#define RESULT_DCA_FILE "diff_percent_log.csv" namespace Ui { class MainWindow; @@ -40,17 +41,21 @@ class MainWindow : public QMainWindow void totalSumFirstOrder(); void calcDone(); protected: - dca result; + dca resultDCA; + double m_depo; // balance user oder m_depo private: void setDefaultValue(); void calculate(double assets, double price, double goal_price); void calculate(dca &res, int max_range = MAX_ASSETS); + void calculateDCA(); + void calculateDiffPercentage(); + void setHotKey(); + void setBackgroundMainWindow(); private: bool isMoonTheme { false }; std::map resultDiffPercent; AvgCostStocks * m_acs { nullptr }; Ui::MainWindow * ui; - }; template diff --git a/common/mainwindow.ui b/common/mainwindow.ui index a4fbde3..e6af393 100755 --- a/common/mainwindow.ui +++ b/common/mainwindow.ui @@ -11,7 +11,7 @@ - DCA + SSM @@ -152,7 +152,7 @@ - + 290 @@ -162,7 +162,7 @@ - calculate + Calculate @@ -287,7 +287,7 @@ 390 0 - 121 + 131 41 @@ -442,6 +442,42 @@ Dark + + + + 10 + 303 + 91 + 31 + + + + + + + 110 + 310 + 41 + 16 + + + + Depo + + + + + + 390 + 300 + 91 + 31 + + + + Trade log + + diff --git a/common/tradelog.cpp b/common/tradelog.cpp new file mode 100755 index 0000000..43e47be --- /dev/null +++ b/common/tradelog.cpp @@ -0,0 +1 @@ +#include "tradelog.h" diff --git a/common/tradelog.h b/common/tradelog.h new file mode 100755 index 0000000..c6903e6 --- /dev/null +++ b/common/tradelog.h @@ -0,0 +1,65 @@ +#ifndef SSM_TRADELOG_H +#define SSM_TRADELOG_H + +#include +#include +#include + +/** + * @brief файл журнала сделок + * @note usage in future struct from future + * //скорее всего выгрузка из таблицы с id trader [ или id можно внести в общий конфиг] + */ + +class TradeLog final { + using string = std::string; +public: + explicit TradeLog(ushort uid_trader) {}; +protected: + struct Config { + string timestampOpen; //dd-mm-yy + string timestampClose; //dd-mm-yy + string orderType; + string typePosition; //[long, short] + string ticker; + string account_balance; + string entry_price; + long long amount; + string SL; //stop loss price + string TP; //take profit price; + string planned_risk_reward; + string actual_exit_price; + string trade_cost;//издержки сделки, стоимость сделки, [taxes, transaction_fee] + double percentage_account_risked; //risk_level; + string closed_position_PL; // [profit - loss] + string account_change_in_percentage; + string pattern_usage; // why i entered deal + }; +private: + ushort uid_trader; +}; + + //PNL, profit and loss; + + class AnalyzeTradeLogSummary final { + using string_view = std::string_view; + public: + explicit AnalyzeTradeLogSummary(); + protected: + ushort total_number_winning_trades; + ushort total_number_losing_trades; + int trade_win_rate; + int average_win_trade; + int average_losing_trade; + ushort largest_lose_trade; + ushort largest_losing_trade; + double total_PL; //profit_loss; + double average_PL; //profit_loss; + double ROI;//return on investment; + double average_risk_per_trade; + double average_reward_per_trade; + double average_risk_reward; + // usage on Month analysis, on Summary All; + }; + +#endif //SSM_TRADELOG_H diff --git a/lib/common/CMakeLists.txt b/lib/common/CMakeLists.txt index 18ace67..31c6c12 100644 --- a/lib/common/CMakeLists.txt +++ b/lib/common/CMakeLists.txt @@ -2,7 +2,11 @@ cmake_minimum_required( VERSION 3.1) project(common VERSION 1.0.0 DESCRIPTION "Common Library for Service Stock Market") message("Lib for Service Stock Market") +message( "Project name:" ${PROJECT_NAME}) + +set(CMAKE_DEFAULT_BUILD_TYPE "Release") set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) add_compile_options(-Wall -Wextra -Wno-unused-function) diff --git a/lib/common/dca.h b/lib/common/dca.h index f1cb2f9..61b3692 100644 --- a/lib/common/dca.h +++ b/lib/common/dca.h @@ -80,7 +80,7 @@ namespace Strategy { double static calculateDiffPercent(DiffPercent &dps) { dps.convertPercentage(); double result = dps.deposit * pow(dps.m_percent, dps.step - 1); -// double result = dps.deposit * pow(1 + dps.m_percent / dps.step, dps.step); +// double resultDCA = dps.deposit * pow(1 + dps.m_percent / dps.step, dps.step); return result; } @@ -92,7 +92,7 @@ namespace Strategy { // double refill = dps.m_refill * pow(dps.m_percent, dps.step - 1); // std::cout<<"Refill calc: " << refill <<"\n"; -// return (double)(result + refill); +// return (double)(resultDCA + refill); return result; } @@ -145,7 +145,7 @@ namespace Strategy { auto diff_price = res.goal_price - find_down_price; - //todo: поменять допустимый диапазон [отклонение] расхождение + //todo: поменять допустимый диапазон [отклонение, delta] расхождение if (diff_price == 0) { res.goal_range[min_range] = range_price; } diff --git a/lib/common/future.h b/lib/common/future.h index 559d4aa..f2e3dc6 100644 --- a/lib/common/future.h +++ b/lib/common/future.h @@ -11,6 +11,15 @@ #include + //Algo Trading + /** + 1)Market Research + 2)Backtesting + 3)Work with data [library for working with data visualization and plotting, analyse data, etc. ] + 4)Live Trading + *Note. Usage Machine learnings for models + **/ + namespace Market { template auto match(const R &range, Ts ...ts) { @@ -110,14 +119,14 @@ }; //common interface for all - class IStartegy { + class IStrategy { virtual void run() = 0; }; - class Strategy final : public IStartegy { + class Strategy final : public IStrategy { public: enum Type { - Scalping, // 0.5% - 1% with big volume + Scalping, // 0.5% - 1% with big volume, a) impulse b) order book c) hybrid DayTrade, //IntraDay BigVolume, Grid, //trader by grid price assets @@ -190,16 +199,20 @@ }; -// here must have wallet? + // here must have wallet? class BalanceInfo { public: BalanceInfo() = default; private: double currency_balance; - std::string asset; //ticker?; + std::string asset; //currency }; + class Balance { + + }; + class Transaction { enum TypeOperation { @@ -219,8 +232,8 @@ }; public: std::vector m_wallet; - long commonDeposit; //basesum in baseSymbol; - Symbol baseSymbol; // for convert + long amount; //basesum in baseSymbol; + Symbol baseSymbol; // for convert for any asset }; @@ -233,27 +246,58 @@ double low; }; + + /* + * @brief + * @note description our assets + * лучше использовать понятие актив [ валюта, акции, облигации] + */ + class Currency { + public: + enum Status{ + OK = 1, + Maintance, + }; + + struct Config { + std::string name; + std::string description; + std::string ticker; + std::string StatusMessage; + }; + + Currency() = default; + + }; + + class Market { enum Status { Open = 1, Closed, Paused }; + +// using MarketId = Id; struct Config { - double bid{0.}; - double ask{0.}; - double volume{0.}; - double open{0.}; - double close{0.}; - double lastPrice{0.}; - double baseVolume{0.}; - double spread{0.}; - double priceTickSize{0.}; + double bid {0.}; + double ask {0.}; + double volume {0.}; + double open {0.}; + double close {0.}; + double lastPrice {0.}; + double baseVolume {0.}; + double spread {0.}; + double priceTickSize {0.}; + Status marketStatus {Open}; }; public: Market() = default; + Market(IStrategy * strategy): m_strategy(strategy){ } private: Status marketStatus; + IStrategy * m_strategy; + }; struct Tax { @@ -514,10 +558,6 @@ public: AnalyzeSearch() = default; }; - } - - - #endif //SSM_FUTURE_H