Forextrade

MQLabs: Расчет совокупной позиции

Советник  OverTake

Файлы стратегий для AutoGraf 4.0

Развернутые результаты тестирования эксперта

   

    Среди трейдеров широко распространена практика открытия обратной сделки без закрытия существующей. Такой метод торговли еще называют локированием (от англ. "lock" - замóк). Наиболее распространенное применение лока - замена уровня стопа, когда вместо заполнения поля "Стоп лосс" рыночного ордера ставится противоположный позиции отложенный ордер.

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

    Первой частью психологической выгоды (самообманом) при локировании является сумма баланса, которая не уменьшается, а во многих случаях даже растет. Трейдеры забывают, что реальное положение дел отражает сумма средств (Equity). Но стабильность баланса заставляет их убеждать себя в обратном. Эта часть психологической выгоды проста и понятна, поэтому и бороться с ней легко. Трейдеров, которые находятся в плену подобных иллюзий, действительно нельзя назвать состоявшимися.

    Со второй частью выгоды не все так просто и однозначно. Фактическим открытием сделки при наличии лока является полное или частичное закрытие одной из сделок. Чаще всего это производится со сделкой, дающей прибыль. Этот момент и является ключевым. Когда счет не содержит открытых сделок, то решение об открытии сопровождается ожиданием "цена сейчас пойдет в эту сторону". При наличии лока и закрытии прибыльной позиции ожидание иное: "цена больше не пойдет в эту сторону". То есть налицо противоположность побудительных мотивов.

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

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

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

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

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

    Эксперт OverTake может быть использован в двух режимах: самодостаточной АТС и помощника в ручной торговле. Для разделения режимов потребуется параметр, указывающий нужный режим. Для этого необходимо расширить круг настроечных параметров эксперта и ввести новую переменную - OpenCloseTrades. Ее значение True разрешит автоматическое открытие и закрытие позиций, а False - запретит, оставив лишь возможность модификации стопов и профитов имеющихся ордеров.

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

 
//+-------------------------------------------------------------------------------------+
//| Поиск своих ордеров.                                                                |
//+-------------------------------------------------------------------------------------+
void FindOrders()  
{
// - 1 - ===================== Инициализация параметров =================================
 BuyCount = ; SellCount = ;                            // Количество ордеров BUY и SELL
 BuyAP = ; SellAP = ;                     // Средняя цена открытия каждого типа ордеров
 BuyLots = ; SellLots = ;                       // Суммарный объем каждого типа ордеров
 BuyLast = ; SellLast = ;         // Время открытия наиболее позднего ордера BUY и SELL
 LotLast = ;                                                  // Наибольший объем ордера
 BuyLow = 99999999999; SellHigh = ;                  // Цена нижнего BUY и верхнего SELL
 BuyHigh = ; SellLow = 999999999;                    // Цена верхнего BUY и нижнего SELL
 CommonProfit = ;                                                   // Совокупный профит
 BuyProfit = ; SellProfit = ;           // Суммарный профит BUY и суммарный профит SELL
// - 1 - ========================== Окончание блока =====================================

// - 2 - =================================== Поиск ордеров ==============================
 for (int i = ; i < OrdersTotal(); i++)              // Используется весь список ордеров
   if (OrderSelect(i, SELECT_BY_POS))                       // Убедимся, что ордер выбран
     if ((OrderMagicNumber() == MagicNumber ||                  // Ордер открыт экспертом
          !OpenCloseTrades) &&                       // или включен режим ручной торговли
         OrderSymbol() == Symbol())    // ордер должен принадлежать текущей валютной паре
       {  
        CommonProfit += OrderProfit()+OrderSwap();         // Подсчет совокупного профита
        LotLast = MathMax(LotLast, OrderLots());              // Поиск наибольшего объема
        if (OrderType() == OP_BUY)                                     // Для ордеров BUY
          {
           BuyTicket[BuyCount] = OrderTicket();                      // Сохранение тикета
           BuyLots += OrderLots();                                      // Подсчет объема
           BuyAP += OrderLots()*OrderOpenPrice();              // Вычисление средней цены
           BuyLast = MathMax(BuyLast, OrderOpenTime());     // нахождение позднего ордера
           BuyLow = MathMin(BuyLow, OrderOpenPrice());                      // Нижний BUY
           BuyHigh = MathMax(BuyHigh, OrderOpenPrice());                   // Верхний BUY
           BuyProfit += OrderProfit()+OrderSwap();                     // Подсчет профита
           BuyCount++;                                                  // Количество BUY
          }
        if (OrderType() == OP_SELL)
          {
           SellTicket[SellCount] = OrderTicket();                    // Сохранение тикета
           SellLots += OrderLots();                                     // Подсчет объема
           SellAP += OrderLots()*OrderOpenPrice();             // Вычисление средней цены
           SellLast = MathMax(SellLast, OrderOpenTime());   // нахождение позднего ордера
           SellHigh = MathMax(SellHigh, OrderOpenPrice());                // Верхний SELL
           SellLow = MathMin(SellLow, OrderOpenPrice());                   // Нижний SELL
           SellProfit += OrderProfit()+OrderSwap();                    // Подсчет профита
           SellCount++;                                                // Количество SELL
          }
       } 
// - 2 - ========================== Окончание блока =====================================

// - 3 - ================== Окончательное вычисление средних цен ========================
 if (BuyLots != )       // Если есть ордера BUY, то вычисляется их средняя цена открытия
   BuyAP /= BuyLots;      

 if (SellLots != )     // Если есть ордера SELL, то вычисляется их средняя цена открытия
   SellAP /= SellLots;      

 if (NormalizeDouble(MathAbs(BuyLots - SellLots), 3) != )// Если есть совокупная позиция
   {                                          // то вычисляется ее уровень безубыточности
    APrice = (BuyAP*BuyLots - SellLots*(SellAP - Spread))/(BuyLots - SellLots);  
    if (BuyLots > SellLots)                                   // Поправка для BUY - вверх
      APrice = MathCeil(APrice/Tick)*Tick;
     else                                                     // Поправка для SELL - вниз
      APrice = MathFloor(APrice/Tick)*Tick;
    if (BuyCount == )       // Если присутствуют только BUY, то совокупная цена равна их
      APrice = SellAP;                                                   //  средней цене
    if (SellCount == )     // Если присутствуют только SELL, то совокупная цена равна их
      APrice = BuyAP;                                                    //  средней цене
   } 
// - 3 - ========================== Окончание блока =====================================
}

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

      Во втором блоке, путем просмотра всего списка ордеров, при выключенном параметре OpenCloseTrades, выбираются рыночные ордера, принадлежащие текущему инструменту. Если же параметр OpenCloseTrades включен, то выбираются только те рыночные ордера, которые были открыты непосредственно экспертом. В зависимости от типа ордера, его тикет сохраняется в массив BuyTicket или SellTicket. Средняя цена по каждому из типов ордеров рассчитывается путем сложения произведений цен открытия и объемов позиций. Значения записываются в переменные BuyAP и SellAP. Это еще не окончательные средние цены открытий, а только числитель формулы расчета. В качестве знаменателя выступят суммарные объемы позиций, которые параллельно рассчитываются в переменных BuyLots и SellLots.

       Третий блок начинается завершением расчетов средних цен ордеров BUY и ордеров Sell. Для этого значения переменных BuyAP и SellAP делятся на значения BuyLots и SellLots соответственно. Эти расчеты не производятся, если ни одна соответствующая позиция не найдена. Эта же проверка позволяет избежать ситуации деления на ноль.

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

       Небольшие корректировки в конце функции: если найден только один из типов ордеров, то формула расчета средней цены совокупной позиции не подходит и необходимо принимать ранее вычисленные значения BuyAP или SellAP.

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

        Указание размера профита будет возложено на трейдера. Для этого в настроечные параметры добавляется переменная TakeProfit, при помощи которой задается размер профита в пунктах. Чтобы вычислить эквивалент ожидаемой трейдером прибыли в валюте депозита, потребуется еще один параметр, указывающий объем позиции, который участвует в получении прибыли TakeProfit пунктов. С этой целью может использоваться имеющийся параметр Lots. Таким образом, если применительно к валютной паре EURUSD задать Lots = 0.1 и TakeProfit = 100, то ожидаемая трейдером прибыль будет 100 долларов (100 пунктов при 0.1 лота, 50 пунктов при 0.2 лота, 10 пунктов при 1 лоте). То есть, если эксперт обнаружит два рыночных ордера объемом по 0.1 лота каждый, открытые по одинаковой цене, то размер профита у них будет установлен 50 пунктов.

        Все эти действия выполняет функция ModifyCheck:

 
//+-------------------------------------------------------------------------------------+
//| Функция установки новых стопа и профита                                             |
//+-------------------------------------------------------------------------------------+
bool ModifyCheck()
{
// - 1 - ======================= Можно ли проводить модификацию? ========================
 if (NormalizeDouble(MathAbs(BuyLots - SellLots), 3) == ) // Если ордеров нет или объемы
   return(True);                           // встречных позиций равны, то изменять нечего
// - 1 - ============================= Окончание блока ==================================
  
 double NomTake = TakeProfit*Lots;      // Количество денег, зарабатываемых при получении
                                        // прибыли TakeProfit пунктов  и  начальном  лоте
                                        // Lots (стоимость пункта не указывается, так как
                                        // сокращается в последующих действиях)
  
// - 2 - ===== Совокупная позиция - BUY. Установка профита для BUY и стопа для SELL =====
 if (BuyLots > SellLots)
   {
    double PriceTP = APrice + NomTake/(BuyLots - SellLots)*Point;// Расчет уровня профита
    
    // - 2.1 - =================== Изменение уровня стопа ордеров SELL ==================
    for (int i = ; i < SellCount; i++)          // Используется весь список ордеров SELL
      if (OrderSelect(SellTicket[i], SELECT_BY_TICKET) &&   // Убедимся, что ордер выбран
          OrderCloseTime() == )                                           // и не закрыт
        if (MathAbs(OrderStopLoss() - (PriceTP + Spread)) >= Tick)//Стоп не равен нужному
          if (WaitForTradeContext())                       // Свободен ли торговый поток?
            {
             RefreshRates();                                // Обновим значения Bid и Ask
             if (PriceTP + Spread - Ask > StopLevel) // Уровень достаточно удален от цены
               if (!OrderModify(OrderTicket(), , NP(PriceTP + Spread), , ))// Изменяем
                 return(False);                     // При неудаче сразу покидаем функцию
            }
    // - 2.1 - ========================== Окончание блока ===============================
    
    // - 2.2 - ================ Изменение уровня профита ордеров BUY ====================
    for (i = ; i < BuyCount; i++)                // Используется весь список ордеров BUY
      if (OrderSelect(BuyTicket[i], SELECT_BY_TICKET) &&    // Убедимся, что ордер выбран
          OrderCloseTime() == )                                           // и не закрыт
        if (MathAbs(OrderTakeProfit() - PriceTP) >= Tick)      // Профит не равен нужному
          if (WaitForTradeContext())                       // Свободен ли торговый поток?
            {
             RefreshRates();                                // Обновим значения Bid и Ask
             if (PriceTP - Bid > StopLevel)          // Уровень достаточно удален от цены
               if (!OrderModify(OrderTicket(), , , NP(PriceTP), , ))      // Изменяем
                 return(False);                     // При неудаче сразу покидаем функцию
            }
    // - 2.2 - ========================== Окончание блока ===============================
   } 
// - 2 - ============================= Окончание блока ==================================
      
// - 3 - ===== Совокупная позиция - SELL. Установка профита для SELL и стопа для BUY ====
 if (BuyLots < SellLots)  
   {
    if (BuyLots == )    // Если нет длинных сделок, то уровень должен быть на спрэд ниже
      PriceTP = APrice - NomTake/SellLots*Point - Spread;        // Расчет уровня профита
     else 
      PriceTP = APrice - NomTake/(SellLots - BuyLots)*Point;     // Расчет уровня профита

    // - 3.1 - =================== Изменение уровня стопа ордеров BUY ===================
    for (i = ; i < BuyCount; i++)                // Используется весь список ордеров BUY
      if (OrderSelect(BuyTicket[i], SELECT_BY_TICKET) &&    // Убедимся, что ордер выбран
          OrderCloseTime() == )                                           // и не закрыт
        if (MathAbs(OrderStopLoss() - PriceTP) >= Tick)          // Стоп не равен нужному
          if (WaitForTradeContext())                       // Свободен ли торговый поток?
            {
             RefreshRates();                                // Обновим значения Bid и Ask
             if (Bid - PriceTP > StopLevel)          // Уровень достаточно удален от цены
               if (!OrderModify(OrderTicket(), , NP(PriceTP), , ))         // Изменяем
                 return(False);                     // При неудаче сразу покидаем функцию
            }
    // - 3.1 - ========================== Окончание блока ===============================

    // - 3.2 - ================ Изменение уровня профита ордеров SELL ===================
    for (i = ; i < SellCount; i++)              // Используется весь список ордеров SELL
      if (OrderSelect(SellTicket[i], SELECT_BY_TICKET) &&   // Убедимся, что ордер выбран
          OrderCloseTime() == )                                           // и не закрыт
        if (MathAbs(OrderTakeProfit() - (PriceTP + Spread)) >= Tick)   // Профит не равен
                                                                       // нужному
          if (WaitForTradeContext())                       // Свободен ли торговый поток?
            {
             RefreshRates();                                // Обновим значения Bid и Ask
             if (Ask - (PriceTP + Spread) > StopLevel)//Уровень достаточно удален от цены
               if (!OrderModify(OrderTicket(), , , NP(PriceTP + Spread), ))// Изменяем
                 return(False);                     // При неудаче сразу покидаем функцию
            }
    // - 3.2 - ========================== Окончание блока ===============================
   }
// - 3 - ============================= Окончание блока ==================================
      
 return(True);                         // Все действия завершены успешно - результат True 
}

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

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

    Второй и третий блоки подобны. В обоих случаях из имеющегося значения средней цены APrice рассчитывается уровень профита PriceTP. Второй блок выполняется, когда суммарный объем ордеров Buy превышает суммарный объем Sell, то есть совокупная позиция - Buy. В этом случае всем имеющимся ордерам Sell устанавливается уровень стоп-приказа по цене PriceTP + Spread, а всем ордерам Buy - профит на уровне PriceTP. В итоге, при достижении ценой Bid показателя PriceTP все позиции будут закрыты одновременно.

    Третий блок выполняется при доминировании ордеров Sell, то есть когда совокупная позиция - Sell. Сначала производится перемещение стоп-приказов ордеров Buy на уровень PriceTP, а затем - изменение уровней профита ордеров Sell на уровень PriceTP+Spread.

    Кроме изменения уровней стопа и профита в соответствии с необходимостями трейдера, требуется визуальное оповещение о текущей ситуации. Поэтому всю собранную в функции FindOrders информацию нужно выдать на экран. Удобнее всего наблюдать эти данные непосредственно на графике в виде информационного окна (см. рис. 1).

Рис. 1. - Информационное окно.

        В текущей ситуации показано два рыночных ордера: ордер Buy объемом 0.11 лота и ордер Sell объемом 0.1 лота. Уровни открытия ордеров находятся выше 1.43 и поэтому, на первый взгляд, кажется странным, что средняя цена открытия совокупной позиции Buy находится далеко внизу - 1.3828. Но ничего странного в этом нет, так как объем совокупной позиции в 10 раз меньше объема каждого из составных ордеров. А для обеспечения суммарного профита 53.56 доллара объемом 0.01 лота требуется открытие позиции Buy именно по цене 1.3828. 

        Положение информационного окна может быть изменено пользователем. Для этого в настройки эксперта OverTake добавлены такие параметры:

       1) CommentCorner - угол привязки информационного окна. Нумеруется с нуля от верхнего левого угла буквой Z. То есть левый верхний - 0, правый верхний - 1, левый нижний - 2, правый нижний - 3. По умолчанию 1. Если пользователю информационное окно мешает, то для его сокрытия необходимо присвоить параметру любое значение больше трех.

       2) BaseColor - цвет статичных объектов таблиц. По умолчанию - желтый. Для светлого фона лучше применять синий цвет (Blue).

       3) ValueColor - цвет значений. По умолчанию цвет морской волны. Для светлого фона лучше использовать кирпичный цвет (FireBrick).

       4) prefix - приставка в названии объектов таблицы для их идентификации экспертом. По умолчанию "OTE_".

      Все объекты приведенного информационного окна создаются при помощи вызова одной функции - SetLabel:

 
//+-------------------------------------------------------------------------------------+
//| Создание или перемещение/изменение текстовой метки                                  |
//+-------------------------------------------------------------------------------------+
void SetLabel(string ObjName,                                              // имя объекта
              int X, int Y,                  // координаты Х и Y от правого верхнего угла
              int Font,      // Тип шрифта: 0 - Windings, 1 - MS Sans Serif, 2 - Fixedsys
              int FontSize,                                              // Размер шрифта
              string Text,                                                 // текст метки
              color Color)                                                  // цвет метки
{
 string name = prefix + ObjName;  // Имя объекта с обязательным префиксом для последующей
                                  // идентификации
 switch (Font)                                    // Может быть применено три типа шрифта
   {
    case : string FontName = "Courier"; break;
    case 1: FontName = "MS Sans Serif"; break;
    case 2: FontName = "Fixedsys"; break;
   } 
 if (ObjectFind(name) < )                     // Если такой объект еще не существует, то
   {
    ObjectCreate(name, OBJ_LABEL, , , );                           // объект создается
    ObjectSet(name, OBJPROP_CORNER, CommentCorner);          // Указывается угол привязки
   }
 ObjectSet(name, OBJPROP_XDISTANCE, X);                      // Расстояние по горизонтали
 ObjectSet(name, OBJPROP_YDISTANCE, Y);                        // Расстояние по вертикали
 ObjectSetText(name, Text, FontSize, FontName, Color);//Отображение текста нужным шрифтом
                                                      // и цветом
}

        Функции SetLabel передается уникальное имя объекта ObjName, координаты объекта X и Y, рассчитанные от угла CommentCorner, тип шрифта Font (0, 1 или 2), размер шрифта FontSize в пикселях, строка, выводимая на экран, Text и цвет шрифта Color.

        Окончательное имя объекта формируется в переменной name конкатенацией строк prefix и ObjName.

        Наименование шрифта определяется по значению Font. Подобная передача имени шрифта применена в связи с необходимостью уменьшения длины вызывающей строки, так как таких вызовов производится большое количество.

        Последний штрих в создании объекта "Текстовая метка" - проверка существования объекта. Если объект уже создан, то производится лишь изменение его координат, текстового  содержимого, типа шрифта, размера шрифта и цвета.  Если же объект не найден, то он создается, а затем производится изменение оставшихся параметров.

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

        Кроме управления имеющимися ордерами, эксперт OverTake снабжен блоком, генерирующим сигналы открытия позиций (функция GetSignal, доставшаяся по наследству от эксперта VolatilityBounce). Поэтому можно превратить стратегию в самодостаточную АТС, которая будет и открывать, и закрывать сделки. Для этого требуется небольшое преобразование имеющейся функции Trade:

 
bool Trade()
{
// - 1 - ==================== Открытие длинной позиции ==================================
 if (Signal >  && BuyLast < Time[] &&     // Сигнал BUY, на который еще не было реакции
     ((Ask < BuyLow && MartinMode < 2) ||  // Режим доливки и Ask ниже самого нижнего BUY
                                                                                   // ИЛИ
      (Ask > BuyHigh && (MartinMode ==  || MartinMode == 2)) ||  // режим пирамиды и Ask
                                                                     // выше верхнего BUY
                                                                                   // ИЛИ
      MartinMode == 3))                                              // режим чередования
   {
    if (MartinMode == 3 && Ask < SellAP)   // В режиме чередования проверяем прибыльность
      {             // текущих ордеров SELL. Если они совокупно в прибыли, то закрываются
       if (!CloseAllSell())                              // Попытка закрытия ордеров SELL
         return(False);                                   // При неудаче мгновенный выход
       FindOrders();                      // Обновление информации после закрытия ордеров
      }   
    if (LotLast == )            // Определение объема следующей  сделки. Если первая, то
      double Lot = Lots;                                             // объем - начальный
     else 
      Lot = LotRound(LotLast*LotExponent);      // иначе изменение по заданному множителю
    OpenOrderCorrect(OP_BUY, Lot, NP(Ask), , );                  // Открытие ордера BUY
    return(False);                                 // Выход для пересчета состава ордеров
   } 
// - 1 - ==================== Окончание блока ===========================================
           
// - 2 - ==================== Открытие короткой позиции =================================
 if (Signal <  && SellLast < Time[] &&   // Сигнал SELL, на который еще не было реакции
     ((Bid > SellHigh && MartinMode < 2) ||     // Режим доливки и Bid выше верхнего SELL
                                                                                   // ИЛИ
      (Bid < SellLow && (MartinMode ==  || MartinMode == 2)) ||  // режим пирамиды и Bid
                                                                    // ниже  нижнего SELL
                                                                                   // ИЛИ
      MartinMode == 3))                                              // режим чередования
   {
    if (MartinMode == 3 && Bid > BuyAP)    // В режиме чередования проверяем прибыльность
      {              // текущих ордеров BUY. Если они совокупно в прибыли, то закрываются
       if (!CloseAllBuy())                                // Попытка закрытия ордеров BUY
         return(False);                                   // При неудаче мгновенный выход
       FindOrders();                      // Обновление информации после закрытия ордеров
      }   
    if (LotLast == )            // Определение объема следующей  сделки. Если первая, то
      Lot = Lots;                                                    // объем - начальный
     else 
      Lot = LotRound(LotLast*LotExponent);      // иначе изменение по заданному множителю
    OpenOrderCorrect(OP_SELL, Lot, NP(Bid), , );                // Открытие ордера SELL
    return(False);                                 // Выход для пересчета состава ордеров
   } 
// - 2 - ==================== Окончание блока ===========================================
 
 return(True);    
}

          Именно в ней используется вторая часть данных, полученных в функции FindOrders: BuyLast, BuyLow, BuyHigh, SellLast, SellLos, SellHigh.

        Благодаря введению еще одного настроечного параметра эксперта MartinMode, функция может работать в четырех режимах: безусловное открытие позиции по сигналу (MartinMode = 0), добавление к убыточной позиции (MartinMode = 1), добавление к прибыльной позиции (MartinMode = 2) и закрытие встречной прибыльной позиции (MartinMode = 3). В итоге пользователь получает разносторонний предмет для исследований.

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

        Блок 1 выполняет открытие рыночного ордера Buy. Это происходит при условии наличия бычьего сигнала, который еще не был обработан. Дальнейшие действия производятся в зависимости от режима MartinMode. Например, при режиме добавления к убыточной позиции (доливки), цена должна быть ниже нижнего Buy. При выборе режима 3, сначала производится попытка закрытия всех ордеров Sell, если, конечно, они суммарно в прибыли. Затем рассчитывается размер объема ордера и открытие ордера Buy.

        Аналогичным образом выполняется блок 2, открывающий рыночный ордер Sell.

        Функция Trade не исполняется вообще при значении параметра OpenCloseTrades = False.

        Основным предназначением эксперта является именно вычисление совокупной позиции с установкой уровня профита. Поэтому умолчательное значение OpenCloseTrades = False. Использование эксперта в режиме самодостаточной АТС рекомендуется только в режиме тестирования, так как советник является одной из модификаций тактики Мартингейла.

        Как замечено выше, тестирование эксперта никому не принесет убытков. Результаты представлены ниже (см. рис. 2 - 5). Рабочий таймфрейм H1, участок истории - с 01.01.2009 до 19.06.2010. Параметр OpenCloseTrades был переведен в положение True, все остальные параметры, кроме Range и TakeProfit, использовались по умолчанию.

    

                Рис. 2. - Результаты тестирования эксперта OverTake на валютной паре EURUSD.

EURUSD. Значения изменяемых параметров были взяты такие: Range = 15, TakeProfit = 70. Чистая прибыль 4 434 доллара, максимальная просадка - 2 930 долларов, фактор восстановления - 1.51. Конец тестирования пришелся на развитие нескольких колен Мартингейла и не успел дойти до финального завершения. Отсюда такой убыток.

                Рис. 3. - Результаты тестирования эксперта OverTake на валютной паре USDCHF.

USDCHF. Оптимальные параметры для франка такие: Range = 4, TakeProfit = 160. Чистая прибыль 5 831 доллар, максимальная просадка - 1 415 долларов, фактор восстановления - 4.12. "Зубы" тактики Мартингейла здесь во всей красе пришлись на начало тестирования.

                      Рис. 4. - Результаты тестирования эксперта OverTake на валютной паре GBPUSD.

GBPUSD. Входные параметры эксперта: Range = 3, TakeProfit = 200. Чистая прибыль 13 956 долларов, максимальная просадка - 3 103 доллара, фактор восстановления - 4.50.

                        Рис. 5. - Результаты тестирования эксперта OverTake на валютной паре USDJPY.

USDJPY.  Результаты показаны при параметрах: Range = 9, TakeProfit = 170. Чистая прибыль 7 912 долларов, максимальная просадка - 2 811 долларов, фактор восстановления - 2.81.

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

 

 Доработка стратегии для использования в AutoGraf 4.0

    Стратегия может быть использована в среде AutoGraf 4.0. Для этого потребуется внесение некоторых изменений в код эксперта OverTake. Для пользователя видимыми изменениями будут перемены в настроечных параметрах стратегии. Большая их часть была вынесена в настроечные параметры AutoGraf от AT_1 до AT_7. Соответствие параметров следующее: OpenCloseTrades - AT_1 (0 соответствует False, любое другое значение - True), ATRPeriod - AT_2, Range - AT_3, LotExponent - AT_4, MartinMode - AT_5. Так как настроить цвета при помощи параметров AutoGraf невозможно, был введен параметр AT_6, задающий тип используемого цвета графика. Нулевое значение AT_6 означает темный экран, на котором информационное окно будет в желтом и синем цветах, а любое другое - светлый экран, где применяются синий и кирпичный цвета информационного окна. Параметру CommentCorner соответствует AT_7.

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

     Значение TakeProfit в пунктах также устанавливается при помощи параметра AutoGraf - TP (панель настроек в нижней части экрана).

     Запуск стратегии OverTake в среде AutoGraf 4.0 состоит из следующих шагов:

  • Получить файл по ссылке Файлы стратегий для AutoGraf 4.0 и распаковать полученный архив в папку MT4\experts\libraries (с перезаписью файлов AG_AT.ex4 и AG_AT.mq4).

  •  Запустить AutoGraf.

  •  Для работы советника в ключе приведенных результатов в окне настроек AutoGraf (закладка "Входные параметры") выставить правильные значения параметров AT_1 -  AT_7 (полное повторение результатов при этом не гарантируется).

  • Выбрать стратегию №5. Для этого необходимо передвинуть вверх значок So и среди названий стратегий найти значок S5, который также потянуть вверх.

  • Запустить функцию автоматической торговли, передвинув значок AT в верхнее положение.

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

 ВНИМАНИЕ!!! Использована тактика Мартингейла! Быть предельно острожным при использовании советника на реальном счете.

 

Игорь Герасько

Июнь 2010

Специально для компании Admiral Markets

2.285715
 
 

Пред.: MQLabs: Отбой волатильности
След.: MQLabs: Волатильность флэта и тренда

Комментарии

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
CAPTCHA
Проверка на СПАМ:
  _____                       ___    ___    ____  __   __
| ____| __ __ __ _ / _ \ |_ _| / ___| \ \ / /
| _| \ \ /\ / / / _` | | | | | | | | | \ V /
| |___ \ V V / | (_| | | |_| | | | | |___ | |
|_____| \_/\_/ \__, | \__\_\ |___| \____| |_|
|_|
Enter the code depicted in ASCII art style.
Общие вопросы
info@forextrade.ru
Техническая поддержка
support@fxservice.com
Необходимые файлы и документы
Филиальная сеть
Условия перепечатки материалов с сайта
Уведомление о рисках
Карта сайта
Политика конфиденциальности
Мы принимаем Webmoney Мы принимаем Webmoney
iPhone iTrader Android Trader BlackBerry Trader MetaTrader для мобильных устройств MetaTrader Web Trader iPad iTrader