English 中文 Español Deutsch 日本語 Português
Кроссплатформенный торговый советник: Стоп-уровни

Кроссплатформенный торговый советник: Стоп-уровни

MetaTrader 5Примеры | 10 октября 2017, 15:18
7 417 2
Enrico Lambino
Enrico Lambino

Оглавление

  1. Введение
  2. COrder
  3. CStop
  4. CStops
  5. COrderStop
  6. COrderStops
  7. Отображение стоп-уровней на графике
  8. Проверка ордеров на стоп-уровни
  9. Примеры
  10. Заключение
  11. Программы, использованные в статье
  12. Файлы классов, созданных в статье


Введение

В предыдущей статье мы создали для кроссплатформенного торгового эксперта менеджер ордеров (COrderManager), который сглаживает большинство различий между MQL4 и MQL5 в части открытия и закрытия сделок. В обеих версиях советник сохраняет в памяти информацию о сделках путем создания экземпляров COrder. Контейнеры с динамическими указателями на экземпляры этого объекта класса также доступны как члены класса COrderManager (как для текущих сделок, так и для находящихся в истории).

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

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

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

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

В этой статье мы поговорим о реализации, в которой СOrderManager будет работать исключительно со входами в основные сделки и выходами из них (как и было до сих пор), а затем реализуем отдельную обработку стоп-уровней объектом другого класса (CStop).

COrder

Как уже было показано в одной из предыдущих статей, экземпляр COrder создается после успешной торговой операции (открытия сделки). И для MetaTrader 4, и для MetaTrader 5 информация о стоп-лоссе и тейк-профите может быть сохранена на стороне брокера. Но в случае, если стоп-уровни скрыты от брокера или задействованы несколько стоп-уровней, информация о большей их части должна храниться локально. Таким образом, в последнем случае, сразу же после успешного открытия позиции должен быть создан экземпляр COrder, а вслед за ним — экземпляры объекта, представляющие ее уровни стоп-лосса и тейк-профита. В одной из предыдущих статей мы показали, как экземпляры COrder добавляются в менеджер ордеров при создании. Это проиллюстрировано следующим рисунком:


TradeOpen

Стоп-уровни добавляются точно так же. Чтобы это сделать, нам просто нужно вставить метод после того, как создан новый экземпляр COrder, и перед тем, как он добавляется в список текущих сделок (COrders). Таким образом, вышеприведенная картинка слегка изменяется:


TradeOpen - со стоп-ордерами

Операция по созданию стоп-уровней в общем виде показана на следующей картинке:

Общий вид операции создания стоп-уровней

Как показано на двух предыдущих блок-схемах, новый экземпляр COrder создается сразу же после успешного открытия сделки. После этого для каждого установленного уровня стоп-лосса и тейк-профита создаются экземпляры COrderStop. Если при инициализации советника не объявлен экземпляр СStop, этот этап процесса пропускается. И наоборот, если созданы экземпляры COrderStop, указатели на них будут сохранены в ранее созданном экземпляре COrder. Эти операции находятся в методе Init класса COrder:

bool COrderBase::Init(COrders *orders,CStops *stops)
  {
   if(CheckPointer(orders))
      SetContainer(GetPointer(orders));
   if(CheckPointer(stops))
      CreateStops(GetPointer(stops));
   m_order_stops.SetContainer(GetPointer(this));
   return true;
  }

Чтобы создать стоп-уровни для экземпляра COrder, мы можем подсмотреть, как вызывается метод этого класса CreateStops:

void COrderBase::CreateStops(CStops *stops)
  {
   if(!CheckPointer(stops))
      return;
   if(stops.Total()>0)
     {
      for(int i=0;i<stops.Total();i++)
        {
         CStop *stop=stops.At(i);
         if(CheckPointer(stop)==POINTER_INVALID)
            continue;
         m_order_stops.NewOrderStop(GetPointer(this),stop);
        }
     }
  }
Метод проходится в цикле через все доступные экземпляры CStop, представляющие каждую пару стоп-уровней (стоп-лосс + тейк-профит). Каждый из этих экземпляров CStop передается в экземпляр COrderStops, который является просто контейнером для всех стоп-уровней по данному ордеру. Таким образом, мы можем построить иерархию объектов класса следующим образом:


Иерархия стоп-объектов

Для каждого экземпляра COrder имеется один член типа COrderStops. Этот экземпляр COrderStops — контейнер (расширение CArrayObj), который содержит указатели на экземпляры COrderStop. Каждый экземпляр COrderStop представляет стоп-уровень (CStop) только для этой конкретной сделки (экземпляр COrder).

CStop

Как уже обсуждалось ранее, нам хотелось бы иметь возможность настраивать способ обработки стоп-уровней для каждой сделки без вмешательства в исходный код Менеджера ордеров. Эти требования вполне по плечу классу CStop. Среди возможностей этого класса — следующие:

  1. определение уровней стоп-лосса и тейк-профита;
  2. расчет стоп-уровней;
  3. реализация уровней стоп-лосса и тейк-профита для основной сделки;
  4. проверка на достижение стоп-уровня;
  5. сглаживание различий между имплементацией стоп-лосса и тейк-профита на языках MQL4 и MQL5;
  6. определение действий по достижении стопов (переход в безубыток, трейлинг-стоп и т.д.).

Пункты 1-5 мы обсудим ниже, а п. 6 будет посвящена отдельная статья.

Типы

Поговорим о трех типах стоп-уровней.

  1. Стоп, срабатывающий на стороне брокера — стоп-уровень, который отправляется брокеру вместе с торговым приказом.
  2. Стоп, выставленный по отложенному ордеру. Он срабатывает либо как частичное/полное хеджирование в направлении, противоположном основной позиции (MetaTrader 4 или режим хеджирования в MetaTrader 5), либо как вычитание из основной позиции (неттинговый режим MetaTrader 5).
  3. Виртуальный стоп скрыт от брокера и обрабатывается локально, внутри советника.

В MetaTrader 4 к первой группе стопов относятся самые распространенные брокерские стоп-лосс и тейк-профит. Цены, на которых они должны сработать, отправляются брокеру вместе с торговым приказом об основной сделке. В хеджинговой версии MetaTrader 5 используется тот же механизм, что и в MetaTrader 4. В неттинговом режиме для этого типа CStop будут использоваться стопы по отложенным ордерам, поскольку стоп-лосс и тейк-профит здесь отличаются (они применяются к полной позиции по символу).

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

Основной стоп

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

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

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

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

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

Объём

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

  1. Фиксирование — назначение фиксированного объема лота
  2. Процент остатка — процент от объема лота, остающегося в основной позиции
  3. Общий процент — процент от общего начального лота главной сделки.
  4. Остаток — оставшийся объем основной сделки.

Назначение фиксированного объема лота — самая простая форма распределения объема. Но это может работать неоптимально, если советник использует некоторые формы динамического расчета объема лота для каждой позиции (например, мани-менеджмент). Такой способ идеален для использования, только если объем лота не изменяется в течение всей работы эксперта.

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

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

Один-Отменяет-Остальные (One-Cancels-the-Other, OCO)

CStop всегда представлен парой значений, которые представляют стоп-лосс или тейк-профит. Однако можно установить только один стоп (тейк-профит без стоп-лосса и наоборот): отсутствующему уровню просто нужно установить значение 0. По умолчанию, при срабатывании одного стоп-уровня закрываются остальные. Единственное исключение — ситуация, когда экземпляр CStop является главным стоп-уровнем.

Базовый класс

Базовый клас для CStop (CStopBase) продемонстрирован в нижеследующем фрагменте кода:

class CStopBase : public CObject
  {
protected:
   //--- параметры стоп-ордера   
   bool              m_active;
   bool              m_main;
   string            m_name;
   bool              m_oco;
   double            m_stoploss;
   string            m_stoploss_name;
   ENUM_STOP_TYPE    m_stop_type;
   double            m_takeprofit;
   string            m_takeprofit_name;
   int               m_delay;
   //--- торговые параметры стоп-ордера
   ENUM_VOLUME_TYPE  m_volume_type;
   double            m_volume;
   int               m_magic;
   int               m_deviation;
   string            m_comment;
   //--- параметры объекта стоп-ордера
   bool              m_entry_visible;
   bool              m_stoploss_visible;
   bool              m_takeprofit_visible;
   color             m_entry_color;
   color             m_stoploss_color;
   color             m_takeprofit_color;
   ENUM_LINE_STYLE   m_entry_style;
   ENUM_LINE_STYLE   m_stoploss_style;
   ENUM_LINE_STYLE   m_takeprofit_style;
   //--- объекты
   CSymbolManager   *m_symbol_man;
   CSymbolInfo      *m_symbol;
   CAccountInfo     *m_account;
   CTradeManager     m_trade_man;
   CExpertTradeX    *m_trade;
   CTrails          *m_trails;
   CEventAggregator *m_event_man;
   CStops           *m_stops;
public:
                     CStopBase(void);
                    ~CStopBase(void);
   virtual int       Type(void) const {return CLASS_TYPE_STOP;}
   //--- инициализация
   virtual bool      Init(CSymbolManager*,CAccountInfo*,CEventAggregator*);
   virtual bool      InitAccount(CAccountInfo*);
   virtual bool      InitEvent(CEventAggregator*);
   virtual bool      InitSymbol(CSymbolManager*);
   virtual bool      InitTrade(void);
   virtual CStops   *GetContainer(void);
   virtual void      SetContainer(CStops*);
   virtual bool      Validate(void) const;
   //--- методы получения и установки
   bool              Active(void);
   void              Active(const bool);
   bool              Broker(void) const;
   void              Comment(const string);
   string            Comment(void) const;
   void              Delay(int delay);
   int               Delay(void) const;
   void              SetDeviation(const int);
   int               SetDeviation(void) const;
   void              EntryColor(const color clr);
   void              EntryStyle(const ENUM_LINE_STYLE);
   void              EntryVisible(const bool);
   bool              EntryVisible(void) const;
   void              Magic(const int);
   int               Magic(void) const;
   void              Main(const bool);
   bool              Main(void) const;
   void              Name(const string);
   string            Name(void) const;
   void              OCO(const bool oco);
   bool              OCO(void) const;
   bool              Pending(void) const;
   void              StopLoss(const double);
   double            StopLoss(void) const;
   void              StopLossColor(const color);
   bool              StopLossCustom(void);
   void              StopLossName(const string);
   string            StopLossName(void) const;
   void              StopLossVisible(const bool);
   bool              StopLossVisible(void) const;
   void              StopLossStyle(const ENUM_LINE_STYLE);
   void              StopType(const ENUM_STOP_TYPE);
   ENUM_STOP_TYPE    StopType(void) const;
   string            SymbolName(void);
   void              TakeProfit(const double);
   double            TakeProfit(void) const;
   void              TakeProfitColor(const color);
   bool              TakeProfitCustom(void);
   void              TakeProfitName(const string);
   string            TakeProfitName(void) const;
   void              TakeProfitStyle(const ENUM_LINE_STYLE);
   void              TakeProfitVisible(const bool);
   bool              TakeProfitVisible(void) const;
   bool              Virtual(void) const;
   void              Volume(double);
   double            Volume(void) const;
   void              VolumeType(const ENUM_VOLUME_TYPE);
   ENUM_VOLUME_TYPE  VolumeType(void) const;
   //--- проверка
   virtual bool      CheckStopLoss(COrder*,COrderStop*);
   virtual bool      CheckTakeProfit(COrder*,COrderStop*);
   virtual bool      CheckStopOrder(ENUM_STOP_MODE,COrder*,COrderStop*)=0;
   virtual bool      DeleteStopOrder(const ulong)=0;
   virtual bool      DeleteMarketStop(const ulong)=0;
   virtual bool      OrderModify(const ulong,const double);
   //--- создание объекта стоп-ордера
   virtual CStopLine *CreateEntryObject(const long,const string,const int,const double);
   virtual CStopLine *CreateStopLossObject(const long,const string,const int,const double);
   virtual CStopLine *CreateTakeProfitObject(const long,const string,const int,const double);
   //--- расчет цены стоп-ордера  
   virtual bool      Refresh(const string);
   virtual double    StopLossCalculate(const string,const ENUM_ORDER_TYPE,const double);
   virtual double    StopLossCustom(const string,const ENUM_ORDER_TYPE,const double);
   virtual double    StopLossPrice(COrder*,COrderStop*);
   virtual double    StopLossTicks(const ENUM_ORDER_TYPE,const double);
   virtual double    TakeProfitCalculate(const string,const ENUM_ORDER_TYPE,const double);
   virtual double    TakeProfitCustom(const string,const ENUM_ORDER_TYPE,const double);
   virtual double    TakeProfitPrice(COrder*,COrderStop*);
   virtual double    TakeProfitTicks(const ENUM_ORDER_TYPE,const double);
   //--- трейлинг
   virtual bool      Add(CTrails*);
   virtual double    CheckTrailing(const string,const ENUM_ORDER_TYPE,const double,const double,const ENUM_TRAIL_TARGET);
protected:
   //--- создание объекта
   virtual CStopLine *CreateObject(const long,const string,const int,const double);
   //--- расчет цены стоп-ордера
   virtual double    LotSizeCalculate(COrder*,COrderStop*);
   //--- вход в стоп-ордер   
   virtual bool      GetClosePrice(const string,const ENUM_ORDER_TYPE,double&);
   //--- выход из стоп-ордера
   virtual bool      CloseStop(COrder*,COrderStop*,const double)=0;
   //--- deinitialization
   virtual void      Deinit(void);
   virtual void      DeinitSymbol(void);
   virtual void      DeinitTrade(void);
   virtual void      DeinitTrails(void);
  };

Для уровней стоп-лосса и тейк-профита на основе пипсов или пунктов нужно будет сохранить как минимум четыре метода класса:

  1. Тип стоп-уровня (брокерский, на основе отложенного ордера или виртуальный), метод StopType
  2. Используемый тип расчета объема, метод VolumeType
  3. Уровень стоп-лосса в пунктах (при необходимости),  метод StopLoss
  4. Уровень тейк-профита в пунктах (при необходимости), метод ТakeProfit

Все они — просто методы установки членов класса, поэтому вдаваться в подробности их рассмотрения мы не будем. Большая часть остальных методов нужны классу только для внутренних расчетов. Среди важнейших из этих защищенных методов — StopLossCalculate и TakeProfitCalculate. Их код показан ниже:

double CStopBase::StopLossCalculate(const string symbol,const ENUM_ORDER_TYPE type,const double price)
  {   
   if(!Refresh(symbol))
      return 0;
   if(type==ORDER_TYPE_BUY || type==ORDER_TYPE_BUY_STOP || type==ORDER_TYPE_BUY_LIMIT)
      return price-m_stoploss*m_symbol.Point();
   else if(type==ORDER_TYPE_SELL || type==ORDER_TYPE_SELL_STOP || type==ORDER_TYPE_SELL_LIMIT)
      return price+m_stoploss*m_symbol.Point();
   return 0;
  }

double CStopBase::TakeProfitCalculate(const string symbol,const ENUM_ORDER_TYPE type,const double price)
  {
   if(!Refresh(symbol))
      return 0;
   if(type==ORDER_TYPE_BUY || type==ORDER_TYPE_BUY_STOP || type==ORDER_TYPE_BUY_LIMIT)
      return price+m_takeprofit*m_symbol.Point();
   else if(type==ORDER_TYPE_SELL || type==ORDER_TYPE_SELL_STOP || type==ORDER_TYPE_SELL_LIMIT)
      return price-m_takeprofit*m_symbol.Point();
   return 0;
  }

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

CStops

Класс CStops — контейнер для экземпляров CStop. Экземпляр этого класса должен будет динамически добавляться к менеджеру ордеров как один из его членов. В коде ниже показан CStopsBase, который является базовым классом для CStops:

class CStopsBase : public CArrayObj
  {
protected:
   bool              m_active;
   CEventAggregator *m_event_man;
   CObject          *m_container;
public:
                     CStopsBase(void);
                    ~CStopsBase(void);
   virtual int       Type(void) const {return CLASS_TYPE_STOPS;}
   //--- инициализация
   virtual bool      Init(CSymbolManager*,CAccountInfo*,CEventAggregator*);
   virtual CObject  *GetContainer(void);
   virtual void      SetContainer(CObject*);
   virtual bool      Validate(void) const;
   //--- методы установки и получения
   virtual bool      Active(void) const;
   virtual void      Active(const bool);
   virtual CStop    *Main(void);
   //--- recovery
   virtual bool      CreateElement(const int);
  };

Этот класс очень похож на другие контейнеры, описанные ранее в этой серии статей.

COrderStop

COrderStop представляет реализацию СStop для конкретной сделки. Для заданной позиции CStop может создать максимум один экземпляр COrderStop. Но произвольное количество экземпляров COrderStop могут использовать один и тот же экземпляр CStop. Таким образом, если у эксперта есть 3 разных экземпляра CStop, мы обычно ждем, что каждый экземпляр COrder должен будет иметь одинаковое количество экземпляров СOrderStop. Если советник совершил 1000 сделок, количество созданных экземпляров СOrderStop будет 1000 * 3 = 3000, тогда как количество созданных экземпляров CStop останется равным 3.

Определение COrderStopBase, который является базовым для COrderStop, показано в нижеследующем фрагменте кода:

class COrderStopBase : public CObject
  {
protected:
   bool              m_active;
   //--- параметры стопа
   double            m_volume;
   CArrayDouble      m_stoploss;
   CArrayDouble      m_takeprofit;
   ulong             m_stoploss_ticket;
   ulong             m_takeprofit_ticket;
   bool              m_stoploss_closed;
   bool              m_takeprofit_closed;
   bool              m_closed;
   ENUM_STOP_TYPE    m_stop_type;
   string            m_stop_name;
   //--- объект основного ордера
   COrder           *m_order;
   //--- стоп-объекты
   CStop            *m_stop;
   CStopLine        *m_objentry;
   CStopLine        *m_objsl;
   CStopLine        *m_objtp;
   COrderStops      *m_order_stops;
public:
                     COrderStopBase(void);
                    ~COrderStopBase(void);
   virtual int       Type(void) const {return CLASS_TYPE_ORDERSTOP;}
   //--- инициализация
   virtual void      Init(COrder*,CStop*,COrderStops*);
   virtual COrderStops *GetContainer(void);
   virtual void      SetContainer(COrderStops*);
   virtual void      Show(bool);
   //--- методы получения и установки  
   bool              Active(void) const;
   void              Active(bool active);
   string            EntryName(void) const;
   ulong             MainMagic(void) const;
   ulong             MainTicket(void) const;
   double            MainTicketPrice(void) const;
   ENUM_ORDER_TYPE   MainTicketType(void) const;
   COrder           *Order(void);
   void              Order(COrder*);
   CStop            *Stop(void);
   void              Stop(CStop*);
   bool              StopLoss(const double);
   double            StopLoss(void) const;
   double            StopLoss(const int);
   void              StopLossClosed(const bool);
   bool              StopLossClosed(void);
   double            StopLossLast(void) const;
   string            StopLossName(void) const;
   void              StopLossTicket(const ulong);
   ulong             StopLossTicket(void) const;
   void              StopName(const string);
   string            StopName(void) const;
   bool              TakeProfit(const double);
   double            TakeProfit(void) const;
   double            TakeProfit(const int);
   void              TakeProfitClosed(const bool);
   bool              TakeProfitClosed(void);
   double            TakeProfitLast(void) const;
   string            TakeProfitName(void) const;
   void              TakeProfitTicket(const ulong);
   ulong             TakeProfitTicket(void) const;
   void              Volume(const double);
   double            Volume(void) const;
   //--- проверка   
   virtual void      Check(double&)=0;
   virtual bool      Close(void);
   virtual bool      CheckTrailing(void);
   virtual bool      DeleteChartObject(const string);
   virtual bool      DeleteEntry(void);
   virtual bool      DeleteStopLines(void);
   virtual bool      DeleteStopLoss(void);
   virtual bool      DeleteTakeProfit(void);
   virtual bool      IsClosed(void);
   virtual bool      Update(void) {return true;}
   virtual void      UpdateVolume(double) {}
   //--- deinitialization 
   virtual void      Deinit(void);
   //--- recovery
   virtual bool      Save(const int);
   virtual bool      Load(const int);
   virtual void      Recreate(void);
protected:
   virtual bool      IsStopLossValid(const double) const;
   virtual bool      IsTakeProfitValid(const double) const;
   virtual bool      Modify(const double,const double);
   virtual bool      ModifyStops(const double,const double);
   virtual bool      ModifyStopLoss(const double) {return true;}
   virtual bool      ModifyTakeProfit(const double){return true;}
   virtual bool      UpdateOrderStop(const double,const double){return true;}
   virtual bool      MoveStopLoss(const double);
   virtual bool      MoveTakeProfit(const double);
  };

COrderStop хранится в COrderStops (это мы рассмотрим ниже), который, в свою очередь, содержится в COrder. В текущей имплементации советника нет неоходимости объявлять экземпляр COrderStop. Его автоматически создает COrder на основе отдельного экземпляра CStop.

COrderStops

class COrderStopsBase : public CArrayObj
  {
protected:
   bool              m_active;
   CArrayInt         m_types;
   COrder           *m_order;
public:
                     COrderStopsBase(void);
                    ~COrderStopsBase(void);
   virtual int       Type(void) const {return CLASS_TYPE_ORDERSTOPS;}
   void              Active(bool);
   bool              Active(void) const;
   //--- инициализация
   virtual CObject *GetContainer(void);
   virtual void      SetContainer(COrder*);
   virtual bool      NewOrderStop(COrder*,CStop*)=0;
   //--- проверка
   virtual void      Check(double &volume);
   virtual bool      CheckNewTicket(COrderStop*);
   virtual bool      Close(void);
   virtual void      UpdateVolume(const double) {}
   //--- скрытие и показ линий уровней
   virtual void      Show(const bool);
   //--- recovery
   virtual bool      CreateElement(const int);
   virtual bool      Save(const int);
   virtual bool      Load(const int);
  };


Подобно CStop, он выглядит просто как типичный контейнер класса. Однако в нем есть некоторые методы, отражающие методы объектов, чьи указатели предназначаются для хранения (COrderStop).

Отображение стоп-уровней на графике

CStopLine — член класса CStop, предназначенный для графического отображения стоп-уровней. Он выполняет в советнике три ключевых функции:

  1. Показывает стоп-уровни при инициализации экземпляра COrder
  2. Обновляет стоп-уровни, если один из них или оба были изменены
  3. Удаляет линии стоп-уровней, как только главная сделка закрывается

Все эти функции реализуются с помощью класса CStop.

Определение CStopLineBase, на которой основан СStopLine, показано ниже:

class CStopLineBase : public CChartObjectHLine
  {
protected:
   bool              m_active;
   CStop            *m_stop;
public:
                     CStopLineBase(void);
                    ~CStopLineBase(void);
   virtual int       Type(void) const {return CLASS_TYPE_STOPLINE;}
   virtual void      SetContainer(CStop*);
   virtual CStop    *GetContainer(void);
   bool              Active(void) const;
   void              Active(const bool);
   virtual bool      ChartObjectExists(void) const;
   virtual double    GetPrice(const int);
   virtual bool      Move(const double);
   virtual bool      SetStyle(const ENUM_LINE_STYLE);
   virtual bool      SetColor(const color);
  };

В старых версиях MetaTrader 4 уровни стоп-лосса и тейк-профита нельзя передвигать перетаскиванием. Их можно изменять только в окне торгового приказа или через использование специальных скриптов или экспертов. Но графическое отображение этих уровней все равно будет полезным, особенно при работе со скрытыми (виртуальными) стопами.

Проверка ордеров на стоп-уровни

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

Для виртуальных (скрытых) стопов советник полностью сам отвечает за отслеживание момента движения рынка и за проверку, пробит ли стоп-уровень. Рисунок ниже показывает общую схему операции. Как только цена пробивает стоп-уровень, советник выполняет соответствующую операцию закрытия.

OrderStop Checking (virtual)

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

COrderStop checking (pending order stop)

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

Примеры

Пример №1: советник, использующий Heiken Ashi и Moving Average, с одним стоп-уровнем (главным стопом)

Для большинства экспертов чаще всего достаточно одного стоп-лосса и одного тейк-профита. Сейчас мы дополним пример из предыдущей статьи, добавив в исходный код стоп-лосс и тейк-профит. Чтобы это сделать, сначала создадим новый экземпляр контейнера (CStops). Затем создадим экземпляр CStop, а потом добавим в контейнер его указатель. Указатель на контейнер затем будет добавлен в менеджер ордеров. Код показан ниже:

int OnInit()
  {
//--- other code

   CStops *stops=new CStops();

   CStop *main=new CStop("main");
   main.StopType(stop_type_main);
   main.VolumeType(VOLUME_TYPE_PERCENT_TOTAL);
   main.Main(true);
   main.StopLoss(stop_loss);
   main.TakeProfit(take_profit);
   stops.Add(GetPointer(main));
   
   order_manager.AddStops(GetPointer(stops));     
//--- other code
  }

Тестирование брокерского стопа в MetaTrader 4 показывает результаты, представленные в таблице ниже.

# Время Тип Ордер Объем Цена S / L T / P Прибыль Баланс
1. 2017.01.03 10:00 продажа 1. 0.30 1.04597 1.05097 1.04097
2 2017.01.03 11:34 t/p 1. 0.30 1.04097 1.05097 1.04097 150.00 3150.00
3 2017.01.05 11:00 продажа 2 0.30 1.05149 1.05649 1.04649
4 2017.01.05 17:28 s/l 2 0.30 1.05649 1.05649 1.04649 -150.00 3000.00

Для отложенных стопов уровни размещаются как и стандартные стоп-лосс/тейк-профит, но в форме отложенных ордеров. Советник выполняет операцию закрытия встречной сделкой, выходя из основной сделки объемом, указанным в сработавшем ордере. Но, в отличие от стандартного стоп-лосса/тейк-профита, советник выполняет это на клиентской стороне (в терминале). То есть, операция не сможет быть выполнена, если торговая платформа закрыта — советник должен быть запущен на работающем графике.

# Время Тип Ордер Объем Цена S / L T / P Прибыль Баланс
1. 2017.01.03 10:00 продажа 1. 0.30 1.04597 0.00000 0.00000
2 2017.01.03 10:00 buy stop 2 0.30 1.05097 0.00000 0.00000
3 2017.01.03 10:00 buy limit 3 0.30 1.04097 0.00000 0.00000
4 2017.01.03 11:34 Покупка 3 0.30 1.04097 0.00000 0.00000
5 2017.01.03 11:34 close by 1. 0.30 1.04097 0.00000 0.00000 150.00 3150.00
6 2017.01.03 11:34 close by 3 0.00 1.04097 0.00000 0.00000 0.00 3150.00
7 2017.01.03 11:34 delete 2 0.30 1.05097 0.00000 0.00000
8 2017.01.05 11:00 продажа 4 0.30 1.05149 0.00000 0.00000
9 2017.01.05 11:00 buy stop 5 0.30 1.05649 0.00000 0.00000
10 2017.01.05 11:00 buy limit 6 0.30 1.04649 0.00000 0.00000
11 2017.01.05 17:28 Покупка 5 0.30 1.05649 0.00000 0.00000
12 2017.01.05 17:28 close by 4 0.30 1.05649 0.00000 0.00000 -150.00 3000.00
13 2017.01.05 17:28 close by 5 0.00 1.05649 0.00000 0.00000 0.00 3000.00
14 2017.01.05 17:28 delete 6 0.30 1.04649 0.00000 0.00000


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

# Время Тип Ордер Объем Цена S / L T / P Прибыль Баланс
1. 2017.01.03 10:00 продажа 1. 0.30 1.04597 0.00000 0.00000
2 2017.01.03 11:34 Закрытие 1. 0.30 1.04097 0.00000 0.00000 150.00 3150.00
3 2017.01.05 11:00 продажа 2 0.30 1.05149 0.00000 0.00000
4 2017.01.05 17:28 Закрытие 2 0.30 1.05649 0.00000 0.00000 -150.00 3000.00


Теперь давайте рассмотрим MetaTrader 5. Режим хеджирования MetaTrader 5 в плане окончательного результата гораздо ближе к MetaTrader 4. Нижеследующая таблица показывает результаты тестирования для брокерских стопов. Здесь мы можем подробно рассмотреть уровни стоп-лосса и тейк-профита основной сделки в соответствующих им колонках.













Ордера
Время открытия Ордер Символ Тип Объём Цена S / L T / P Время Состояние Комментарий
2017.01.03 10:00:00 2 EURUSD продажа 0.30 / 0.30 1.04597 1.05097 1.04097 2017.01.03 10:00:00 заполнение
2017.01.03 11:34:38 3 EURUSD Покупка 0.30 / 0.30 1.04097

2017.01.03 11:34:38 заполнение tp 1.04097
2017.01.05 11:00:00 4 EURUSD продажа 0.30 / 0.30 1.05149 1.05649 1.04649 2017.01.05 11:00:00 заполнение
2017.01.05 17:28:37 5 EURUSD Покупка 0.30 / 0.30 1.05649

2017.01.05 17:28:37 заполнение sl 1.05649

Сделки
Время Сделка Символ Тип Направление Объём Цена Ордер Комиссия Своп Прибыль Баланс Комментарий
2017.01.01 00:00:00 1.
balance



0.00 0.00 3 000.00 3 000.00
2017.01.03 10:00:00 2 EURUSD продажа in 0.30 1.04597 2 0.00 0.00 0.00 3 000.00
2017.01.03 11:34:38 3 EURUSD Покупка out 0.30 1.04097 3 0.00 0.00 150.00 3 150.00 tp 1.04097
2017.01.05 11:00:00 4 EURUSD продажа in 0.30 1.05149 4 0.00 0.00 0.00 3 150.00
2017.01.05 17:28:37 5 EURUSD Покупка out 0.30 1.05649 5 0.00 0.00 -150.00 3 000.00 sl 1.05649

0.00 0.00 0.00 3 000.00

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














Ордера
Время открытия Ордер Символ Тип Объём Цена S / L T / P Время Состояние Комментарий
2017.01.03 10:00:00 2 EURUSD продажа 0.30 / 0.30 1.04597

2017.01.03 10:00:00 заполнение
2017.01.03 10:00:00 3 EURUSD buy stop 0.30 / 0.00 1.05097

2017.01.03 11:34:38 canceled
2017.01.03 10:00:00 4 EURUSD buy limit 0.30 / 0.30 1.04097

2017.01.03 11:34:38 заполнение
2017.01.03 11:34:38 5 EURUSD close by 0.30 / 0.30 1.04097

2017.01.03 11:34:38 заполнение close #2 by #4
2017.01.05 11:00:00 6 EURUSD продажа 0.30 / 0.30 1.05149

2017.01.05 11:00:00 заполнение
2017.01.05 11:00:00 7 EURUSD buy stop 0.30 / 0.30 1.05649

2017.01.05 17:28:37 заполнение
2017.01.05 11:00:00 8 EURUSD buy limit 0.30 / 0.00 1.04649

2017.01.05 17:28:37 canceled
2017.01.05 17:28:37 9 EURUSD close by 0.30 / 0.30 1.05649

2017.01.05 17:28:37 заполнение close #6 by #7

Сделки
Время Сделка Символ Тип Направление Объём Цена Ордер Комиссия Своп Прибыль Баланс Комментарий
2017.01.01 00:00:00 1.
balance



0.00 0.00 3 000.00 3 000.00
2017.01.03 10:00:00 2 EURUSD продажа in 0.30 1.04597 2 0.00 0.00 0.00 3 000.00
2017.01.03 11:34:38 3 EURUSD Покупка in 0.30 1.04097 4 0.00 0.00 0.00 3 000.00
2017.01.03 11:34:38 4 EURUSD Покупка out by 0.30 1.04097 5 0.00 0.00 150.00 3 150.00 close #2 by #4
2017.01.03 11:34:38 5 EURUSD продажа out by 0.30 1.04597 5 0.00 0.00 0.00 3 150.00 close #2 by #4
2017.01.05 11:00:00 6 EURUSD продажа in 0.30 1.05149 6 0.00 0.00 0.00 3 150.00
2017.01.05 17:28:37 7 EURUSD Покупка in 0.30 1.05649 7 0.00 0.00 0.00 3 150.00
2017.01.05 17:28:37 9 EURUSD продажа out by 0.30 1.05149 9 0.00 0.00 0.00 3 150.00 close #6 by #7
2017.01.05 17:28:37 8 EURUSD Покупка out by 0.30 1.05649 9 0.00 0.00 -150.00 3 000.00 close #6 by #7

0.00 0.00 0.00 3 000.00

Используя виртуальные (скрытые) стопы, мы не видим типичных меток "close", как в MetaTrader 4. Вместо этого операция закрытия использует другой способ: открытие позиции в противоположном направлении, но мы можем видеть это в истории сделок, вне зависимости от того, сделка это на покупку или на продажу.














Ордера
Время открытия Ордер Символ Тип Объём Цена S / L T / P Время Состояние Комментарий
2017.01.03 10:00:00 2 EURUSD продажа 0.30 / 0.30 1.04597

2017.01.03 10:00:00 заполнение
2017.01.03 11:34:38 3 EURUSD Покупка 0.30 / 0.30 1.04097

2017.01.03 11:34:38 заполнение
2017.01.05 11:00:00 4 EURUSD продажа 0.30 / 0.30 1.05149

2017.01.05 11:00:00 заполнение
2017.01.05 17:28:37 5 EURUSD Покупка 0.30 / 0.30 1.05649

2017.01.05 17:28:37 заполнение

Сделки
Время Сделка Символ Тип Направление Объём Цена Ордер Комиссия Своп Прибыль Баланс Комментарий
2017.01.01 00:00:00 1.
balance



0.00 0.00 3 000.00 3 000.00
2017.01.03 10:00:00 2 EURUSD продажа in 0.30 1.04597 2 0.00 0.00 0.00 3 000.00
2017.01.03 11:34:38 3 EURUSD Покупка out 0.30 1.04097 3 0.00 0.00 150.00 3 150.00
2017.01.05 11:00:00 4 EURUSD продажа in 0.30 1.05149 4 0.00 0.00 0.00 3 150.00
2017.01.05 17:28:37 5 EURUSD Покупка out 0.30 1.05649 5 0.00 0.00 -150.00 3 000.00

0.00 0.00 0.00 3 000.00

В неттинговом режиме, поскольку MetaTrader 5 использует для этого глобальные стоп-лоссы и тейк-профиты (применимые ко всему объему позиции), советник должен использовать отложенные ордера, чтобы создать отдельные стоп-уровни. Как мы уже обсуждали выше, в режиме хеджирования брокерские стопы будут обработаны как стопы на основании отложенных ордеров, как показано в таблице:













Ордера
Время открытия Ордер Символ Тип Объём Цена S / L T / P Время Состояние Комментарий
2017.01.03 10:00:00 2 EURUSD продажа 0.30 / 0.30 1.04597

2017.01.03 10:00:00 заполнение
2017.01.03 10:00:00 3 EURUSD buy stop 0.30 / 0.00 1.05097

2017.01.03 11:34:38 canceled
2017.01.03 10:00:00 4 EURUSD buy limit 0.30 / 0.30 1.04097

2017.01.03 11:34:38 заполнение
2017.01.05 11:00:00 5 EURUSD продажа 0.30 / 0.30 1.05149

2017.01.05 11:00:00 заполнение
2017.01.05 11:00:00 6 EURUSD buy stop 0.30 / 0.30 1.05649

2017.01.05 17:28:37 заполнение
2017.01.05 11:00:00 7 EURUSD buy limit 0.30 / 0.00 1.04649

2017.01.05 17:28:37 canceled

Сделки
Время Сделка Символ Тип Направление Объём Цена Ордер Комиссия Своп Прибыль Баланс Комментарий
2017.01.01 00:00:00 1.
balance



0.00 0.00 3 000.00 3 000.00
2017.01.03 10:00:00 2 EURUSD продажа in 0.30 1.04597 2 0.00 0.00 0.00 3 000.00
2017.01.03 11:34:38 3 EURUSD Покупка out 0.30 1.04097 4 0.00 0.00 150.00 3 150.00
2017.01.05 11:00:00 4 EURUSD продажа in 0.30 1.05149 5 0.00 0.00 0.00 3 150.00
2017.01.05 17:28:37 5 EURUSD Покупка out 0.30 1.05649 6 0.00 0.00 -150.00 3 000.00

0.00 0.00 0.00 3 000.00

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













Ордера
Время открытия Ордер Символ Тип Объём Цена S / L T / P Время Состояние Комментарий
2017.01.03 10:00:00 2 EURUSD продажа 0.30 / 0.30 1.04597

2017.01.03 10:00:00 заполнение
2017.01.03 10:00:00 3 EURUSD buy stop 0.30 / 0.00 1.05097

2017.01.03 11:34:38 canceled
2017.01.03 10:00:00 4 EURUSD buy limit 0.30 / 0.30 1.04097

2017.01.03 11:34:38 заполнение
2017.01.05 11:00:00 5 EURUSD продажа 0.30 / 0.30 1.05149

2017.01.05 11:00:00 заполнение
2017.01.05 11:00:00 6 EURUSD buy stop 0.30 / 0.30 1.05649

2017.01.05 17:28:37 заполнение
2017.01.05 11:00:00 7 EURUSD buy limit 0.30 / 0.00 1.04649

2017.01.05 17:28:37 canceled

Сделки
Время Сделка Символ Тип Направление Объём Цена Ордер Комиссия Своп Прибыль Баланс Комментарий
2017.01.01 00:00:00 1.
balance



0.00 0.00 3 000.00 3 000.00
2017.01.03 10:00:00 2 EURUSD продажа in 0.30 1.04597 2 0.00 0.00 0.00 3 000.00
2017.01.03 11:34:38 3 EURUSD Покупка out 0.30 1.04097 4 0.00 0.00 150.00 3 150.00
2017.01.05 11:00:00 4 EURUSD продажа in 0.30 1.05149 5 0.00 0.00 0.00 3 150.00
2017.01.05 17:28:37 5 EURUSD Покупка out 0.30 1.05649 6 0.00 0.00 -150.00 3 000.00

0.00 0.00 0.00 3 000.00

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














Ордера
Время открытия Ордер Символ Тип Объём Цена S / L T / P Время Состояние Комментарий
2017.01.03 10:00:00 2 EURUSD продажа 0.30 / 0.30 1.04597

2017.01.03 10:00:00 заполнение
2017.01.03 11:34:38 3 EURUSD Покупка 0.30 / 0.30 1.04097

2017.01.03 11:34:38 заполнение
2017.01.05 11:00:00 4 EURUSD продажа 0.30 / 0.30 1.05149

2017.01.05 11:00:00 заполнение
2017.01.05 17:28:37 5 EURUSD Покупка 0.30 / 0.30 1.05649

2017.01.05 17:28:37 заполнение

Сделки
Время Сделка Символ Тип Направление Объём Цена Ордер Комиссия Своп Прибыль Баланс Комментарий
2017.01.01 00:00:00 1.
balance



0.00 0.00 3 000.00 3 000.00
2017.01.03 10:00:00 2 EURUSD продажа in 0.30 1.04597 2 0.00 0.00 0.00 3 000.00
2017.01.03 11:34:38 3 EURUSD Покупка out 0.30 1.04097 3 0.00 0.00 150.00 3 150.00
2017.01.05 11:00:00 4 EURUSD продажа in 0.30 1.05149 4 0.00 0.00 0.00 3 150.00
2017.01.05 17:28:37 5 EURUSD Покупка out 0.30 1.05649 5 0.00 0.00 -150.00 3 000.00

0.00 0.00 0.00 3 000.00

Пример №2: советник с использованием Heiken Ashi и Moving Average, с тремя стоп-уровнями

Сложные советники часто требуют более чем по одному стоп-лоссу и тейк-профиту. Мы используем тот же метод, что описан в предыдущем примере, чтобы добавить дополнительные стоп-уровни, которые назовем "stop1" и "stop2":

int OnInit()
  {
//--- other code
  
   CStops *stops=new CStops();

   CStop *main=new CStop("main");
   main.StopType(stop_type_main);
   main.VolumeType(VOLUME_TYPE_PERCENT_TOTAL);
   main.Main(true);
   main.StopLoss(stop_loss);
   main.TakeProfit(take_profit);
   stops.Add(GetPointer(main));
   
   CStop *stop1=new CStop("stop1");
   stop1.StopType(stop_type1);
   stop1.VolumeType(VOLUME_TYPE_PERCENT_TOTAL);
   stop1.Volume(0.35);
   stop1.StopLoss(stop_loss1);
   stop1.TakeProfit(take_profit1);
   stops.Add(GetPointer(stop1));
   
   CStop *stop2=new CStop("stop2");
   stop2.StopType(stop_type2);
   stop2.VolumeType(VOLUME_TYPE_PERCENT_TOTAL);
   stop2.Volume(0.35);
   stop2.StopLoss(stop_loss2);
   stop2.TakeProfit(take_profit2);
   stops.Add(GetPointer(stop2));
   
   order_manager.AddStops(GetPointer(stops));

//--- other code
  }

Таблица ниже показывает результаты тестирования на MetaTrader 4:

# Время Тип Ордер Объем Цена S / L T / P Прибыль Баланс
1. 2017.01.03 10:00 продажа 1. 0.30 1.04597 1.05097 1.04097
2 2017.01.03 10:00 buy stop 2 0.11 1.04847 0.00000 0.00000
3 2017.01.03 10:00 buy limit 3 0.11 1.04347 0.00000 0.00000
4 2017.01.03 10:21 Покупка 3 0.11 1.04347 0.00000 0.00000
5 2017.01.03 10:21 close by 1. 0.11 1.04347 1.05097 1.04097 27.50 3027.50
6 2017.01.03 10:21 продажа 4 0.19 1.04597 1.05097 1.04097
7 2017.01.03 10:21 close by 3 0.00 1.04347 0.00000 0.00000 0.00 3027.50
8 2017.01.03 10:21 delete 2 0.11 1.04847 0.00000 0.00000
9 2017.01.03 10:34 Закрытие 4 0.11 1.04247 1.05097 1.04097 38.50 3066.00
10 2017.01.03 10:34 продажа 5 0.08 1.04597 1.05097 1.04097
11 2017.01.03 11:34 t/p 5 0.08 1.04097 1.05097 1.04097 40.00 3106.00
12 2017.01.05 11:00 продажа 6 0.30 1.05149 1.05649 1.04649
13 2017.01.05 11:00 buy stop 7 0.11 1.05399 0.00000 0.00000
14 2017.01.05 11:00 buy limit 8 0.11 1.04899 0.00000 0.00000
15 2017.01.05 12:58 Покупка 8 0.11 1.04899 0.00000 0.00000
16 2017.01.05 12:58 close by 6 0.11 1.04899 1.05649 1.04649 27.50 3133.50
17 2017.01.05 12:58 продажа 9 0.19 1.05149 1.05649 1.04649
18 2017.01.05 12:58 close by 8 0.00 1.04899 0.00000 0.00000 0.00 3133.50
19 2017.01.05 12:58 delete 7 0.11 1.05399 0.00000 0.00000
20 2017.01.05 16:00 Закрытие 9 0.19 1.05314 1.05649 1.04649 -31.35 3102.15
21 2017.01.05 16:00 Покупка 10 0.30 1.05314 1.04814 1.05814
22 2017.01.05 16:00 sell stop 11 0.11 1.05064 0.00000 0.00000
23 2017.01.05 16:00 sell limit 12 0.11 1.05564 0.00000 0.00000
Торговля 2017.01.05 17:09 продажа 12 0.11 1.05564 0.00000 0.00000
25 2017.01.05 17:09 close by 10 0.11 1.05564 1.04814 1.05814 27.50 3129.65
26 2017.01.05 17:09 Покупка 13 0.19 1.05314 1.04814 1.05814
27 2017.01.05 17:09 close by 12 0.00 1.05564 0.00000 0.00000 0.00 3129.65
28 2017.01.05 17:09 delete 11 0.11 1.05064 0.00000 0.00000
29 2017.01.05 17:28 Закрытие 13 0.11 1.05664 1.04814 1.05814 38.50 3168.15
30- 2017.01.05 17:28 Покупка 14 0.08 1.05314 1.04814 1.05814
31 2017.01.05 17:40 t/p 14 0.08 1.05814 1.04814 1.05814 40.00 3208.15


Как продемонстрировала таблица выше, все три стоп-уровня сработали для первой сделки. Для виртуального стопа советник выполняет частичное закрытие основной сделки, как мы и ожидали. Для стоп-уровня с использованием отложенного ордера, как только он сработал, советник выполнил операцию закрытия встречной и вычел ее объем из основной сделки. И, наконец, для главного стоп-уровня, которым был брокерский, основная сделка была закрыта полным объемом в 0,08 лота.

Таблица ниже показывает результаты тестирования в хеджинговом режиме MetaTrader 5.














Ордера
Время открытия Ордер Символ Тип Объём Цена S / L T / P Время Состояние Комментарий
2017.01.03 10:00:00 2 EURUSD продажа 0.30 / 0.30 1.04597 1.05097 1.04097 2017.01.03 10:00:00 заполнение
2017.01.03 10:00:00 3 EURUSD buy stop 0.11 / 0.00 1.04847

2017.01.03 10:21:32 canceled
2017.01.03 10:00:00 4 EURUSD buy limit 0.11 / 0.11 1.04347

2017.01.03 10:21:32 заполнение
2017.01.03 10:21:32 5 EURUSD close by 0.11 / 0.11 1.04347

2017.01.03 10:21:32 заполнение close #2 by #4
2017.01.03 10:33:40 6 EURUSD Покупка 0.11 / 0.11 1.04247

2017.01.03 10:33:40 заполнение
2017.01.03 11:34:38 7 EURUSD Покупка 0.08 / 0.08 1.04097

2017.01.03 11:34:38 заполнение tp 1.04097
2017.01.05 11:00:00 8 EURUSD продажа 0.30 / 0.30 1.05149 1.05649 1.04649 2017.01.05 11:00:00 заполнение
2017.01.05 11:00:00 9 EURUSD buy stop 0.11 / 0.00 1.05399

2017.01.05 12:58:27 canceled
2017.01.05 11:00:00 10 EURUSD buy limit 0.11 / 0.11 1.04899

2017.01.05 12:58:27 заполнение
2017.01.05 12:58:27 11 EURUSD close by 0.11 / 0.11 1.04896

2017.01.05 12:58:27 заполнение close #8 by #10
2017.01.05 16:00:00 12 EURUSD Покупка 0.19 / 0.19 1.05307

2017.01.05 16:00:00 заполнение
2017.01.05 16:00:00 13 EURUSD Покупка 0.30 / 0.30 1.05307 1.04807 1.05807 2017.01.05 16:00:00 заполнение
2017.01.05 16:00:00 14 EURUSD sell stop 0.11 / 0.00 1.05057

2017.01.05 17:09:40 canceled
2017.01.05 16:00:00 15 EURUSD sell limit 0.11 / 0.11 1.05557

2017.01.05 17:09:40 заполнение
2017.01.05 17:09:40 16 EURUSD close by 0.11 / 0.11 1.05557

2017.01.05 17:09:40 заполнение close #13 by #15
2017.01.05 17:28:47 17 EURUSD продажа 0.11 / 0.11 1.05660

2017.01.05 17:28:47 заполнение
2017.01.05 17:29:15 18 EURUSD продажа 0.08 / 0.08 1.05807

2017.01.05 17:29:15 заполнение tp 1.05807

Сделки
Время Сделка Символ Тип Направление Объём Цена Ордер Комиссия Своп Прибыль Баланс Комментарий
2017.01.01 00:00:00 1.
balance



0.00 0.00 3 000.00 3 000.00
2017.01.03 10:00:00 2 EURUSD продажа in 0.30 1.04597 2 0.00 0.00 0.00 3 000.00
2017.01.03 10:21:32 3 EURUSD Покупка in 0.11 1.04347 4 0.00 0.00 0.00 3 000.00
2017.01.03 10:21:32 4 EURUSD Покупка out by 0.11 1.04347 5 0.00 0.00 27.50 3 027.50 close #2 by #4
2017.01.03 10:21:32 5 EURUSD продажа out by 0.11 1.04597 5 0.00 0.00 0.00 3 027.50 close #2 by #4
2017.01.03 10:33:40 6 EURUSD Покупка out 0.11 1.04247 6 0.00 0.00 38.50 3 066.00
2017.01.03 11:34:38 7 EURUSD Покупка out 0.08 1.04097 7 0.00 0.00 40.00 3 106.00 tp 1.04097
2017.01.05 11:00:00 8 EURUSD продажа in 0.30 1.05149 8 0.00 0.00 0.00 3 106.00
2017.01.05 12:58:27 9 EURUSD Покупка in 0.11 1.04896 10 0.00 0.00 0.00 3 106.00
2017.01.05 12:58:27 10 EURUSD Покупка out by 0.11 1.04896 11 0.00 0.00 27.83 3 133.83 close #8 by #10
2017.01.05 12:58:27 11 EURUSD продажа out by 0.11 1.05149 11 0.00 0.00 0.00 3 133.83 close #8 by #10
2017.01.05 16:00:00 12 EURUSD Покупка out 0.19 1.05307 12 0.00 0.00 -30.02 3 103.81
2017.01.05 16:00:00 13 EURUSD Покупка in 0.30 1.05307 13 0.00 0.00 0.00 3 103.81
2017.01.05 17:09:40 14 EURUSD продажа in 0.11 1.05557 15 0.00 0.00 0.00 3 103.81
2017.01.05 17:09:40 16 EURUSD Покупка out by 0.11 1.05307 16 0.00 0.00 0.00 3 103.81 close #13 by #15
2017.01.05 17:09:40 15 EURUSD продажа out by 0.11 1.05557 16 0.00 0.00 27.50 3 131.31 close #13 by #15
2017.01.05 17:28:47 17 EURUSD продажа out 0.11 1.05660 17 0.00 0.00 38.83 3 170.14
2017.01.05 17:29:15 18 EURUSD продажа out 0.08 1.05807 18 0.00 0.00 40.00 3 210.14 tp 1.05807

0.00 0.00 210.14 3 210.14

Как можно увидеть из таблицы выше, советник работает примерно так же, как в хеджинговом режиме MetaTrader 5. Механизм был таким же, как в MetaTrader 4 для трех типов стоп-уровней.

Таблица ниже демонстрирует результаты тестирования в неттинговом режиме MetaTrader 5.














Ордера
Время открытия Ордер Символ Тип Объём Цена S / L T / P Время Состояние Комментарий
2017.01.03 10:00:00 2 EURUSD продажа 0.30 / 0.30 1.04597

2017.01.03 10:00:00 заполнение
2017.01.03 10:00:00 3 EURUSD buy stop 0.30 / 0.00 1.05097

2017.01.03 11:34:38 canceled
2017.01.03 10:00:00 4 EURUSD buy limit 0.30 / 0.30 1.04097

2017.01.03 11:34:38 заполнение
2017.01.03 10:00:00 5 EURUSD buy stop 0.11 / 0.00 1.04847

2017.01.03 10:21:32 canceled
2017.01.03 10:00:00 6 EURUSD buy limit 0.11 / 0.11 1.04347

2017.01.03 10:21:32 заполнение
2017.01.03 10:33:40 7 EURUSD Покупка 0.11 / 0.11 1.04247

2017.01.03 10:33:40 заполнение
2017.01.05 11:00:00 8 EURUSD продажа 0.30 / 0.30 1.05149

2017.01.05 11:00:00 заполнение
2017.01.05 11:00:00 9 EURUSD buy stop 0.30 / 0.00 1.05649

2017.01.05 16:00:00 canceled
2017.01.05 11:00:00 10 EURUSD buy limit 0.30 / 0.00 1.04649

2017.01.05 16:00:00 canceled
2017.01.05 11:00:00 11 EURUSD buy stop 0.11 / 0.00 1.05399

2017.01.05 12:58:27 canceled
2017.01.05 11:00:00 12 EURUSD buy limit 0.11 / 0.11 1.04899

2017.01.05 12:58:27 заполнение
2017.01.05 16:00:00 13 EURUSD Покупка 0.19 / 0.19 1.05307

2017.01.05 16:00:00 заполнение
2017.01.05 16:00:00 14 EURUSD Покупка 0.30 / 0.30 1.05307

2017.01.05 16:00:00 заполнение
2017.01.05 16:00:00 15 EURUSD sell stop 0.30 / 0.00 1.04807

2017.01.05 17:29:15 canceled
2017.01.05 16:00:00 16 EURUSD sell limit 0.30 / 0.30 1.05807

2017.01.05 17:29:15 заполнение
2017.01.05 16:00:00 17 EURUSD sell stop 0.11 / 0.00 1.05057

2017.01.05 17:09:40 canceled
2017.01.05 16:00:00 18 EURUSD sell limit 0.11 / 0.11 1.05557

2017.01.05 17:09:40 заполнение
2017.01.05 17:28:47 19 EURUSD продажа 0.11 / 0.11 1.05660

2017.01.05 17:28:47 заполнение

Сделки
Время Сделка Символ Тип Направление Объём Цена Ордер Комиссия Своп Прибыль Баланс Комментарий
2017.01.01 00:00:00 1.
balance



0.00 0.00 3 000.00 3 000.00
2017.01.03 10:00:00 2 EURUSD продажа in 0.30 1.04597 2 0.00 0.00 0.00 3 000.00
2017.01.03 11:34:38 5 EURUSD Покупка in/out 0.30 1.04097 4 0.00 0.00 40.00 3 040.00
2017.01.03 10:21:32 3 EURUSD Покупка out 0.11 1.04347 6 0.00 0.00 27.50 3 067.50
2017.01.03 10:33:40 4 EURUSD Покупка out 0.11 1.04247 7 0.00 0.00 38.50 3 106.00
2017.01.05 11:00:00 6 EURUSD продажа in/out 0.30 1.05149 8 0.00 -0.61 231.44 3 336.83
2017.01.05 12:58:27 7 EURUSD Покупка in/out 0.11 1.04896 12 0.00 0.00 20.24 3 357.07
2017.01.05 16:00:00 8 EURUSD Покупка in 0.19 1.05307 13 0.00 0.00 0.00 3 357.07
2017.01.05 16:00:00 9 EURUSD Покупка in 0.30 1.05307 14 0.00 0.00 0.00 3 357.07
2017.01.05 17:29:15 12 EURUSD продажа out 0.30 1.05807 16 0.00 0.00 157.11 3 514.18
2017.01.05 17:09:40 10 EURUSD продажа out 0.11 1.05557 18 0.00 0.00 30.11 3 544.29
2017.01.05 17:28:47 11 EURUSD продажа out 0.11 1.05660 19 0.00 0.00 41.44 3 585.73

0.00 -0.61 586.34 3 585.73

Здесь мы столкнулись с проблемой. Окончательный стоп-уровень закрыл 0,3 лота вместо 0,08, как наблюдалось в двух предыдущих тестах.

Как мы говорили выше, стандартные стоп-лосс и тейк-профит в MetaTrader 5 (неттинг) отличаются от таковых в двух других режимах. В отличие от них, советник конвертирует брокерский стоп в стоп на основе отложенного ордера. Но с такой настройкой советник уже имеет два стоп-уровня на основе отложенных ордеров, и один из них является основным. Как также объяснялось выше, это может привести к зависшей сделке. Окончательный (или основной) стоп-уровень всегда будет иметь объем, эквивалентный начальному объему основной сделки. И поскольку вводятся другие стоп-уровни, это может привести к закрытию позиции основным стопом, причем большим объемом, чем начальный.

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














Ордера
Время открытия Ордер Символ Тип Объём Цена S / L T / P Время Состояние Комментарий
2017.01.03 10:00:00 2 EURUSD продажа 0.30 / 0.30 1.04597

2017.01.03 10:00:00 заполнение
2017.01.03 10:00:00 3 EURUSD buy stop 0.11 / 0.00 1.04847

2017.01.03 10:21:32 canceled
2017.01.03 10:00:00 4 EURUSD buy limit 0.11 / 0.11 1.04347

2017.01.03 10:21:32 заполнение
2017.01.03 10:33:40 5 EURUSD Покупка 0.11 / 0.11 1.04247

2017.01.03 10:33:40 заполнение
2017.01.03 11:34:38 6 EURUSD Покупка 0.08 / 0.08 1.04097

2017.01.03 11:34:38 заполнение
2017.01.05 11:00:00 7 EURUSD продажа 0.30 / 0.30 1.05149

2017.01.05 11:00:00 заполнение
2017.01.05 11:00:00 8 EURUSD buy stop 0.11 / 0.00 1.05399

2017.01.05 12:58:27 canceled
2017.01.05 11:00:00 9 EURUSD buy limit 0.11 / 0.11 1.04899

2017.01.05 12:58:27 заполнение
2017.01.05 16:00:00 10 EURUSD Покупка 0.19 / 0.19 1.05307

2017.01.05 16:00:00 заполнение
2017.01.05 16:00:00 11 EURUSD Покупка 0.30 / 0.30 1.05307

2017.01.05 16:00:00 заполнение
2017.01.05 16:00:00 12 EURUSD sell stop 0.11 / 0.00 1.05057

2017.01.05 17:09:40 canceled
2017.01.05 16:00:00 13 EURUSD sell limit 0.11 / 0.11 1.05557

2017.01.05 17:09:40 заполнение
2017.01.05 17:28:47 14 EURUSD продажа 0.11 / 0.11 1.05660

2017.01.05 17:28:47 заполнение
2017.01.05 17:29:15 15 EURUSD продажа 0.08 / 0.08 1.05807

2017.01.05 17:29:15 заполнение

Сделки
Время Сделка Символ Тип Направление Объём Цена Ордер Комиссия Своп Прибыль Баланс Комментарий
2017.01.01 00:00:00 1.
balance



0.00 0.00 3 000.00 3 000.00
2017.01.03 10:00:00 2 EURUSD продажа in 0.30 1.04597 2 0.00 0.00 0.00 3 000.00
2017.01.03 10:21:32 3 EURUSD Покупка out 0.11 1.04347 4 0.00 0.00 27.50 3 027.50
2017.01.03 10:33:40 4 EURUSD Покупка out 0.11 1.04247 5 0.00 0.00 38.50 3 066.00
2017.01.03 11:34:38 5 EURUSD Покупка out 0.08 1.04097 6 0.00 0.00 40.00 3 106.00
2017.01.05 11:00:00 6 EURUSD продажа in 0.30 1.05149 7 0.00 0.00 0.00 3 106.00
2017.01.05 12:58:27 7 EURUSD Покупка out 0.11 1.04896 9 0.00 0.00 27.83 3 133.83
2017.01.05 16:00:00 8 EURUSD Покупка out 0.19 1.05307 10 0.00 0.00 -30.02 3 103.81
2017.01.05 16:00:00 9 EURUSD Покупка in 0.30 1.05307 11 0.00 0.00 0.00 3 103.81
2017.01.05 17:09:40 10 EURUSD продажа out 0.11 1.05557 13 0.00 0.00 27.50 3 131.31
2017.01.05 17:28:47 11 EURUSD продажа out 0.11 1.05660 14 0.00 0.00 38.83 3 170.14
2017.01.05 17:29:15 12 EURUSD продажа out 0.08 1.05807 15 0.00 0.00 40.00 3 210.14

0.00 0.00 210.14 3 210.14

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

Пример #3: Стопы с мани-менеджментом

В одной из предыдущих статей уже обсуждалось, что некоторые методы мани-менеджмента зависят от определенного стоп-уровня (обычно это стоп-лосс, но иногда используется и тейк-профит). Методы мани-менеджмента — такие как фиксированно-фракционный, метод фиксированного риска и фиксированного риска на пункт/пипс — часто требуют конечного уровня стоп-лосса. Если этот уровень не устанавливать, то предполагается очень большой (или даже бесконечный) риск, а следовательно, и рассчитанный объем тоже будет очень большим. Чтобы продемонстрировать эксперта, способного использовать описанные в этой статье объекты класса с мани-менеджментом, мы модифицируем первый пример таким образом, чтобы ранее закомментированные строки кода были включены в компиляцию.

Сначала удалим тэги комментирования из строк кода для методов мани-менеджмента, как показано в коде ниже, внутри функции OnInit:

int OnInit()
  {
//--- other code
   order_manager=new COrderManager();
   money_manager= new CMoneys();
   CMoney *money_fixed=new CMoneyFixedLot(0.05);
   CMoney *money_ff=new CMoneyFixedFractional(5);
   CMoney *money_ratio=new CMoneyFixedRatio(0,0.1,1000);
   CMoney *money_riskperpoint=new CMoneyFixedRiskPerPoint(0.1);
   CMoney *money_risk=new CMoneyFixedRisk(100);

   money_manager.Add(money_fixed);
   money_manager.Add(money_ff);
   money_manager.Add(money_ratio);
   money_manager.Add(money_riskperpoint);
   money_manager.Add(money_risk);
   order_manager.AddMoneys(money_manager);
//--- other code
  }

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

enum ENUM_MM_TYPE
  {
   MM_FIXED=0,
   MM_FIXED_FRACTIONAL,
   MM_FIXED_RATIO,
   MM_FIXED_RISK_PER_POINT,
   MM_FIXED_RISK
  };

Затем объявим новый входной параметр для этого перечисления:

input ENUM_MM_TYPE mm_type=MM_FIXED_FRACTIONAL;

И, наконец, мы должны привязать этот параметр к актуальному выбору метода мани-менеджмента в функции OnTick.

void OnTick()
  {
//---    
   manage_trades();
   if(symbol_info.RefreshRates())
     {
      signals.Check();
      if(signals.CheckOpenLong())
        {
         close_last();
         if(time_filters.Evaluate(TimeCurrent()))
           {
            Print("Entering buy trade..");
            money_manager.Selected((int)mm_type); //use mm_type, cast to 'int' type
            order_manager.TradeOpen(Symbol(),ORDER_TYPE_BUY,symbol_info.Ask());
           }
        }
      else if(signals.CheckOpenShort())
        {
         close_last();
         if(time_filters.Evaluate(TimeCurrent()))
           {
            Print("Entering sell trade..");
            money_manager.Selected((int)mm_type); //use mm_type, cast to 'int' type
            order_manager.TradeOpen(Symbol(),ORDER_TYPE_SELL,symbol_info.Bid());
           }
        }
     }
  }

Поскольку методы мани-менеджмента имеют дело только с чистыми расчетами, у нас не возникает проблем с совместимостью между MQL4 и MQL5. Два предыдущих примера уже показали, как стоп-уровни работают на обеих платформах. Нижеследующие таблицы показывают результаты теста в хеджинговом режиме MetaTrader 5.

Первая таблица показывает результаты теста с использованием фиксированно-фракционного мани-менеджмента. Запрограммирована настройка риска 5% от баланса счета. С начальным балансом в 3000 $ мы ожидаем, что это значение составит около 150 $, если для первой сделки будет достигнут стоп-лосс. Поскольку стоп-лосс и тейк-профит имеют одинаковое значение (500 пунктов), мы ожидаем, что и профит составит 150 долларов по достижении тейк-профита.














Ордера
Время открытия Ордер Символ Тип Объём Цена S / L T / P Время Состояние Комментарий
2017.01.03 10:00:00 2 EURUSD продажа 0.30 / 0.30 1.04597 1.05097 1.04097 2017.01.03 10:00:00 заполнение
2017.01.03 11:34:38 3 EURUSD Покупка 0.30 / 0.30 1.04097

2017.01.03 11:34:38 заполнение tp 1.04097
2017.01.05 11:00:00 4 EURUSD продажа 0.32 / 0.32 1.05149 1.05649 1.04649 2017.01.05 11:00:00 заполнение
2017.01.05 16:00:00 5 EURUSD Покупка 0.32 / 0.32 1.05307

2017.01.05 16:00:00 заполнение
2017.01.05 16:00:00 6 EURUSD Покупка 0.31 / 0.31 1.05307 1.04807 1.05807 2017.01.05 16:00:00 заполнение
2017.01.05 17:29:15 7 EURUSD продажа 0.31 / 0.31 1.05807

2017.01.05 17:29:15 заполнение tp 1.05807

Сделки
Время Сделка Символ Тип Направление Объём Цена Ордер Комиссия Своп Прибыль Баланс Комментарий
2017.01.01 00:00:00 1.
balance



0.00 0.00 3 000.00 3 000.00
2017.01.03 10:00:00 2 EURUSD продажа in 0.30 1.04597 2 0.00 0.00 0.00 3 000.00
2017.01.03 11:34:38 3 EURUSD Покупка out 0.30 1.04097 3 0.00 0.00 150.00 3 150.00 tp 1.04097
2017.01.05 11:00:00 4 EURUSD продажа in 0.32 1.05149 4 0.00 0.00 0.00 3 150.00
2017.01.05 16:00:00 5 EURUSD Покупка out 0.32 1.05307 5 0.00 0.00 -50.56 3 099.44
2017.01.05 16:00:00 6 EURUSD Покупка in 0.31 1.05307 6 0.00 0.00 0.00 3 099.44
2017.01.05 17:29:15 7 EURUSD продажа out 0.31 1.05807 7 0.00 0.00 155.00 3 254.44 tp 1.05807

0.00 0.00 254.44 3 254.44

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

Для мани-менеджмента по фиксированному риску на пункт запрограммированная настройка — риск в 0,1 доллар на пункт стоп-лосса. С настройкой на 500 пунктов по стоп-лоссу и тейк-профиту мы ожидаем, что эти стоп-уровни будут стоить по  50 $ каждый.














Ордера
Время открытия Ордер Символ Тип Объём Цена S / L T / P Время Состояние Комментарий
2017.01.03 10:00:00 2 EURUSD продажа 0.10 / 0.10 1.04597 1.05097 1.04097 2017.01.03 10:00:00 заполнение
2017.01.03 11:34:38 3 EURUSD Покупка 0.10 / 0.10 1.04097

2017.01.03 11:34:38 заполнение tp 1.04097
2017.01.05 11:00:00 4 EURUSD продажа 0.10 / 0.10 1.05149 1.05649 1.04649 2017.01.05 11:00:00 заполнение
2017.01.05 16:00:00 5 EURUSD Покупка 0.10 / 0.10 1.05307

2017.01.05 16:00:00 заполнение
2017.01.05 16:00:00 6 EURUSD Покупка 0.10 / 0.10 1.05307 1.04807 1.05807 2017.01.05 16:00:00 заполнение
2017.01.05 17:29:15 7 EURUSD продажа 0.10 / 0.10 1.05807

2017.01.05 17:29:15 заполнение tp 1.05807

Сделки
Время Сделка Символ Тип Направление Объём Цена Ордер Комиссия Своп Прибыль Баланс Комментарий
2017.01.01 00:00:00 1.
balance



0.00 0.00 3 000.00 3 000.00
2017.01.03 10:00:00 2 EURUSD продажа in 0.10 1.04597 2 0.00 0.00 0.00 3 000.00
2017.01.03 11:34:38 3 EURUSD Покупка out 0.10 1.04097 3 0.00 0.00 50.00 3 050.00 tp 1.04097
2017.01.05 11:00:00 4 EURUSD продажа in 0.10 1.05149 4 0.00 0.00 0.00 3 050.00
2017.01.05 16:00:00 5 EURUSD Покупка out 0.10 1.05307 5 0.00 0.00 -15.80 3 034.20
2017.01.05 16:00:00 6 EURUSD Покупка in 0.10 1.05307 6 0.00 0.00 0.00 3 034.20
2017.01.05 17:29:15 7 EURUSD продажа out 0.10 1.05807 7 0.00 0.00 50.00 3 084.20 tp 1.05807

0.00 0.00 84.20 3 084.20

Для мани-менеджмента по фиксированному риску запрограммирована настройка риска 100 $. Советник, в свою очередь, должен вычислить объем, который соответствует этому риску. Результат показан ниже.














Ордера
Время открытия Ордер Символ Тип Объём Цена S / L T / P Время Состояние Комментарий
2017.01.03 10:00:00 2 EURUSD продажа 0.20 / 0.20 1.04597 1.05097 1.04097 2017.01.03 10:00:00 заполнение
2017.01.03 11:34:38 3 EURUSD Покупка 0.20 / 0.20 1.04097

2017.01.03 11:34:38 заполнение tp 1.04097
2017.01.05 11:00:00 4 EURUSD продажа 0.20 / 0.20 1.05149 1.05649 1.04649 2017.01.05 11:00:00 заполнение
2017.01.05 16:00:00 5 EURUSD Покупка 0.20 / 0.20 1.05307

2017.01.05 16:00:00 заполнение
2017.01.05 16:00:00 6 EURUSD Покупка 0.20 / 0.20 1.05307 1.04807 1.05807 2017.01.05 16:00:00 заполнение
2017.01.05 17:29:15 7 EURUSD продажа 0.20 / 0.20 1.05807

2017.01.05 17:29:15 заполнение tp 1.05807

Сделки
Время Сделка Символ Тип Направление Объём Цена Ордер Комиссия Своп Прибыль Баланс Комментарий
2017.01.01 00:00:00 1.
balance



0.00 0.00 3 000.00 3 000.00
2017.01.03 10:00:00 2 EURUSD продажа in 0.20 1.04597 2 0.00 0.00 0.00 3 000.00
2017.01.03 11:34:38 3 EURUSD Покупка out 0.20 1.04097 3 0.00 0.00 100.00 3 100.00 tp 1.04097
2017.01.05 11:00:00 4 EURUSD продажа in 0.20 1.05149 4 0.00 0.00 0.00 3 100.00
2017.01.05 16:00:00 5 EURUSD Покупка out 0.20 1.05307 5 0.00 0.00 -31.60 3 068.40
2017.01.05 16:00:00 6 EURUSD Покупка in 0.20 1.05307 6 0.00 0.00 0.00 3 068.40
2017.01.05 17:29:15 7 EURUSD продажа out 0.20 1.05807 7 0.00 0.00 100.00 3 168.40 tp 1.05807

0.00 0.00 168.40 3 168.40

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

Заключение

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

Программы, использованные в статье

#
Имя
Тип
Описание параметров
1.
stops_ha_ma1.mqh
Заголовочный файл
Главный заголовочный файл, использованный для советника в первом примере
2.
stops_ha_ma1.mq4 Советник
Основной исходный файл, использованный для советника на MQL4 в первом примере
3.
stops_ha_ma1.mq5 Советник Основной исходный файл, использованный для советника на MQL5 в первом примере
4.  stops_ha_ma2.mqh Заголовочный файл Основной заголовочный файл, использованный для советника во втором примере
5.  stops_ha_ma2.mq4 Советник
Основной исходный файл, использованный для советника на MQL4 во втором примере
6.  stops_ha_ma2.mq5 Советник
Основной исходный файл, использованный для советника на MQL5 во втором примере
7.  stops_ha_ma3.mqh Заголовочный файл Основной заголовочный файл, использованный для советника в третьем примере
8.  stops_ha_ma3.mq4 Советник
Основной исходный файл, использованный для советника на MQL4 в третьем примере
9.  stops_ha_ma3.mq5 Советник
Основной исходный файл, использованный для советника на MQL5 в третьем примере

Файлы классов, созданные в статье

#
Имя
Тип
Описание параметров
1.
MQLx\Base\Stop\StopBase.mqh
Заголовочный файл
CStop (базовый класс)
2.
MQLx\MQL4\Stop\Stop.mqh Заголовочный файл CStop (MQL4 версия)
3.
MQLx\MQL5\Stop\Stop.mqh Заголовочный файл CStop (MQL5 версия)
4. MQLx\Base\Stop\StopsBase.mqh Заголовочный файл CStops (контейнер CStop, базовый класс)
5. MQLx\MQL4\Stop\Stops.mqh Заголовочный файл CStops (MQL4 версия)
6. MQLx\MQL5\Stop\Stops.mqh Заголовочный файл CStops (MQL5 версия)
7. MQLx\Base\Stop\StopLineBase.mqh Заголовочный файл CStopLine (графическое представление, базовый класс)
8. MQLx\MQL4\Stop\StopLine.mqh Заголовочный файл CStopLine (MQL4 версия)
9. MQLx\MQL5\Stop\StopLine.mqh Заголовочный файл CStopLine (MQL5 версия)
10.  MQLx\Base\Order\OrderStopBase.mqh Заголовочный файл COrderStop (базовый класс)
11.  MQLx\MQL4\Order\OrderStop.mqh Заголовочный файл COrderStop (MQL4 версия)
12.  MQLx\MQL5\Order\OrderStop.mqh Заголовочный файл COrderStop (MQL5 версия)
13.
 MQLx\Base\Order\OrderStopVirtualBase.mqh Заголовочный файл
COrderStopVirtual (скрытый, или виртуальный стоп-уровень, базовый класс)
13.  MQLx\Base\Order\OrderStopVirtual.mqh Заголовочный файл
COrderStopVirtual (MQL4 версия)
15.
 MQLx\Base\Order\OrderStopVirtual.mqh Заголовочный файл
COrderStopVirtual (MQL5 версия)
16.  MQLx\Base\Order\OrderStopPendingBase.mqh Заголовочный файл
COrderStopPending (стоп-уровень по отложенному ордеру, базовый класс)
17.  MQLx\Base\Order\OrderStopPending.mqh Заголовочный файл
COrderStopPending (MQL4 версия)
18.
 MQLx\Base\Order\OrderStopPending.mqh Заголовочный файл
COrderStopPending (MQL5 версия)
19.
 MQLx\Base\Order\OrderStopBroker.mqh Заголовочный файл
COrderStopBroker (брокерский стоп-уровень, базовый класс)
20.  MQLx\Base\Order\OrderStopBroker.mqh Заголовочный файл
COrderStopBroker (MQL4 версия)
21.  MQLx\Base\Order\OrderStopBroker.mqh Заголовочный файл
COrderStopBroker (MQL5 версия)
22.  MQLx\Base\Order\OrderStopsBase.mqh Заголовочный файл
COrderStops (контейнер COrderStop, базовый класс)
23.  MQLx\Base\Order\OrderStops.mqh Заголовочный файл
COrderStops (MQL4 версия)
24.  MQLx\Base\Order\OrderStops.mqh Заголовочный файл
COrderStops (MQL5 версия)

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

Прикрепленные файлы |
tester.zip (1445.59 KB)
MQL5.zip (708.29 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (2)
fxsaber
fxsaber | 10 окт. 2017 в 15:30

Как же далек от практики и удобства предложенный кроссплатформенный подход. Как свой громоздкий велосипед - пойдет. Но зачем его публиковать?! Проще написать все полностью свое даже новичку, чем изучать и осваивать этого монстра. Не понимаю.

СБ под MT5 - пример элегантности, по сравнению с данным циклом статей. Да еще и перенесен под MT4.

Viktar Dzemikhau
Viktar Dzemikhau | 25 апр. 2018 в 15:19
fxsaber:

Как же далек от практики и удобства предложенный кроссплатформенный подход. Как свой громоздкий велосипед - пойдет. Но зачем его публиковать?! Проще написать все полностью свое даже новичку, чем изучать и осваивать этого монстра. Не понимаю.

СБ под MT5 - пример элегантности, по сравнению с данным циклом статей. Да еще и перенесен под MT4.

Полностью согласен. Даже будучи прекрасно знакомым с ООП, подход данного автора какой-то слишком извращённый. Слишком много излишеств и вообще не код, а, действительно, "монстр"..

Тестирование паттернов, возникающих при торговле корзинами валютных пар. Часть II Тестирование паттернов, возникающих при торговле корзинами валютных пар. Часть II
Продолжаем тестирование паттернов и проверку методик, описанных в статьях о торговле корзинами валютных пар. Рассмотрим на практике, можно ли использовать паттерны пересечения графиком объединенного WPR скользящей средней, и если можно, то как именно.
Использование фильтра Калмана в прогнозе направления цены Использование фильтра Калмана в прогнозе направления цены
Для успешного трейдинга почти всегда необходимы индикаторы, призванные отделить основное ценовое движение от шумовых колебаний. В этой статье рассматривается один из перспективнейших цифровых фильтров — фильтр Калмана. Описано его построение и использование на практике.
Мини-эмулятор рынка, или Ручной тестер стратегий Мини-эмулятор рынка, или Ручной тестер стратегий
Мини-эмулятор рынка — индикатор, предназначенный для частичной эмуляции работы в терминале. Предположительно, его можно использовать для тестирования "ручных" стратегий анализа и торговли на рынке.
Сравнение различных типов скользящих средних в торговле Сравнение различных типов скользящих средних в торговле
Рассмотрены 7 видов скользящих средних (MA), разработана торговая стратегия по работе с ними. Выполнено тестирование и сравнение различных МА на одной торговой стратегии, дана сравнительная характеристика эффективности применения той или иной скользящей средней.