English
preview
Менеджер жизненного цикла позиций на MQL5 (Часть 1): Основы повторно используемой системы управления позициями

Менеджер жизненного цикла позиций на MQL5 (Часть 1): Основы повторно используемой системы управления позициями

MetaTrader 5 — Торговые системы |
23 0
Francis Nyoike Thumbi
Francis Nyoike Thumbi

Введение

Открытие сделки — это лишь начало её жизненного цикла. После открытия позиции необходимо продолжать отслеживать её и управлять ею вплоть до закрытия. Хотя MetaTrader 5 предоставляет функции, необходимые для открытия, изменения и закрытия позиций, в ней нет повторно используемого фреймворка для управления позицией после её открытия. В результате каждый советник должен реализовывать собственную логику управления сделками.

Это часто приводит к тому, что один и тот же код управления приходится переписывать в разных проектах. Хотя торговые стратегии могут использовать разные условия входа в рынок, логика отслеживания открытых позиций, применения правил управления и реагирования на изменения на протяжении жизненного цикла сделки зачастую очень схожа.

В этой статье мы представляем менеджер жизненного цикла позиций, который отделяет управление позициями от открытия сделок. Мы создаём специализированный фреймворк, который обнаруживает открытые позиции, отслеживает их жизненный цикл, выполняет действия по управлению ими и исключает закрытые позиции из активного отслеживания. Благодаря этому логика управления отделена от торговой стратегии.

Чтобы продемонстрировать работу фреймворка, мы интегрируем его с советником MACD из Стандартной библиотеки MQL5. Стратегия остается прежней; после открытия позиций ими занимается менеджер жизненного цикла позиций. Это позволяет проводить независимую оценку данного фреймворка, а впоследствии интегрировать его в другие советники с минимальными изменениями.

Каждая отслеживаемая позиция представлена собственным управляемым объектом. Вместо многократных запросов к терминалу за информацией о позиции фреймворк хранит дополнительные данные о состоянии сделки на протяжении всего её жизненного цикла. Это позволяет при принятии решений по управлению учитывать как текущее состояние позиции, так и уже выполненные действия.

Фреймворк построен на четырёх основных принципах:

  • Управление на основе состояний: позиции проходят четко определенные этапы жизненного цикла.
  • Разделение обязанностей: торговые стратегии по-прежнему отвечают за открытие сделок, а менеджер жизненного цикла позиций управляет ими после входа в рынок.
  • Объектно-ориентированное проектирование: каждая отслеживаемая позиция представлена независимым объектом, который хранит собственное состояние и данные для управления.
  • Архитектура для повторного использования: фреймворк спроектирован так, чтобы его можно было интегрировать с различными торговыми стратегиями без изменения его внутренней реализации.

В этой первой части мы заложим основы архитектуры менеджера жизненного цикла позиций. Мы реализуем обнаружение позиций, отслеживание жизненного цикла, переходы между состояниями и очистку после закрытия позиции. Правила управления, представленные в данной статье, служат основой для более сложных возможностей, которые будут разработаны в последующих частях серии.


Архитектура менеджера жизненного цикла позиций

Управление позицией — это нечто большее, чем просто отслеживание открытой сделки. Фреймворк хранит данные о жизненном цикле, координирует принятие решений и определяет момент завершения отслеживания. В традиционных советниках открытие сделок и управление позициями часто объединены в одной кодовой базе, что затрудняет повторное использование логики управления в различных стратегиях.

Менеджер жизненного цикла позиций вводит отдельный уровень управления, работающий независимо от торговой стратегии. Советник по-прежнему отвечает за открытие сделок, а менеджер автоматически обнаруживает вновь открытые позиции, создает объекты управляемых позиций для их представления и начинает отслеживать их жизненный цикл.

Фреймворк построен по многоуровневой архитектуре, в которой у каждого компонента четко определены функции:

  • Советник — анализирует рынок и открывает сделки.
  • Менеджер позиций — координирует все активные управляемые позиции.
  • Управляемая позиция — представляет отдельную сделку и хранит состояние ее жизненного цикла.
  • Модуль расчета рисков — выполняет вспомогательные расчеты, необходимые для процесса управления.

Рис. 1. Архитектура менеджера жизненного цикла позиций

Рис. 1. Архитектура менеджера жизненного цикла позиций

Данная архитектура отделяет открытие сделок от управления позициями. Торговая стратегия определяет, когда открываются сделки, а менеджер жизненного цикла позиций отслеживает существующие позиции, выполняет действия в рамках их жизненного цикла и исключает завершенные сделки из активного отслеживания. Поскольку эти функции являются независимыми, один и тот же менеджер жизненного цикла позиций может быть интегрирован с различными торговыми стратегиями без изменения его внутренней реализации.


Определение состояний жизненного цикла позиции

Чтобы управлять позицией, фреймворку необходимо четкое представление этапов, на которых сделка может находиться в течение своего жизненного цикла. Позиция в MetaTrader 5 содержит такие торговые данные, как торговый инструмент, объем, цена входа, стоп-лосс и текущая прибыль. Однако в ней не хранится дополнительная история операций по управлению. Платформа не может определить, была ли для позиции уже установлена защита, выполнен ли перевод в безубыток и требуется ли очистка после закрытия позиции.

Без модели внутреннего состояния менеджеру пришлось бы заново оценивать каждую позицию с самого начала в ходе каждого цикла выполнения. Состояния жизненного цикла позволяют решить эту проблему за счет фиксации текущего этапа каждой управляемой позиции.

//+------------------------------------------------------------------+
//| Enumeration of position lifecycle states                         |
//+------------------------------------------------------------------+
enum ENUM_POSITION_LIFECYCLE_STATE
  {
   POSITION_NEW,
   POSITION_PROTECTED,
   POSITION_BREAKEVEN,
   POSITION_CLOSED
  };

В начальной версии фреймворка определены четыре этапа жизненного цикла.

POSITION_NEW

Обозначает недавно обнаруженную позицию, зарегистрированную менеджером, для которой еще не завершено ни одно действие по управлению. На данном этапе фреймворк создает объект управляемой позиции, сохраняет его исходные данные и подготавливает его к дальнейшей обработке.

POSITION_PROTECTED

Указывает, что для позиции завершен начальный этап установки защиты. Это состояние лишь фиксирует факт перехода; логика, отвечающая за расчет уровней защиты, остается отдельной.

POSITION_BREAKEVEN

Указывает на то, что перевод в безубыток уже выполнен. Фиксация этого состояния предотвращает повторное выполнение одного и того же действия по управлению и позволяет каждой позиции независимо проходить этапы жизненного цикла.

POSITION_CLOSED

Обозначает позицию, которая больше не существует в торговой среде. Как только достигается это состояние, менеджер выполняет очистку и удаляет позицию из списка активного отслеживания. Модель жизненного цикла превращает управление позициями из набора повторяющихся проверок условий в контролируемый процесс управления на основе состояний. Каждая управляемая позиция хранит сведения о своём текущем этапе и выполненных действиях.

После определения модели жизненного цикла следующим шагом становится создание объекта, отвечающего за представление отдельной управляемой позиции.

Объект управляемой позиции: CManagedPosition

Позиция в MetaTrader 5 содержит информацию, необходимую для проведения торговых операций, но не хранит данные времени выполнения, необходимые системе управления позициями. Чтобы устранить этот пробел, в менеджере жизненного цикла позиций вводится специальный объект, который представляет каждую отслеживаемую позицию на протяжении всего её жизненного цикла. Вместо того чтобы полагаться исключительно на данные терминала, фреймворк поддерживает внутреннее представление, содержащее информацию, необходимую для управления жизненным циклом.

Класс CManagedPosition содержит:

  • идентификационные данные позиции,
  • первоначальную информацию о сделке,
  • текущее состояние жизненного цикла,
  • данные времени выполнения, связанные с управлением.
//+------------------------------------------------------------------+
//| Class representing a single managed trade position               |
//+------------------------------------------------------------------+
class CManagedPosition : public CObject
  {
private:
   //--- member variables for position tracking and state
   ulong                        m_ticket;
   string                       m_symbol;
   ENUM_POSITION_TYPE           m_position_type;
   double                       m_volume;
   double                       m_entry_price;
   double                       m_current_sl;
   double                       m_initial_risk;
   ENUM_POSITION_LIFECYCLE_STATE m_lifecycle_state;
   CTrade                       m_trade_client;
   CPositionInfo                m_position_info;

public:
   //--- constructor
                     CManagedPosition(void) : m_ticket(0),
                     m_symbol(""),
                     m_position_type(POSITION_TYPE_BUY),
                     m_volume(0.0),
                     m_entry_price(0.0),
                     m_current_sl(0.0),
                     m_initial_risk(0.0),
                     m_lifecycle_state(POSITION_NEW)
     {
     }

   //--- destructor
                    ~CManagedPosition(void)
     {
     }

Благодаря инкапсуляции данных о позициях в отдельных объектах каждая сделка может обрабатываться независимо, в то время как менеджер координирует общий поток выполнения.

Таким образом, распределение ответственности выглядит следующим образом:

  • CPositionManager — управляет набором активных позиций и координирует их обработку.
  • CManagedPosition — хранит данные и состояние, связанные с одной позицией.


Управление идентификационными данными позиции и её инициализация

После создания объекта управляемой позиции фреймворк должен установить связь между внутренним представлением и соответствующей позицией в MetaTrader 5. Процесс инициализации осуществляется с помощью функции Init(). Цель инициализации — считать данные существующей в терминале позиции и заполнить управляемый объект информацией, необходимой для управления ее жизненным циклом.

   //--- initialize managed position properties from an open terminal position
   void              Init(const ulong ticket, const ulong magic_number)
     {
      m_ticket = ticket;
      m_trade_client.SetExpertMagicNumber(magic_number);

      //--- select position by ticket to read its properties
      if(m_position_info.SelectByTicket(m_ticket))
        {
         m_symbol = m_position_info.Symbol();
         m_position_type = m_position_info.PositionType();
         m_volume = m_position_info.Volume();
         m_entry_price = m_position_info.PriceOpen();
         m_current_sl = m_position_info.StopLoss();
         m_lifecycle_state = POSITION_NEW;

         if(InpEnableLogging)
            Print("Position detected, ticket: ", m_ticket);
        }
     }

В процессе инициализации выполняются три основные операции.

1. Сохранить идентификационные данные позиции

Тикет позиции служит уникальным идентификатором, связывающим управляемый объект с соответствующей позицией в MetaTrader 5. Это позволяет менеджеру правильно идентифицировать и обновлять каждую отслеживаемую позицию.

2. Собрать исходную информацию о сделке

Объект хранит начальные свойства позиции, в том числе:

  • торговый инструмент,
  • тип позиции,
  • объём,
  • цена входа,
  • текущий стоп-лосс.

Эти значения служат исходными данными для последующих решений по управлению позицией.

3. Установить начальное состояние жизненного цикла

После инициализации позиция находится в начальном состоянии POSITION_NEW. На данном этапе позиция обнаружена и зарегистрирована, но ни одного перехода между состояниями жизненного цикла еще не выполнено.

Теперь объект готов к обработке менеджером позиций.


Менеджер позиций: координация управляемых позиций

Хотя CManagedPosition представляет отдельную сделку, системе требуется центральный компонент, отвечающий за координацию нескольких управляемых объектов. CPositionManager обеспечивает взаимодействие между средой MetaTrader 5 и объектами управляемых позиций. В его обязанности входят:

  • обнаружение новых позиций,
  • создание объектов управляемых позиций,
  • обновление открытых позиций,
  • прекращение отслеживания объектов закрытых позиций.

Менеджер управляет потоком выполнения, но не содержит всех правил управления. Вычисления и отдельные действия по управлению делегируются специализированным компонентам, а CPositionManager обеспечивает правильную обработку каждой отслеживаемой позиции.

//+------------------------------------------------------------------+
//| Main orchestrator class for position lifecycle management        |
//+------------------------------------------------------------------+
class CPositionManager
  {
private:
   //--- member variables for orchestration and engines
   CArrayObj            m_managed_positions;
   CRiskEngine          m_risk_engine;
   bool                 m_is_initialized;

   //--- check if a position ticket is already tracked in the collection
   bool              IsPositionTracked(const ulong ticket)
     {
      for(int i = 0; i < m_managed_positions.Total(); i++)
        {
         CManagedPosition *pos = dynamic_cast<CManagedPosition*>(m_managed_positions.At(i));
         if(pos != NULL && pos.GetTicket() == ticket)
            return true;
        }
      return false;
     }

public:
   //--- constructor
                     CPositionManager(void) : m_is_initialized(false)
     {
     }

   //--- destructor
                    ~CPositionManager(void)
     {
      m_managed_positions.Clear();
     }

Менеджер поддерживает ресурсы, необходимые для координации открытых позиций:

CArrayObj      m_managed_positions;
CRiskEngine    m_risk_engine;

m_managed_positions хранит набор объектов управляемых позиций, которые в данный момент контролируются фреймворком, а m_risk_engine обеспечивает вспомогательные вычисления, необходимые при обработке позиций.

Разделение обязанностей позволяет менеджеру сосредоточиться на координации, а не на непосредственной реализации каждой операции по управлению позициями.

Таким образом, архитектуру можно описать следующим образом:

  • CPositionManager — координирует объекты управляемых позиций.
  • CManagedPosition — представляет отдельную сделку.
  • Вспомогательные компоненты — обеспечивают специализированные функции при необходимости.

Теперь, когда компонент-координатор определен, следующий шаг — разобраться, как позиции обнаруживаются и подключаются к системе управления.


Автоматическое обнаружение позиций

Менеджер позиций не может обработать сделку, пока не зарегистрирует соответствующую позицию во внутренней структуре данных. MetaTrader 5 предоставляет доступ к открытым позициям через торговую среду, однако эти позиции сначала необходимо связать с объектами, поддерживаемыми менеджером жизненного цикла позиций.

Во время выполнения менеджер автоматически обнаруживает позиции:

  • Считывает доступные позиции из MetaTrader 5.
  • Проверяет для каждой позиции, отслеживается ли она уже.
  • Создаёт и инициализирует новый объект CManagedPosition при необходимости.
  • Добавляет объект в коллекцию активно управляемых позиций.
//--- automatically discover and register new positions
if(InpAutoDetectPositions)
  {
   int total_positions = PositionsTotal();

   for(int i = total_positions - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);

      if(ticket <= 0)
         continue;

      //--- process only positions belonging to this EA
      if(PositionGetString(POSITION_SYMBOL) != Symbol() ||
         PositionGetInteger(POSITION_MAGIC) != InpMagicNumber)
         continue;

      //--- register newly discovered positions
      if(!IsPositionTracked(ticket))
        {
         CManagedPosition *new_pos = new CManagedPosition();

         if(new_pos != NULL)
           {
            new_pos.Init(ticket, InpMagicNumber);
            m_managed_positions.Add(new_pos);
           }
        }
     }
  }

В процессе обнаружения в качестве уникального идентификатора используется тикет позиции. Перед созданием нового управляемого объекта менеджер проверяет, существует ли уже такой тикет:

IsPositionTracked(ticket)

Если позиция не найдена, создается и регистрируется новый управляемый объект. С этого момента позиция становится частью внутренней системы управления и может проходить этапы заданного для нее жизненного цикла.


Применение начальной защиты на основе ATR

Как только позиция обнаружена и зарегистрирована, она переходит на первый этап своего жизненного цикла. Прежде чем позиция перейдет в последующие состояния, фреймворк устанавливает начальный защитный стоп-лосс. Вместо фиксированного расстояния фреймворк использует индикатор «средний истинный диапазон (ATR)» для расчета защиты на основе текущей рыночной волатильности.

Расчет передается модулю CRiskEngine, что позволяет менеджеру жизненного цикла позиций оставаться независимым от модели рисков.

  • CManagedPosition определяет, когда следует применять защиту.
  • CRiskEngine рассчитывает необходимый уровень стоп-лосса.

Такое разделение позволяет внедрять различные методы защиты без изменения логики жизненного цикла.

Расчет начального стоп-лосса

CRiskEngine управляет процессом расчета ATR. Во время инициализации он создает хэндл индикатора ATR и сохраняет параметры, необходимые для последующих расчетов.

   //--- initialize risk parameters and atr indicator
   void              Init(const bool use_atr, const int atr_period, const double atr_multiplier, const string symbol)
     {
      m_use_atr = use_atr;
      m_atr_period = atr_period;
      m_atr_multiplier = atr_multiplier;

      //--- create atr indicator handle if enabled
      if(m_use_atr)
        {
         m_atr_handle = iATR(symbol, PERIOD_CURRENT, m_atr_period);
         if(m_atr_handle == INVALID_HANDLE)
            Print("Error creating ATR indicator in RiskEngine");
        }
     }

При запросе начальной защиты модуль расчета рисков получает последнее значение ATR и рассчитывает необходимое расстояние с использованием заданного множителя. Для позиций на покупку стоп-лосс устанавливается ниже цены входа. В случае позиций на продажу он устанавливается выше цены входа. Перед возвратом полученная цена нормализуется с учетом точности котировок торгового инструмента.

   //--- calculate initial stop loss using atr
   double            CalculateInitialStopLoss(const string symbol, const ENUM_POSITION_TYPE pos_type, const double entry_price)
     {
      //--- return zero if atr protection is disabled or handle is invalid
      if(!m_use_atr || m_atr_handle == INVALID_HANDLE)
         return 0.0;

      double atr_values[];
      ArraySetAsSeries(atr_values, true);

      //--- copy latest atr value
      if(CopyBuffer(m_atr_handle, 0, 0, 1, atr_values) <= 0)
        {
         Print("Error copying ATR buffer values");
         return 0.0;
        }

      double atr_value = atr_values[0];
      double risk_distance = atr_value * m_atr_multiplier;
      double sl = 0.0;

      //--- compute stop loss based on position type
      if(pos_type == POSITION_TYPE_BUY)
        {
         sl = entry_price - risk_distance;
        }
      else
         if(pos_type == POSITION_TYPE_SELL)
           {
            sl = entry_price + risk_distance;
           }

      //--- normalize final calculated stop loss price
      return PositionManagerUtils::NormalizePrice(symbol, sl);
     }
  };

Обратите внимание, что модуль расчета рисков не изменяет позицию напрямую. Его задача ограничивается расчетом допустимой цены стоп-лосса. За применение этого значения к торговой позиции по-прежнему отвечает менеджер жизненного цикла позиций.


Применение защиты при обработке позиций

В ходе каждого цикла обновления объект управляемой позиции проверяет, существует ли еще соответствующая торговая позиция. Если позиция закрыта, её состояние изменяется на POSITION_CLOSED. Для позиций, находящихся в состоянии POSITION_NEW, управляемая позиция запрашивает у CRiskEngine расчёт начального стоп-лосса. Если возвращено допустимое значение и изменение выполнено успешно, стоп-лосс устанавливается, а состояние жизненного цикла меняется на POSITION_PROTECTED.

   //--- update lifecycle state and apply management rules
   void              Update(CRiskEngine &risk_engine, const bool use_atr, const bool use_be, const double be_trigger, const double be_offset)
     {
      //--- check if position still exists in terminal
      if(!m_position_info.SelectByTicket(m_ticket))
        {
         m_lifecycle_state = POSITION_CLOSED;
         return;
        }

      //--- handle state: POSITION_NEW -> Apply initial protection
      if(m_lifecycle_state == POSITION_NEW)
        {
         if(use_atr)
           {
            double initial_sl = risk_engine.CalculateInitialStopLoss(m_symbol, m_position_type, m_entry_price);
            if(initial_sl > 0.0)
              {
               double tp = m_position_info.TakeProfit();
               if(m_trade_client.PositionModify(m_ticket, initial_sl, tp))
                 {
                  m_current_sl = initial_sl;
                  m_lifecycle_state = POSITION_PROTECTED;

                  if(InpEnableLogging)
                     Print("Initial protection applied for ticket: ", m_ticket);
                 }
              }
           }
         else
           {
            //--- if atr protection is disabled, transition directly
            m_lifecycle_state = POSITION_PROTECTED;
           }
        }

Обновление состояния жизненного цикла после успешного обеспечения защиты предотвращает повторное выполнение того же действия в ходе последующих циклов обновления. Теперь эта позиция может перейти к последующим этапам жизненного цикла.


Реализация перевода в безубыток в рамках жизненного цикла

Перевод в безубыток выполняется внутри функции Update() класса CManagedPosition. Проверка условий перевода позиции в безубыток выполняется только после завершения этапа начальной защиты, что обеспечивает правильный порядок действий в рамках жизненного цикла.

//--- handle state: POSITION_PROTECTED -> Check for breakeven transition
if(m_lifecycle_state == POSITION_PROTECTED && use_be)
  {
   double current_bid = SymbolInfoDouble(m_symbol, SYMBOL_BID);
   double current_ask = SymbolInfoDouble(m_symbol, SYMBOL_ASK);

   double trigger_distance = PositionManagerUtils::PipsToPrice(m_symbol, be_trigger);
   double offset_distance  = PositionManagerUtils::PipsToPrice(m_symbol, be_offset);

   bool trigger_hit = false;
   double new_sl = 0.0;

//--- evaluate buy positions
   if(m_position_type == POSITION_TYPE_BUY)
     {
      if(current_bid >= (m_entry_price + trigger_distance))
        {
         new_sl = PositionManagerUtils::NormalizePrice(
                     m_symbol,
                     m_entry_price + offset_distance);

         trigger_hit = (new_sl > m_current_sl);
        }
     }

//--- evaluate sell positions
   else
      if(m_position_type == POSITION_TYPE_SELL)
        {
         if(current_ask <= (m_entry_price - trigger_distance))
           {
            new_sl = PositionManagerUtils::NormalizePrice(
                        m_symbol,
                        m_entry_price - offset_distance);

            trigger_hit = (new_sl < m_current_sl || m_current_sl == 0.0);
           }
        }

//--- apply breakeven protection
   if(trigger_hit)
     {
      double tp = m_position_info.TakeProfit();

      if(m_trade_client.PositionModify(m_ticket, new_sl, tp))
        {
         m_current_sl = new_sl;
         m_lifecycle_state = POSITION_BREAKEVEN;

         if(InpEnableLogging)
            Print("Lifecycle state changed to BREAKEVEN for ticket: ", m_ticket);
        }
     }
  }

После успешного изменения стоп-лосса управляемая позиция меняет свое состояние жизненного цикла на POSITION_BREAKEVEN. Это фиксирует факт завершения перехода и предотвращает повторное выполнение того же действия в ходе будущих циклов обновления.

Примечание по архитектуре

Правило перевода в безубыток, реализованное в этой версии, намеренно упрощено. Система управления жизненным циклом отвечает только за управление переходом между состояниями:

Готова ли эта позиция к следующему этапу управления?

Логика принятия решений определяет:

При каких условиях должен быть разрешен этот переход?

Благодаря разделению этих обязанностей модель перевода в безубыток может развиваться без изменения архитектуры жизненного цикла.

Например, будущие модели перевода в безубыток могли бы учитывать следующие факторы:

  • Поправка на волатильность — адаптация расстояния до срабатывания с учетом текущих рыночных условий.
  • Подтверждение рыночной структуры — требование выполнения условий ценовой структуры, таких как формирование более высоких максимумов, более высоких минимумов или пробои ключевых уровней.
  • Подтверждение объемом — проверка того, что движение цены подкрепляется достаточной активностью участников рынка.

Эти изменения затрагивают лишь критерии перехода, тогда как фреймворк управления жизненным циклом остается неизменным.


Очистка после закрытия позиции и завершение жизненного цикла

Заключительным этапом управления позициями является обработка завершенных сделок. После закрытия позиции ее представление в терминале MetaTrader 5 становится недоступным, поэтому менеджер должен удалить соответствующий объект из активного отслеживания.

В ходе обработки менеджер обновляет каждую управляемую позицию и удаляет объекты, перешедшие в состояние POSITION_CLOSED.

//--- step 2: update all active managed positions and clean up closed ones
for(int i = m_managed_positions.Total() - 1; i >= 0; i--)
  {
   CManagedPosition *pos = dynamic_cast<CManagedPosition*>(m_managed_positions.At(i));

   if(pos == NULL)
      continue;

//--- update the managed position according to its current lifecycle state
   pos.Update(
      m_risk_engine,
      InpUseATRProtection,
      InpUseBreakEven,
      InpBreakEvenTrigger,
      InpBreakEvenOffset
   );

//--- remove positions that have completed their lifecycle
   if(pos.GetState() != POSITION_CLOSED)
      continue;

   if(InpEnableLogging)
      Print("Position closed, removing from manager, ticket: ", pos.GetTicket());

   m_managed_positions.Delete(i);
  }

Удаление позиции из коллекции сохраняет соответствие внутреннего представления торговой среде, и завершенные сделки больше не обрабатываются. Теперь, когда реализованы обнаружение позиций, защита, перевод в безубыток и очистка после закрытия позиции, менеджер жизненного цикла позиций обеспечивает основу для управления сделкой на протяжении всего ее жизненного цикла.


Интеграция менеджера жизненного цикла позиций в советник

Последний шаг — подключение менеджера жизненного цикла позиций к существующему советнику. Для демонстрации фреймворк интегрирован со стандартным примером советника MACD, входящим в состав MetaTrader 5. Стратегия MACD не претерпела изменений в плане анализа рынка и логики входа в рынок. Эта интеграция добавляет уровень управления позициями, необходимый для мониторинга и управления сделками после их исполнения.

Общая структура интеграции представлена ниже:

Рис. 2. Схема интеграции менеджера жизненного цикла позиций

Рис. 2. Схема интеграции менеджера жизненного цикла позиций

На блок-схеме показано, как существующий советник можно интегрировать с менеджером жизненного цикла позиций. Тот же подход можно применить и к другим стратегиям, инициализировав менеджер и позволив ему обрабатывать позиции в ходе выполнения.

Адаптация стратегии для управления жизненным циклом позиций

В исходном примере MACD открытие сделок и управление позициями объединены в одном советнике. Для интеграции фреймворка управления жизненным циклом позиций дублирующаяся логика управления удаляется.

Советник продолжает выполнять следующие задачи:

  • принятие решений о входе в рынок,
  • исполнение сделок,
  • установку тейк-профита.

Исходная реализация трейлинг-стопа удалена, поскольку управление стоп-лоссами теперь осуществляется менеджером жизненного цикла позиций. Логика выхода на основе сигнала MACD также по умолчанию отключена, чтобы избежать конфликтов с управлением жизненным циклом позиций.

input double InpLots          = 0.1;                  // Lots
input int    InpTakeProfit    = 50;                   // Take Profit (in pips)
//--- DELETED: input int    InpTrailingStop  = 30;    // Trailing Stop Level (in pips) - Replaced by CPositionManager framework inputs
input int    InpMACDOpenLevel = 3;                    // MACD open level (in pips)
input int    InpMACDCloseLevel= 2;                    // MACD close level (in pips)
input int    InpMATrendPeriod = 26;                   // MA trend period
input bool   InpUseMACDExit   = false;                // Disabled original MACD signal-based exits

В будущих версиях фреймворк можно расширить дополнительными функциями управления, такими как динамическое управление тейк-профитом и усовершенствованная логика выхода.

Подключение модуля менеджера позиций

Первый шаг — добавление необходимого модуля управления позициями.

//--- Include the custom modular position lifecycle framework
#include <PositionManager\PositionManager.mqh>
Модуль предоставляет доступ к:

  • CPositionManager,
  • отслеживание управляемых позиций,
  • обработка жизненного цикла,
  • вспомогательные компоненты системы управления.

Стратегии не требуется доступ к внутренней реализации менеджера. Стратегия взаимодействует только с интерфейсом, необходимым для инициализации компонента и вызова его обработки.

Создание экземпляра менеджера

Советник создает один экземпляр класса CPositionManager.

//--- global expert
CSampleExpert ExtExpert;
//--- Global instance for the modular position lifecycle manager framework
CPositionManager ExtPositionManager;

Отдельные объекты CManagedPosition создаются автоматически в процессе обнаружения позиций. Советник взаимодействует исключительно с интерфейсом менеджера.

Инициализация менеджера жизненного цикла позиций

При запуске менеджер инициализируется внутри функции Init() советника.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//--- create all necessary objects
   if(!ExtExpert.Init())
      return(INIT_FAILED);

//--- Initialize the modular position lifecycle manager framework
   if(!ExtPositionManager.Initialize())
      return(INIT_FAILED);

//--- succeed
   return(INIT_SUCCEEDED);
  }

На этапе инициализации подготавливаются внутренние ресурсы, необходимые для обработки позиций. После успешной инициализации менеджер жизненного цикла позиций готов к мониторингу позиций, созданных торговой стратегией.

Обработка позиций во время выполнения программы

Заключительный этап интеграции происходит внутри функции OnTick(). Стратегия продолжает работать в обычном режиме, а менеджеру позиций выделяется время выполнения для обработки изменений в жизненном цикле позиций.

//+------------------------------------------------------------------+
//| Expert new tick handling function                                |
//+------------------------------------------------------------------+
void OnTick(void)
  {
//--- Delegate post-execution position tracking, state machine, ATR protection, and break-even management to CPositionManager
   ExtPositionManager.Process();

   static datetime limit_time=0; // last trade processing time + timeout
//--- don't process if timeout
   if(TimeCurrent()>=limit_time)
     {
      //--- check for data
      if(Bars(Symbol(),Period())>2*InpMATrendPeriod)
        {
         //--- change limit time by timeout in seconds if processed
         if(ExtExpert.Processing())
            limit_time=TimeCurrent()+ExtTimeOut;
        }
     }
  }

Во время выполнения:

  • Метод CPositionManager::Process() оценивает текущую ситуацию с позициями.
  • Обнаруживаются и регистрируются новые позиции.
  • Существующие управляемые позиции продолжают проходить свой жизненный цикл.
  • Закрытые позиции исключаются из активного отслеживания.

Стратегии не требуется знать текущую стадию жизненного цикла каждой сделки. Эту информацию поддерживает у себя менеджер жизненного цикла позиций.


Результат интеграции

После интеграции советник работает на основе двух независимых уровней: уровня стратегии и уровня управления позициями. Приведенный ниже вывод тестера подтверждает, что менеджер жизненного цикла позиций корректно инициализирован и успешно управляет жизненным циклом позиции.

Рис. 3. Наглядное подтверждение работы фреймворка по журналу

Пример с MACD служит лишь демонстрационной средой. Менеджер жизненного цикла позиций остается повторно используемым компонентом, который можно интегрировать в другие советники, требующие структурированного управления позициями.

Такое разделение позволяет независимо расширять компоненты открытия сделок и управления позициями.


Заключение

В этой первой части мы заложили основу повторно используемого менеджера жизненного цикла позиций для MQL5. Фреймворк обеспечивает структурированный подход к управлению позициями после входа в рынок, отслеживая состояния жизненного цикла и обрабатывая позиции на определенных этапах.

В реализации были представлены основные компоненты, необходимые для управления на основе жизненного цикла:

  • автоматическое обнаружение позиций,
  • объекты управляемых позиций,
  • отслеживание состояний жизненного цикла,
  • защита на основе ATR,
  • перевод в безубыток,
  • очистка после закрытия позиции.

Интеграция со стандартным советником MACD показала, что структурированное управление позициями можно внедрить без изменения основной торговой логики стратегии. В результате получается фреймворк для повторного использования, в котором открытие сделок и управление позициями остаются независимыми друг от друга. В следующих частях эту основу можно будет расширить дополнительными возможностями, включая системы динамического трейлинг-стопа, управление частями позиций, подхват сделок, открытых вручную, аналитику сделок и более совершенные модели рисков.

Имя файла
Описание
PositionManager_MACD_Sample.mq5 Точка входа демонстрационного советника. Он содержит исходную торговую логику MACD и интегрирует менеджер жизненного цикла позиций. Советник по-прежнему отвечает за анализ рынка и исполнение сделок, передавая обновления данных во время выполнения во фреймворк управления позициями.
PositionManager.mqh
Реализует центральный уровень оркестрации фреймворка. Он обнаруживает активные позиции, создаёт объекты управляемых позиций, поддерживает коллекцию отслеживаемых позиций, координирует обработку их жизненного цикла и исключает закрытые позиции из активного управления.
ManagedPosition.mqh
Реализует поведение отдельной управляемой позиции. Он хранит идентификационные данные позиции, исходную информацию о сделке, состояние жизненного цикла и данные времени выполнения, используемые для управления, а также контролирует прохождение отдельной позиции через заданные этапы её жизненного цикла.
RiskEngine.mqh
Предоставляет вычислительный слой, необходимый для процесса управления. В этой первой реализации модуль выполняет расчёты защиты на основе ATR, сохраняя независимость расчётов рисков от логики управления жизненным циклом.
Common.mqh Содержит общие определения, используемые во всём фреймворке, включая перечисления состояний жизненного цикла, общие константы, значения конфигурации и вспомогательные объявления, необходимые нескольким компонентам.
MQL5.zip Архив, содержащий полную структуру папок MQL5. Распакуйте архив в каталог терминала MetaTrader 5 таким образом, чтобы файл PositionManager_MACD_Sample.mq5 находился в папке MQL5\Experts\PositionManager\, а все вспомогательные файлы с расширением .mqh — в папке MQL5\Include\PositionManager\.

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/23752

Прикрепленные файлы |
MQL5.zip (10.14 KB)
Конструирование признаков для машинного обучения (Часть 13): Признаки на основе сканирования трендов в Python Конструирование признаков для машинного обучения (Часть 13): Признаки на основе сканирования трендов в Python
Сканирование трендов поддерживает как окна, направленные в будущее, так и окна, направленные в прошлое, а режим разметки по умолчанию небезопасен для вычисления признаков: он использует будущие данные и на случайных блужданиях повышает долю совпадений с направлением следующего бара значительно выше случайного уровня. Мы предлагаем специальную функцию-обертку get_trend_scanning_features, которая принудительно задает каузальный режим вычислений и возвращает только window, slope, t_value и rsquared. Во втором анализе количественно оцениваются ошибки, возникающие при применении используемого по умолчанию логарифмического преобразования к рядам, допускающим отрицательные значения.
Создание пользовательских индикаторов для начинающих (Часть 1): Индикатор SuperTrend Создание пользовательских индикаторов для начинающих (Часть 1): Индикатор SuperTrend
В данной статье описывается создание надежного индикатора SuperTrend на MQL5 с использованием полос на основе ATR, механизма фиксации полосы и строгого соблюдения индексации как в таймсериях, что позволяет избежать скрытых ошибок рекурсивного расчета и перерисовки на закрытых барах. Мы рассмотрим привязку буферов, управление хэндлом индикатора ATR, задание начальных значений и логику подтверждения стрелок. Сопутствующий торговый советник (EA) демонстрирует практическую интеграцию
Разрабатываем менеджер терминалов (Часть 4): Используем сервис для получения информации о терминалах Разрабатываем менеджер терминалов (Часть 4): Используем сервис для получения информации о терминалах
Заменяем последовательный опрос терминалов из Python сервисом MQL5, который записывает состояние каждого терминала и торгового счёта в общую базу SQLite. Разбираем схему базы, чтение данных веб-приложением и развёртывание сервиса на нескольких терминалах. Такой подход позволяет получать данные параллельно и сохранять существующий интерфейс почти без изменений.
Интерактивное управление зонами спроса и предложения на MQL5 (Часть IV): Tорговля в зонах спроса и предложения Интерактивное управление зонами спроса и предложения на MQL5 (Часть IV): Tорговля в зонах спроса и предложения
Мы расширяем фреймворк зон спроса и предложения, добавляя уровень стратегии, который преобразует взаимодействия цены с зонами в решения. Зоны, прошедшие проверку пригодности, последовательно проверяются на близость цены к зоне, характер приближения цены к зоне, согласованность с условиями старшего таймфрейма и подтверждение по моделям Price Action, после чего исполнение передается специализированному менеджеру торговли. Эта архитектура повышает управляемость, упрощает сопровождение и дальнейшее расширение системы без изменения базового механизма обработки зон.