Кроссплатформенный торговый советник: Стоп-уровни
Оглавление
- Введение
- COrder
- CStop
- CStops
- COrderStop
- COrderStops
- Отображение стоп-уровней на графике
- Проверка ордеров на стоп-уровни
- Примеры
- Заключение
- Программы, использованные в статье
- Файлы классов, созданных в статье
Введение
В предыдущей статье мы создали для кроссплатформенного торгового эксперта менеджер ордеров (COrderManager), который сглаживает большинство различий между MQL4 и MQL5 в части открытия и закрытия сделок. В обеих версиях советник сохраняет в памяти информацию о сделках путем создания экземпляров COrder. Контейнеры с динамическими указателями на экземпляры этого объекта класса также доступны как члены класса COrderManager (как для текущих сделок, так и для находящихся в истории).
Можно сделать так, чтобы менеджер ордеров напрямую обрабатывал и стоп-уровни для каждой сделки. Однако для этого существуют определенные ограничения:
- COrderManager должен быть расширен, чтобы обрабатывать стоп-уровни для каждого трейда.
- Существующие методы COrderManager обрабатывают только вход в основные сделки.
Можно расширить COrderManager так, чтобы он мог обрабатывать стоп-уровни для каждого трейда самостоятельно. Но этот функционал не должен ограничиваться только размещением текущих уровней. Нужно выполнять и задачи их изменения и мониторинга — например, проверять, достигла ли уже цена определенного уровня. Эти функции сильно усложнят COrderManager, не говоря уже о раздельной имплементации.
Менеджер ордеров занимается только входами в основные сделки, в то время как для некоторых стоп-уровней нужно, чтобы советник выполнял и другие торговые операции — такие, как, к примеру, размещение отложенных ордеров или закрытие текущих позиций. Несмотря на то, что менеджер ордеров способен обрабатывать всё это самостоятельно, лучше было бы сфокусировать его только на входе в основные сделки, а обработку стоп-уровней оставить другому объекту класса.
В этой статье мы поговорим о реализации, в которой СOrderManager будет работать исключительно со входами в основные сделки и выходами из них (как и было до сих пор), а затем реализуем отдельную обработку стоп-уровней объектом другого класса (CStop).
COrder
Как уже было показано в одной из предыдущих статей, экземпляр COrder создается после успешной торговой операции (открытия сделки). И для MetaTrader 4, и для MetaTrader 5 информация о стоп-лоссе и тейк-профите может быть сохранена на стороне брокера. Но в случае, если стоп-уровни скрыты от брокера или задействованы несколько стоп-уровней, информация о большей их части должна храниться локально. Таким образом, в последнем случае, сразу же после успешного открытия позиции должен быть создан экземпляр COrder, а вслед за ним — экземпляры объекта, представляющие ее уровни стоп-лосса и тейк-профита. В одной из предыдущих статей мы показали, как экземпляры COrder добавляются в менеджер ордеров при создании. Это проиллюстрировано следующим рисунком:
Стоп-уровни добавляются точно так же. Чтобы это сделать, нам просто нужно вставить метод после того, как создан новый экземпляр COrder, и перед тем, как он добавляется в список текущих сделок (COrders). Таким образом, вышеприведенная картинка слегка изменяется:
Операция по созданию стоп-уровней в общем виде показана на следующей картинке:
Как показано на двух предыдущих блок-схемах, новый экземпляр 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. Среди возможностей этого класса — следующие:
- определение уровней стоп-лосса и тейк-профита;
- расчет стоп-уровней;
- реализация уровней стоп-лосса и тейк-профита для основной сделки;
- проверка на достижение стоп-уровня;
- сглаживание различий между имплементацией стоп-лосса и тейк-профита на языках MQL4 и MQL5;
- определение действий по достижении стопов (переход в безубыток, трейлинг-стоп и т.д.).
Пункты 1-5 мы обсудим ниже, а п. 6 будет посвящена отдельная статья.
Типы
Поговорим о трех типах стоп-уровней.
- Стоп, срабатывающий на стороне брокера — стоп-уровень, который отправляется брокеру вместе с торговым приказом.
- Стоп, выставленный по отложенному ордеру. Он срабатывает либо как частичное/полное хеджирование в направлении, противоположном основной позиции (MetaTrader 4 или режим хеджирования в MetaTrader 5), либо как вычитание из основной позиции (неттинговый режим MetaTrader 5).
- Виртуальный стоп скрыт от брокера и обрабатывается локально, внутри советника.
В MetaTrader 4 к первой группе стопов относятся самые распространенные брокерские стоп-лосс и тейк-профит. Цены, на которых они должны сработать, отправляются брокеру вместе с торговым приказом об основной сделке. В хеджинговой версии MetaTrader 5 используется тот же механизм, что и в MetaTrader 4. В неттинговом режиме для этого типа CStop будут использоваться стопы по отложенным ордерам, поскольку стоп-лосс и тейк-профит здесь отличаются (они применяются к полной позиции по символу).
Стопы по отложенным ордерам в какой-то мере имитируют стопы на брокерской стороне. При исполнении отложенного ордера советник будет выполнять торговую операцию (OrderCloseBy), чтобы закрыть основную позицию с использованием объема только что сработавшего отложенного ордера. Описанное поведение верно для MetaTrader 4 и для хеджингового режима MetaTrader 5. Для неттинговой версии MetaTrader 5 выход из некоторого или из полного объема торговой позиции осуществляется автоматически, поскольку в этом режиме одновременно по одному символу может быть открыта только одна позиция.
Основной стоп
Основной стоп — это стоп-уровень, который запускает полное закрытие позиции. Обычно это стоп на стороне брокера. Когда срабатывает стоп-лосс или тейк-профит, отправленный брокеру, вся позиция на рынке закрывается, вне зависимости от того, намеревается ли советник продолжать работать. Однако, если выставлены множественные стоп-уровни и они не отправлены брокеру, будет не лучшей идеей предоставлять советнику право решать, какой из них является главным. В этом случае программист должен сам назначить основной экземпляр CStop для этой сделки. Это может быть полезно, в особенности для некоторых функций и возможностей, зависящих от основного стопа позиции (например, для манименеджмента). Поскольку стоп-лосс на основном стоп-уровне приводит к полному закрытию позиции, он и будет представлять собой максимальный риск для входа в эту сделку. И, уже имея экземпляр основного стоп-уровня, советник получает возможность в соответствии с ним вычислять размер лота.
Стоит отметить, что когда стоп назначается главным, его объем всегда будет аналогичным начальному объему основной сделки. Это отлично работает с виртуальными и брокерскими стопами, но не подходит для стопов по отложенным ордерам. Этому мешают две проблемы.
Первая состоит в том, что в MetaTrader 4 цена открытия отложенного ордера может быть изменена, пока ордер еще не сработал. В MetaTrader 5 это невозможно, потому что здесь должна быть сохранена полная и неизмененная история торговых операций. Поэтому нужно устанавливать новый отложенный ордер. Старый при этом удаляется, и с этого момента советник должен будет использовать в качестве нового стоп-уровня свежеустановленный отложенный ордер.
Вторая проблема — возможность срабатывания старых отложенных ордеров, пока новый еще находится в процессе отправки брокеру. Поскольку советник не имеет контроля над срабатыванием отложенных ордеров, которые были отправлены брокеру вместе с торговым приказом, это может привести к проблемам: зависшим сделкам или закрытию основной сделки по стопу с большим объемом, чем предполагалось.
Самый простой подход для решения этих проблем — назначить объем отложенного ордера прямо при открытии позиции, вместо того чтобы настраивать его динамически в течение всей жизни сделки. Но для этого требуется, чтобы кроме отложенного ордера, назначенного главным стопом, других отложенных ордеров не было.
Объём
Для главного стоп-уровня не нужно назначать размер лота, вычитаемого из основной позиции, потому что при его срабатывании позиция закрывается целиком. Но для других типов стоп-уровней нужно учитывать объем, поскольку обычно они назначаются для частичного закрытия основной позиции. Распределение в таком случае делится на четыре разных типа:
- Фиксирование — назначение фиксированного объема лота
- Процент остатка — процент от объема лота, остающегося в основной позиции
- Общий процент — процент от общего начального лота главной сделки.
- Остаток — оставшийся объем основной сделки.
Назначение фиксированного объема лота — самая простая форма распределения объема. Но это может работать неоптимально, если советник использует некоторые формы динамического расчета объема лота для каждой позиции (например, мани-менеджмент). Такой способ идеален для использования, только если объем лота не изменяется в течение всей работы эксперта.
Процент остатка и остаток лучше использовать, если основной стоп виртуальный (скрытый). Остаток будет предохранять советник от создания "висящих" сделок из незакрытого объема или от закрытия объемом, превышающим остаток по основной сделке. Процент от остатка используется, когда советник должен закрыть сделку на основе не начального объема, а того, который на данный момент остался в основной сделке.
Общий процент используется с брокерскими, виртуальными стопами и стопами по отложенным ордерам. Расчеты, использующие этот метод, основаны на начальном объеме основной сделки.
Один-Отменяет-Остальные (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); };
Для уровней стоп-лосса и тейк-профита на основе пипсов или пунктов нужно будет сохранить как минимум четыре метода класса:
- Тип стоп-уровня (брокерский, на основе отложенного ордера или виртуальный), метод StopType
- Используемый тип расчета объема, метод VolumeType
- Уровень стоп-лосса в пунктах (при необходимости), метод StopLoss
- Уровень тейк-профита в пунктах (при необходимости), метод Т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, предназначенный для графического отображения стоп-уровней. Он выполняет в советнике три ключевых функции:
- Показывает стоп-уровни при инициализации экземпляра COrder
- Обновляет стоп-уровни, если один из них или оба были изменены
- Удаляет линии стоп-уровней, как только главная сделка закрывается
Все эти функции реализуются с помощью класса 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 уровни стоп-лосса и тейк-профита нельзя передвигать перетаскиванием. Их можно изменять только в окне торгового приказа или через использование специальных скриптов или экспертов. Но графическое отображение этих уровней все равно будет полезным, особенно при работе со скрытыми (виртуальными) стопами.
Проверка ордеров на стоп-уровни
Следующим шагом после успешной установки стоп-уровней по данной позиции должна быть проверка на достижение рынком этих уровней. Для брокерских стопов процесс необязателен, потому что закрытие операции совершается на стороне сервера. Но в случае виртуальных стопов или стопов на основании отложенного ордера эксперт должен будет сам выполнить операцию закрытия.
Для виртуальных (скрытых) стопов советник полностью сам отвечает за отслеживание момента движения рынка и за проверку, пробит ли стоп-уровень. Рисунок ниже показывает общую схему операции. Как только цена пробивает стоп-уровень, советник выполняет соответствующую операцию закрытия.
Для стопа на основании отложенного ордера процесс чуть более сложный. Срабатывание стоп-уровня приведет к срабатыванию отложенного ордера — то есть, к появлению соответствующей позиции. Это происходит автоматически, на стороне брокера. Таким образом, эксперт сам берет на себя ответственность за определение того, является ли отложенный ордер всё еще отложенным или же он уже вошел в рынок. Если отложенный ордер уже сработал, советник отвечает за закрытие главной позиции в объеме, соответствующей этому ордеру — это будет операция закрытия сделки встречной сделкой.
Во всех случаях стоп-уровень помечается как закрытый, как только срабатывает ордер по нему. Это сделано для того, чтобы защитить стоп-уровень от многократного срабатывания.
Примеры
Пример №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 |
Ордера |
||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Время открытия | Ордер | Символ | Тип | Объём | Цена | 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 | |||||||||
Ордера |
||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Время открытия | Ордер | Символ | Тип | Объём | Цена | 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
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Как же далек от практики и удобства предложенный кроссплатформенный подход. Как свой громоздкий велосипед - пойдет. Но зачем его публиковать?! Проще написать все полностью свое даже новичку, чем изучать и осваивать этого монстра. Не понимаю.
СБ под MT5 - пример элегантности, по сравнению с данным циклом статей. Да еще и перенесен под MT4.
Как же далек от практики и удобства предложенный кроссплатформенный подход. Как свой громоздкий велосипед - пойдет. Но зачем его публиковать?! Проще написать все полностью свое даже новичку, чем изучать и осваивать этого монстра. Не понимаю.
СБ под MT5 - пример элегантности, по сравнению с данным циклом статей. Да еще и перенесен под MT4.
Полностью согласен. Даже будучи прекрасно знакомым с ООП, подход данного автора какой-то слишком извращённый. Слишком много излишеств и вообще не код, а, действительно, "монстр"..