286 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			MQL5
		
	
	
	
	
	
			
		
		
	
	
			286 lines
		
	
	
	
		
			13 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);
 | 
						|
}
 | 
						|
//+------------------------------------------------------------------+
 |