diff --git a/.gitignore b/.gitignore
index 9062042..99850c3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
/*.idea
*/.idea
*.pro.*
+*.vscode
#Build
/build
@@ -9,6 +10,7 @@
/cmake*
Makefile
*stash*
+.env
#Library
@@ -19,3 +21,4 @@ Makefile
+/.vscode/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 039fa70..f90cc12 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,13 +10,22 @@ message(status "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
if(MSVS)
add_compile_options( /wd4127 /wd4250)
else()
-add_compile_options(-Wall -Wextra -Wno-unused-function ) #-Werror
+add_compile_options(-Wall -Wextra -Wno-unused-function) #-Werror -Wpedantic
+endif()
+
+
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g")
+elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -DNDEBUG")
endif()
add_subdirectory(lib/common)
#find Package
-find_package(Qt5 COMPONENTS Widgets Network Core Gui Charts REQUIRED)
+find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
+find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network Core Gui Multimedia Charts)
+
find_package(Threads REQUIRED)
#for QT
@@ -25,12 +34,11 @@ set(CMAKE_AUTOMOC ON)
#set(CMAKE_AUTORCC ON)
#Standart
-set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS -pthread)
-
#Version
set(VERSION_MAJOR 0)
set(VERSION_MINOR 2)
@@ -51,30 +59,12 @@ set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/common/)
-#file( GLOB_RECURSE SOURCE_FILES *.cpp)
-#file( GLOB_RECURSE HEADER_FILES *.h)
+file( GLOB_RECURSE SOURCE_FILES common/*.cpp Model/acsmodel.cpp main.cpp)
+file( GLOB_RECURSE HEADER_FILES common/*.h Model/acsmodel.h)
+
#file( GLOB_RECURSE MODEL_FILES Model/*.cpp)
#file( GLOB_RECURSE API_FILES Model/*.h)
-SET( SOURCE_FILES
- Model/acsmodel.cpp
- common/mainwindow.cpp
- common/avgcoststocks.cpp
- common/chart.cpp
- common/csvmodel.cpp
- common/tradelog.cpp
- main.cpp)
-SET( HEADER_FILES
- Model/acsmodel.h
- common/mainwindow.h
- common/avgcoststocks.h
- common/chart.h
- common/threadpool.h
- common/timer.h
- common/csvreader.h
- common/csvmodel.h
- common/tradelog.h)
-
#file(GLOB CLIENT_FILE *.cpp *.h)
set(UIFORM common/mainwindow.ui)
@@ -83,12 +73,10 @@ set(UIFORM common/mainwindow.ui)
QT5_WRAP_UI(UI_HEADERS ${UIFORM} )
add_executable(${PROJECT_NAME} ${HEADER_FILES} ${SOURCE_FILES} ${UI_HEADERS})
-target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets Qt5::Network Qt5::Core Qt5::Gui Qt5::Charts Threads::Threads stdc++fs lib::common)
+target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Charts Threads::Threads stdc++fs lib::common)
install (TARGETS ${PROJECT_NAME} DESTINATION bin)
-#SET(CPACK_PACKAGE_VERSION "1.0.2")
-
set(CPACK_SYSTEM_NAME ${SO_VERSION})
#Generate debian package with cpack [or alternative make package]
diff --git a/README.md b/README.md
index 2e66495..32cffd9 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
## Service Stock Markets
The service for calculate some parameters stock market
## Requirements
-
-C++17 compiler support
+
-C++20 compiler support
-Cmake
-QT
-Doxygen
@@ -12,19 +12,19 @@ git clone https://github.com/silverstringer/ssm.git
mkdir build && cd build
cmake ..
-
-make -j8
+make -j12
## Install
make install
## Run
-
## Usage
1) Simple Dollar Cost Average Digital Asset( on bull market)
2) Different percentage on month
3) Calculate average price of asset
+4) Futures calc
+5) Invest calc
*Advanced. Save resultDCA on *.csv file, build graph
diff --git a/common/chart.cpp b/common/chart.cpp
index 8b7b7f1..9067611 100755
--- a/common/chart.cpp
+++ b/common/chart.cpp
@@ -76,8 +76,6 @@ void Graph::buildBarChartDiffDepo(const std::map &data)
for (auto&& [key, value] : data) {
set[i] = new QBarSet(key);
*set[i] <append(set[i]);
i++;
}
@@ -98,7 +96,7 @@ void Graph::buildBarChartDiffDepo(const std::map &data)
series->attachAxis(axisX);
QValueAxis *axisY = new QValueAxis();
- auto param = min_max_range_element(data);
+ [[maybe_unused]]auto param = min_max_range_element(data);
// axisY->setRange(0, max->second + min->second);
// axisY->setTickCount(data.size() * 1.5);
@@ -117,8 +115,14 @@ void Graph::buildLineChart(const std::map &data) {
QLineSeries *series = new QLineSeries();
+ QVector points;
+
for (auto&& [key, value] : data)
- series->append(key,value);
+ points.append(QPointF(key, value));
+ series->replace(points);
+
+ // for (auto&& [key, value] : data)
+ // series->append(key,value);
QChart *chart = new QChart();
chart->legend()->hide();
diff --git a/common/mainwindow.cpp b/common/mainwindow.cpp
index 1c58164..7155024 100644
--- a/common/mainwindow.cpp
+++ b/common/mainwindow.cpp
@@ -12,6 +12,11 @@
#include
#include
+#include
+#include
+#include
+
+
#include
@@ -70,8 +75,66 @@ MainWindow::MainWindow(QWidget *parent) :
ui->spnGoalPrice->setValue(ui->spnFirstPrice->value());
});
+ connect(ui->btnFuturesCalc, &QPushButton::clicked, []() {
+
+ try {
+ QtConcurrent::run([]() {
+ FuturesCalculator calc;
+ calc.run();
+ });
+ }
+ catch(std::exception& e){
+ qDebug() <btnInvestmentCalc, &QPushButton::clicked, []() {
+
+ try {
+ QtConcurrent::run([]() {
+
+ int currentLots;
+ double currentAvgPrice, targetAvgPrice, budget;
+
+ std::cout << "\n Введите текущее количество лотов: ";
+ std::cin >> currentLots;
+ std::cout << "Введите текущую среднюю цену (руб.): ";
+ std::cin >> currentAvgPrice;
+ std::cout << "Введите целевую среднюю цену (руб.): ";
+ std::cin >> targetAvgPrice;
+ std::cout << "Введите бюджет (руб., или 0 для неограниченного): ";
+ std::cin >> budget;
+ budget = (budget <= 0) ? std::numeric_limits::max() : budget;
+
+ InvestmentCalculator::compareStrategies(currentLots, currentAvgPrice, targetAvgPrice, budget);
+
+ });
+ }
+ catch(std::exception& e){
+ qDebug() <btnCalculateDCA, &QPushButton::clicked, [this]() {
- calculateDCA();
+
+ QFuture future = QtConcurrent::run(this, &MainWindow::calculateDCA);
+ QFutureWatcher * watcher_calculate = new QFutureWatcher (this);
+ connect(watcher_calculate, &QFutureWatcher::finished,this,[&](){
+ emit calcDone();
+ ui->btnCalculateDCA->setText("calculate");
+
+// ui->spnGoalPrice->setStyleSheet("QDoubleSpinBox {color : red;}");
+//
+// ui->spnRangeAsset->setStyleSheet("QDoubleSpinBox {color : green; }");
+// ui->spnRangePrice->setStyleSheet("QDoubleSpinBox {color : green; }");
+//
+// ui->lblRangeSum->setStyleSheet("QLabel {color : green; }");
+ });
+ watcher_calculate->setFuture(future);
+ ui->btnCalculateDCA->setText("calculate...");
+
+
+// calculateDCA();
});
}
@@ -263,26 +326,7 @@ void MainWindow::calculate(dca &res, int max_range) {
}
//set GUI
- ui->lblTotalFirstSum->setText(QString::number(res.assets * res.price));
-
- for (const auto value:res.goal_range) {
- auto range_assets = value.first;
- auto range_price = value.second;
-
- ui->spnRangeAsset->setValue(range_assets);
- ui->spnRangePrice->setValue(range_price);
-
- ui->spnTotalAsset->setValue(range_assets + res.assets);
- ui->lblTotalSum->setText(QString::number(range_price * range_assets + res.assets * res.price));
-
- ui->spnGoalPrice->setStyleSheet("QDoubleSpinBox {color : red;}");
-
- ui->spnRangeAsset->setStyleSheet("QDoubleSpinBox {color : green; }");
- ui->spnRangePrice->setStyleSheet("QDoubleSpinBox {color : green; }");
-
- ui->lblRangeSum->setText(QString::number(range_assets * range_price));
- ui->lblRangeSum->setStyleSheet("QLabel {color : green; }");
- }
+ setGuiCalculateDca(res);
// emit calcDone();
}
@@ -434,12 +478,12 @@ void MainWindow::getDiffPercentDetails() {
}
std::unique_ptr graph = std::make_unique();
- graph->setType(Graph::TypeChart::BarChart);
+ graph->setType(Graph::TypeChart::LineChart);
graph->setTitleGraph("Diff Percentage", "Month", "Depo");
- graph->buildBarChart(data_convert);
+// graph->buildBarChart(data_convert);
// graph->buildBarChartDiffDepo(data_convert);
-// graph->buildLineChart(data_convert1);
+ graph->buildLineChart(data_convert1);
//View csv data from file
char delim = ';';
@@ -520,4 +564,26 @@ void MainWindow::setBackgroundMainWindow() {
}
+void MainWindow::setGuiCalculateDca(dca &res) {
+
+ ui->lblTotalFirstSum->setText(QString::number(res.assets * res.price));
+
+ for (const auto value:res.goal_range) {
+ auto range_assets = value.first;
+ auto range_price = value.second;
+
+ ui->spnRangeAsset->setValue(range_assets);
+ ui->spnRangePrice->setValue(range_price);
+ ui->spnTotalAsset->setValue(range_assets + res.assets);
+ ui->lblTotalSum->setText(QString::number(range_price * range_assets + res.assets * res.price));
+//
+// ui->spnGoalPrice->setStyleSheet("QDoubleSpinBox {color : red;}");
+//
+// ui->spnRangeAsset->setStyleSheet("QDoubleSpinBox {color : green; }");
+// ui->spnRangePrice->setStyleSheet("QDoubleSpinBox {color : green; }");
+//
+ ui->lblRangeSum->setText(QString::number(range_assets * range_price));
+// ui->lblRangeSum->setStyleSheet("QLabel {color : green; }");
+ }
+}
diff --git a/common/mainwindow.h b/common/mainwindow.h
index 01d208e..6ee2b6c 100644
--- a/common/mainwindow.h
+++ b/common/mainwindow.h
@@ -10,6 +10,10 @@
#include "chart.h"
#include "csvreader.h"
#include "csvmodel.h"
+#include "futurescalculator.h"
+#include "investmentcalculator.h"
+
+#include "storage.h"
#include
#include
@@ -51,6 +55,7 @@ class MainWindow : public QMainWindow
void calculateDiffPercentage();
void setHotKey();
void setBackgroundMainWindow();
+ void setGuiCalculateDca(dca &res);
private:
bool isMoonTheme { false };
std::map resultDiffPercent;
diff --git a/common/mainwindow.ui b/common/mainwindow.ui
index e6af393..d47a11c 100755
--- a/common/mainwindow.ui
+++ b/common/mainwindow.ui
@@ -6,7 +6,7 @@
0
0
- 560
+ 582
410
@@ -478,6 +478,32 @@
Trade log
+
+
+
+ 390
+ 340
+ 91
+ 31
+
+
+
+ FuturesCalc
+
+
+
+
+
+ 490
+ 300
+ 81
+ 71
+
+
+
+ Invest Calc
+
+
diff --git a/common/tradelog.cpp b/common/tradelog.cpp
index 43e47be..7d59766 100755
--- a/common/tradelog.cpp
+++ b/common/tradelog.cpp
@@ -1 +1,10 @@
#include "tradelog.h"
+
+AnalyzeTradeLogSummary::AnalyzeTradeLogSummary( [[maybe_unused]]TradeLogSummary &log) {
+
+}
+
+void AnalyzeTradeLogSummary::calculate() {
+
+
+}
diff --git a/common/tradelog.h b/common/tradelog.h
index c6903e6..8ca4f58 100755
--- a/common/tradelog.h
+++ b/common/tradelog.h
@@ -3,27 +3,35 @@
#include
#include
+#include
#include
+#pragma pop(1)
+
/**
* @brief файл журнала сделок
+ * @future возможно отдельный модуль
+ * @note for example;
+ * @todo type data exchange;
* @note usage in future struct from future
- * //скорее всего выгрузка из таблицы с id trader [ или id можно внести в общий конфиг]
+ * @note скорее всего выгрузка из таблицы с id trader [ или id можно внести в общий конфиг]
+ * @note in [.csv -> grid]
*/
class TradeLog final {
using string = std::string;
public:
- explicit TradeLog(ushort uid_trader) {};
+ explicit TradeLog([[maybe_unused]] ushort uid_trader) {};
protected:
- struct Config {
- string timestampOpen; //dd-mm-yy
+ struct Record { //order
+ string timestampOpen; //dd-mm-yy [hh::mm::ss]
string timestampClose; //dd-mm-yy
string orderType;
- string typePosition; //[long, short]
+ string typePosition; //[long, short,hold]
string ticker;
- string account_balance;
- string entry_price;
+ string Market; //idmarket
+ double account_balance;
+ double entry_price;
long long amount;
string SL; //stop loss price
string TP; //take profit price;
@@ -31,20 +39,30 @@ class TradeLog final {
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
+ double closed_position_PL; // [profit - loss]
+ double account_change_in_symbol;
+ double account_change_in_percentage;
+ string pattern_usage_enter; // why i entered deal [pattern, formation , news ]
+ string pattern_usage_exit; // why i exit deal [line breakout month, by stop etc.]
+ string status; //for show status order [ win, loss, neutral]
+ string mistakes; //optional [fomo, overtrade]
};
private:
ushort uid_trader;
};
- //PNL, profit and loss;
- class AnalyzeTradeLogSummary final {
+ /**
+ * @brief PNL, profit and loss;
+ *
+ */
+
+ class AnalyzeTradeLogSummary final {
using string_view = std::string_view;
+ using TradeLogSummary = std::vector;
public:
- explicit AnalyzeTradeLogSummary();
+ explicit AnalyzeTradeLogSummary(TradeLogSummary &log);
+ void calculate();
protected:
ushort total_number_winning_trades;
ushort total_number_losing_trades;
@@ -62,4 +80,7 @@ class TradeLog final {
// usage on Month analysis, on Summary All;
};
+
+#pragma push(pop)
+
#endif //SSM_TRADELOG_H
diff --git a/lib/common/CMakeLists.txt b/lib/common/CMakeLists.txt
index 31c6c12..3488f5c 100644
--- a/lib/common/CMakeLists.txt
+++ b/lib/common/CMakeLists.txt
@@ -5,12 +5,29 @@ 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 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+set(CMAKE_CXX_FLAGS -pthread)
+
+cmake_policy(SET CMP0071 NEW)
+
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-function")
+endif()
+
+
+#optimization flags
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g")
+elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -DNDEBUG")
+endif()
+
add_compile_options(-Wall -Wextra -Wno-unused-function)
-add_library(${PROJECT_NAME} SHARED dca.cpp grid.h logger.h future.h)
+add_library(${PROJECT_NAME} SHARED dca.cpp grid.h logger.h future.h futurescalculator.cpp investmentcalculator.h storage.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 6e5d325..421642c 100644
--- a/lib/common/dca.cpp
+++ b/lib/common/dca.cpp
@@ -32,7 +32,7 @@ void DiffPercent::convertPercentage()
{
if(isBoundRange(i * 100 , (i + 1) *100 , (int)m_percent))
{
- Coeff = 1 + m_percent /100;
+ Coeff = 1 + m_percent / 100;
}
}
};
@@ -41,13 +41,13 @@ void DiffPercent::convertPercentage()
if(isBoundRange(0, 99, static_cast(m_percent)))
- m_percent = 1 + m_percent/100;
+ m_percent = 1 + m_percent / 100;
if(m_percent == 100)
- m_percent = 2;
+ m_percent = 2;
if(Coeff != 0 )
- m_percent= Coeff;
+ m_percent= Coeff;
-// assert(m_percent >100 && "Error!Percent can't larger 100");
+// assert(percent >100 && "Error!Percent can't larger 100");
}
diff --git a/lib/common/dca.h b/lib/common/dca.h
index 61b3692..03e8ec8 100644
--- a/lib/common/dca.h
+++ b/lib/common/dca.h
@@ -47,9 +47,9 @@ namespace Strategy {
//namespace container{}
struct dca {
- double assets{0};
+ double assets{0}; //
double price{0};
- double goal_price{0};
+ double goal_price{0}; //target
std::map goal_range;
dca() = default;
@@ -64,15 +64,14 @@ namespace Strategy {
* @note calculate for month
*/
struct DiffPercent {
- DiffPercent(double depo, double percent, double counterMonth, double refill = 0.00L);
double deposit;
double m_percent;
double step;
double m_refill; // add advanced asset
+ DiffPercent(double depo, double percent, double counterMonth, double refill = 0.00L);
void convertPercentage();
-
void clear();
};
@@ -80,7 +79,7 @@ namespace Strategy {
double static calculateDiffPercent(DiffPercent &dps) {
dps.convertPercentage();
double result = dps.deposit * pow(dps.m_percent, dps.step - 1);
-// double resultDCA = dps.deposit * pow(1 + dps.m_percent / dps.step, dps.step);
+// double resultDCA = dps.deposit * pow(1 + dps.percent / dps.step, dps.step);
return result;
}
@@ -89,7 +88,7 @@ namespace Strategy {
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);
+// double refill = dps.refill * pow(dps.percent, dps.step - 1);
// std::cout<<"Refill calc: " << refill <<"\n";
// return (double)(resultDCA + refill);
@@ -99,6 +98,10 @@ namespace Strategy {
std::map static
calculateDiffPercentPeriod(const double depo, const double percentage, const int period) {
+ if (period <= 0) {
+ std::map empty_map;
+ return empty_map;
+ }
std::map resultDiffPercent;
@@ -129,6 +132,13 @@ namespace Strategy {
return resultDiffPercent;
}
+ /**
+ *
+ * @param dca res
+ * @param min_range
+ * @param max_range
+ * @note calculate only exactly result by range [slowly]
+ */
void static calculateDCA(dca &res, int min_range = 0, int max_range = 0) {
auto first_total_sum = res.assets * res.price;
diff --git a/lib/common/future.h b/lib/common/future.h
index f2e3dc6..716e577 100644
--- a/lib/common/future.h
+++ b/lib/common/future.h
@@ -43,10 +43,10 @@
// 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)
+ float sma(std::vector &price_closing, int period = 0) {
+ if (static_cast(period) > price_closing.size() || period < 0)
return 0L;
- if (period != price_closing.size() && period != 0)
+ if (static_cast(period) != price_closing.size() && period != 0)
price_closing.resize(period);
return (float) std::accumulate(price_closing.begin(), price_closing.end(), 0) / price_closing.size();
}
diff --git a/lib/common/futurescalculator.cpp b/lib/common/futurescalculator.cpp
new file mode 100644
index 0000000..fb4752e
--- /dev/null
+++ b/lib/common/futurescalculator.cpp
@@ -0,0 +1,161 @@
+#include "futurescalculator.h"
+
+
+
+FuturesCalculator::FuturesCalculator() noexcept {
+ m_instrumentDb = {
+ {"SBERF", InstrumentParams(100, 0.01, 1.0)}, // Фьючерс на Сбербанк
+ {"GAZPF", InstrumentParams(100, 0.01, 1.0)}, // Фьючерс на Газпром
+ {"BRF4", InstrumentParams(10, 0.1, 10.0)}, // Фьючерс на нефть Brent
+ {"RTSF", InstrumentParams(1, 10, 1.0)}, // Фьючерс на индекс РТС
+ {"SIH4", InstrumentParams(1000, 0.01, 1.0)}, // Фьючерс на серебро
+ {"USDRUBF", InstrumentParams(1000, 0.01, 10)},// Фьючерс на доллар однодневный
+ {"USDRUBFK", InstrumentParams(1000, 1, 1)}, // Фьючерс на доллар квартальный
+ {"MTLRFK", InstrumentParams(100, 1, 1)}, // Фьючерс на мечел квартальный
+ {"SBRFK", InstrumentParams(100, 1, 1)} // Фьючерс на сбербанк квартальный
+ };
+}
+
+FuturesCalculator::InstrumentParams FuturesCalculator::getInstrumentParams(const std::string& ticker)
+{
+
+ auto it = m_instrumentDb.find(ticker);
+ if (it != m_instrumentDb.end()) {
+ printInstrumentParams(ticker);
+ return it->second;
+ }
+
+ cout << "Tool not found. Please enter parameters manually:\n";
+ int lot_size;
+ double price_step, step_value;
+
+ cout << "Size of lots: ";
+ cin >> lot_size;
+ cout << "Price step: ";
+ cin >> price_step;
+ cout << "Cost of price step: ";
+ cin >> step_value;
+
+ return InstrumentParams(lot_size, price_step, step_value);
+}
+
+
+
+double FuturesCalculator::calculatePnl(const Trade& trade) const {
+ const double price_diff = trade.is_long
+ ? trade.close_price - trade.open_price
+ : trade.open_price - trade.close_price;
+
+ const double steps = price_diff / trade.params.price_step;
+ const double gross_profit = steps * trade.params.step_value * trade.quantity;
+ const double total_fees = (trade.exchange_fee + trade.broker_fee) * 2 * trade.quantity;
+
+ return gross_profit - total_fees;
+}
+
+FuturesCalculator::Trade FuturesCalculator::inputTradeData() {
+ std::string ticker;
+ cout << "\nВведите тикер фьючерса (например, SBERF): ";
+ cin >> ticker;
+
+ InstrumentParams params = getInstrumentParams(ticker);
+
+ char direction;
+ cout << "Тип позиции (L - лонг, S - шорт): ";
+ cin >> direction;
+
+ double open_price, close_price;
+ cout << "Цена открытия: ";
+ cin >> open_price;
+ cout << "Цена закрытия: ";
+ cin >> close_price;
+
+ int quantity;
+ cout << "Количество контрактов: ";
+ cin >> quantity;
+
+ double exchange_fee, broker_fee;
+ cout << "Комиссия биржи за контракт: ";
+ cin >> exchange_fee;
+ cout << "Комиссия брокера за контракт: ";
+ cin >> broker_fee;
+
+ return Trade(ticker, toupper(direction) == 'L', open_price, close_price,
+ quantity, exchange_fee, broker_fee, params);
+}
+
+
+
+void FuturesCalculator::printInstrumentParams(const std::string& ticker) const {
+
+ const auto& params = m_instrumentDb.at(ticker);
+ cout << "Tool parameters:\n";
+ cout << " - Size of lots: " << params.lot_size << "\n";
+ cout << " - Step of price: " << params.price_step << "\n";
+ cout << " - Cost per step: " << params.step_value << " ₽\n";
+}
+
+
+void FuturesCalculator::printTradeReport(const Trade& trade) const {
+
+
+ const double profit = calculatePnl(trade);
+
+ cout << "\n=== Transaction Report ===\n";
+ cout << "Тикер: " << trade.ticker << "\n";
+ cout << "Позиция: " << (trade.is_long ? "Лонг" : "Шорт") << "\n";
+ cout << "Количество контрактов: " << trade.quantity << "\n";
+ cout << std::fixed << std::setprecision(2);
+ cout << "Цена открытия: " << trade.open_price << " ₽\n";
+ cout << "Цена закрытия: " << trade.close_price << " ₽\n";
+ cout << "Размер лота: " << trade.params.lot_size << "\n";
+ cout << "Шаг цены: " << trade.params.price_step << "\n";
+ cout << "Стоимость шага: " << trade.params.step_value << " ₽\n";
+ cout << "Комиссия биржи: " << trade.exchange_fee << " ₽ за контракт\n";
+ cout << "Комиссия брокера: " << trade.broker_fee << " ₽ за контракт\n";
+ cout << "-------------------------\n";
+ cout << "Результат: " << (profit >= 0 ? "Прибыль" : "Убыток")
+ << ": " << std::abs(profit) << " ₽\n";
+ cout << "=========================\n\n";
+}
+
+void FuturesCalculator::printSummaryReport() const {
+ double total_profit = 0.0;
+ cout << "\n=== Final report ===\n";
+
+ for (const auto& trade : m_trades) {
+ const double profit = calculatePnl(trade);
+ total_profit += profit;
+ cout << trade.ticker << ": " << (profit >= 0 ? "+" : "")
+ << profit << " ₽\n";
+ }
+
+ cout << "-----------------------\n";
+ cout << "Common result: " << (total_profit >= 0 ? "+" : "")
+ << total_profit << " ₽\n";
+}
+
+void FuturesCalculator::run() {
+ cout << " \nCalculate pnl by futures\n";
+ cout << "----------------------------------------\n";
+
+ while (true) {
+ Trade trade = inputTradeData();
+ m_trades.push_back(trade);
+ printTradeReport(trade);
+
+ if (!askToContinue()) break;
+ }
+
+ printSummaryReport();
+}
+
+
+bool FuturesCalculator::askToContinue() const {
+ char choice;
+ cout << "Add another deal? (Y/N): ";
+ cin >> choice;
+ return toupper(choice) == 'Y';
+}
+
+
diff --git a/lib/common/futurescalculator.h b/lib/common/futurescalculator.h
new file mode 100644
index 0000000..9a60b7f
--- /dev/null
+++ b/lib/common/futurescalculator.h
@@ -0,0 +1,60 @@
+#ifndef SSM_FUTURESCALCULATOR_H
+#define SSM_FUTURESCALCULATOR_H
+
+#include
+#include
+#include