286 lines
22 KiB
MQL5
286 lines
22 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| VirtualCloseManager.mqh |
|
|
//| Copyright 2022-2025, Yuriy Bykov |
|
|
//| https://www.mql5.com/ru/users/antekov |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2022-2025, Yuriy Bykov"
|
|
#property link "https://www.mql5.com/ru/users/antekov"
|
|
#property version "1.00"
|
|
|
|
class CVirtualAdvisor;
|
|
|
|
#include "../Database/Storage.mqh"
|
|
|
|
// Возможные состояния менеджера закрытия
|
|
enum ENUM_CM_STATE {
|
|
CM_STATE_OK, // Лимиты не превышены (нормальное состояние)
|
|
CM_STATE_LOSS, // Превышен общий убыток
|
|
CM_STATE_PROFIT, // Достигнута общая прибыль
|
|
CM_STATE_TRAIL_PROFIT // Трейлинг прибыли
|
|
};
|
|
|
|
// Возможные способы расчёта общего убытка
|
|
enum ENUM_CM_CALC_LOSS {
|
|
CM_CALC_LOSS_MONEY_BB, // [$] Fixed Money
|
|
CM_CALC_LOSS_PERCENT_BB, // [%] of Base Balance
|
|
};
|
|
|
|
// Возможные способы расчёта общей прибыли
|
|
enum ENUM_CM_CALC_PROFIT {
|
|
CM_CALC_PROFIT_MONEY_BB, // [$] Fixed Money
|
|
CM_CALC_PROFIT_PERCENT_BB, // [%] of Base Balance
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Класс менеджера закрытия (фиксации прибыли и убытков) |
|
|
//+------------------------------------------------------------------+
|
|
class CVirtualCloseManager : public CFactorable {
|
|
protected:
|
|
// Основные параметры конструктора
|
|
double m_baseBalance; // Базовый баланс
|
|
|
|
ENUM_CM_CALC_LOSS m_calcLossLimit; // Способ расчёта максимального общего убытка
|
|
double m_maxLossLimit; // Параметр расчёта максимального общего убытка
|
|
|
|
ENUM_CM_CALC_PROFIT m_calcProfitLimit; // Способ расчёта максимальной общей прибыли
|
|
double m_maxProfitLimit; // Параметр расчёта максимальной общей прибыли
|
|
|
|
CVirtualAdvisor* m_expert; // Указатель на объект эксперта
|
|
|
|
// Текущее состояние
|
|
ENUM_CM_STATE m_state; // Состояние
|
|
|
|
// Обновляемые значения
|
|
double m_balance; // Текущий баланс
|
|
double m_equity; // Текущие средства
|
|
double m_profit; // Текущая плавающая прибыль
|
|
double m_overallProfit; // Текущая общая прибыль относительно базового баланса
|
|
|
|
|
|
// Защищённые методы
|
|
double LossMoney(); // Максимальный общий убыток
|
|
double ProfitMoney(); // Максимальная прибыль
|
|
|
|
void UpdateProfit(); // Обновление текущих значений прибыли
|
|
void CheckLimits(); // Проверка достижения допустимых уровней прибыли/убытка
|
|
|
|
CVirtualCloseManager(string p_params); // Закрытый конструктор
|
|
|
|
public:
|
|
STATIC_CONSTRUCTOR(CVirtualCloseManager); // Статический метод создания объекта
|
|
virtual void Tick(); // Обработка тика в менеджере закрытия
|
|
|
|
virtual string Text(); // Информация о текущем состоянии
|
|
|
|
// Привязка эксперта к менеджеру закрытия
|
|
void Expert(CVirtualAdvisor* p_expert);
|
|
|
|
virtual bool Save(); // Сохранение состояния
|
|
virtual bool Load(); // Загрузка состояния
|
|
|
|
virtual string operator~() override; // Преобразование объекта в строку
|
|
};
|
|
|
|
REGISTER_FACTORABLE_CLASS(CVirtualCloseManager); // Регистрация нового потомка CFactorable
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Конструктор |
|
|
//+------------------------------------------------------------------+
|
|
CVirtualCloseManager::CVirtualCloseManager(string p_params) {
|
|
// Запоминаем строку инициализации
|
|
m_params = p_params;
|
|
|
|
// Читаем строку инициализации и устанавливаем значения свойств
|
|
m_isActive = (bool) ReadLong(p_params);
|
|
m_baseBalance = ReadDouble(p_params);
|
|
m_calcLossLimit = (ENUM_CM_CALC_LOSS) ReadLong(p_params);
|
|
m_maxLossLimit = ReadDouble(p_params);
|
|
m_calcProfitLimit = (ENUM_CM_CALC_PROFIT) ReadLong(p_params);
|
|
m_maxProfitLimit = ReadDouble(p_params);
|
|
|
|
|
|
// Устанавливаем состояние: Лимиты не превышены
|
|
m_state = CM_STATE_OK;
|
|
|
|
// Обновляем текущие значения прибыли
|
|
UpdateProfit();
|
|
|
|
// Корректируем базовый баланс, если он не задан
|
|
if(m_baseBalance == 0) {
|
|
m_baseBalance = m_balance;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Обработка тика в риск-менеджере |
|
|
//+------------------------------------------------------------------+
|
|
void CVirtualCloseManager::Tick() {
|
|
// Если риск-менеджер неактивен, то выходим
|
|
if(!m_isActive) {
|
|
return;
|
|
}
|
|
|
|
// Обновляем текущие значения прибыли
|
|
UpdateProfit();
|
|
|
|
// Если менеджер в состоянии трейлинга, то
|
|
if(m_state == CM_STATE_TRAIL_PROFIT) {
|
|
// Пока просто будем сразу фиксировать прибыль,
|
|
// переводя менеджер в соответсвующее состояние
|
|
if(true) {
|
|
m_state = CM_STATE_PROFIT;
|
|
}
|
|
}
|
|
|
|
// Если менеджер в нормальном состоянии, то
|
|
if(m_state == CM_STATE_OK) {
|
|
// Проверяем превышение пределов убытка и прибыли
|
|
CheckLimits();
|
|
}
|
|
|
|
// Если менеджер в состоянии достигнутого убытка или прибыли, то
|
|
if(m_state == CM_STATE_LOSS || m_state == CM_STATE_PROFIT) {
|
|
// Закрываем все позиции
|
|
m_expert.Close();
|
|
|
|
// Если все позиции закрыты, то
|
|
if(PositionsTotal() == 0) {
|
|
// Переходим в нормальное состояние
|
|
m_state = CM_STATE_OK;
|
|
|
|
// Обновляем значение базового баланса
|
|
m_baseBalance = m_balance;
|
|
} else {
|
|
// Ждём закрытия всех позиций
|
|
}
|
|
|
|
// Сохраняем состояние эксперта
|
|
m_expert.Save();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Информация о текущем состоянии |
|
|
//+------------------------------------------------------------------+
|
|
string CVirtualCloseManager::Text() {
|
|
string s = "=== Close Manager ===\n";
|
|
|
|
s += StringFormat("BL: %8.2f | Target: %8.2f (%8.2f)\n",
|
|
m_baseBalance,
|
|
m_baseBalance + ProfitMoney(),
|
|
m_baseBalance - LossMoney());
|
|
|
|
return s;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Привязка эксперта к менеджеру закрытия |
|
|
//+------------------------------------------------------------------+
|
|
void CVirtualCloseManager::Expert(CVirtualAdvisor* p_expert) {
|
|
m_expert = p_expert;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Сохранение состояния |
|
|
//+------------------------------------------------------------------+
|
|
bool CVirtualCloseManager::Save() {
|
|
CStorage::Set("CVirtualCloseManager::m_state", m_state);
|
|
CStorage::Set("CVirtualCloseManager::m_baseBalance", m_baseBalance);
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Загрузка состояния |
|
|
//+------------------------------------------------------------------+
|
|
bool CVirtualCloseManager::Load() {
|
|
bool res = true;
|
|
|
|
res &= CStorage::Get("CVirtualCloseManager::m_state", m_state);
|
|
res &= CStorage::Get("CVirtualCloseManager::m_baseBalance", m_baseBalance);
|
|
|
|
return res;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Максимальный общий убыток |
|
|
//+------------------------------------------------------------------+
|
|
double CVirtualCloseManager::LossMoney() {
|
|
if(m_calcLossLimit == CM_CALC_LOSS_PERCENT_BB) {
|
|
// Для заданного процента от базового баланса вычисляем его
|
|
return m_baseBalance * m_maxLossLimit / 100;
|
|
} else {
|
|
// Для фиксированного значения просто возвращаем его
|
|
// CM_CALC_LOSS_MONEY_BB
|
|
return m_maxLossLimit;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Максимальная общая прибыль |
|
|
//+------------------------------------------------------------------+
|
|
double CVirtualCloseManager::ProfitMoney() {
|
|
if(m_calcProfitLimit == CM_CALC_PROFIT_PERCENT_BB) {
|
|
// Для заданного процента от базового баланса вычисляем его
|
|
return m_baseBalance * m_maxProfitLimit / 100;
|
|
} else {
|
|
// Для фиксированного значения просто возвращаем его
|
|
// CM_CALC_PROFIT_MONEY_BB
|
|
return m_maxProfitLimit;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Обновление текущих значений прибыли |
|
|
//+------------------------------------------------------------------+
|
|
void CVirtualCloseManager::UpdateProfit() {
|
|
// Текущие средства
|
|
m_equity = AccountInfoDouble(ACCOUNT_EQUITY);
|
|
|
|
// Текущий баланс
|
|
m_balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
|
|
// Текущая плавающая прибыль
|
|
m_profit = m_equity - m_balance;
|
|
|
|
// Текущая общая прибыль относительно базового баланса
|
|
m_overallProfit = m_equity - m_baseBalance;
|
|
|
|
// Раз в час выводим значения в лог
|
|
if(IsNewBar(Symbol(), PERIOD_H1)) {
|
|
PrintFormat(__FUNCTION__" | Profit = %.2f | Overall = %.2f",
|
|
m_profit, m_overallProfit);
|
|
}
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Проверка лимитов убытка |
|
|
//+------------------------------------------------------------------+
|
|
void CVirtualCloseManager::CheckLimits() {
|
|
// Если достигнут общий убыток
|
|
if(m_overallProfit <= -LossMoney()) {
|
|
// Устанавливаем риск-менеджер в состояние достигнутого общего убытка
|
|
m_state = CM_STATE_LOSS;
|
|
|
|
PrintFormat(__FUNCTION__" | CLOSE LOSS Profit = %.2f | OverallProfit = %.2f (%.2f)",
|
|
m_profit, m_overallProfit, -LossMoney());
|
|
|
|
}
|
|
// Если достигнут общий убыток и позиции ещё открыты
|
|
else if(m_overallProfit >= ProfitMoney()) {
|
|
// Устанавливаем риск-менеджер в состояние достигнутой общей прибыли
|
|
m_state = CM_STATE_PROFIT;
|
|
|
|
PrintFormat(__FUNCTION__" | CLOSE PROFIT Profit = %.2f | OverallProfit = %.2f (%.2f)",
|
|
m_profit, m_overallProfit, ProfitMoney());
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Преобразование объекта в строку |
|
|
//+------------------------------------------------------------------+
|
|
string CVirtualCloseManager::operator~() {
|
|
return StringFormat("%s(%s)", typename(this), m_params);
|
|
}
|
|
//+------------------------------------------------------------------+
|