//+----------------------------------------------------------------------------+
//|                                                          e-SOTrailing.mq4  |
//|                                                                            |
//|                                                    Ким Игорь В. aka KimIV  |
//|                                                       http://www.kimiv.ru  |
//|                                                                            |
//|  03.09.2006  Автоматический Trailing всех стоповых ордеров.                |
//|              Вешать только на один график.                                 |
//|  21.07.2008  Сделал модификацию стопов и тейков.                           |
//+----------------------------------------------------------------------------+
#property copyright "Ким Игорь В. aka KimIV"
#property link      "http://www.kimiv.ru"

//------- Внешние параметры советника -----------------------------------------+
extern bool  AllStopOrders = False;    // Управлять всеми стоповыми ордерами
extern int   TrailingStop  = 20;       // Фиксированный размер трала
extern int   TrailingStep  = 3;        // Шаг трала
extern bool  UseSound      = True;     // Использовать звуковой сигнал
extern color clModifyBuy   = Aqua;     // Цвет значка модификации покупки
extern color clModifySell  = Tomato;   // Цвет значка модификации продажи

//------- Глобальные переменные советника -------------------------------------+
string SoundSuccess  = "ok.wav";       // Звук успеха
string SoundError    = "timeout.wav";  // Звук ошибки
int    NumberOfTry   = 5;              // Количество торговых попыток

//------- Подключение внешних модулей -----------------------------------------+
#include <stdlib.mqh>             // Стандартная библиотека

//+----------------------------------------------------------------------------+
//|  expert start function                                                     |
//+----------------------------------------------------------------------------+
void start() {
  for (int i=0; i<OrdersTotal(); i++) {
    if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
      if (AllStopOrders || OrderSymbol()==Symbol()) {
        TrailingOrders();
      }
    }
  }
}

//+----------------------------------------------------------------------------+
//|  Автор    : Ким Игорь В. aka KimIV,  http://www.kimiv.ru                   |
//+----------------------------------------------------------------------------+
//|  Версия   : 01.09.2005                                                     |
//|  Описание : Возвращает наименование торговой операции                      |
//+----------------------------------------------------------------------------+
//|  Параметры:                                                                |
//|    op - идентификатор торговой операции                                    |
//+----------------------------------------------------------------------------+
string GetNameOP(int op) {
  switch (op) {
    case OP_BUY      : return("Buy");
    case OP_SELL     : return("Sell");
    case OP_BUYLIMIT : return("BuyLimit");
    case OP_SELLLIMIT: return("SellLimit");
    case OP_BUYSTOP  : return("BuyStop");
    case OP_SELLSTOP : return("SellStop");
    default          : return("Unknown Operation");
  }
}

//+----------------------------------------------------------------------------+
//|  Автор    : Ким Игорь В. aka KimIV,  http://www.kimiv.ru                   |
//+----------------------------------------------------------------------------+
//|  Версия   : 18.07.2008                                                     |
//|  Описание : Возвращает одно из двух значений взависимости от условия.      |
//+----------------------------------------------------------------------------+
color IIFc(bool condition, color ifTrue, color ifFalse) {
  if (condition) return(ifTrue); else return(ifFalse);
}

//+----------------------------------------------------------------------------+
//|  Автор    : Ким Игорь В. aka KimIV,  http://www.kimiv.ru                   |
//+----------------------------------------------------------------------------+
//|  Версия   : 28.11.2006                                                     |
//|  Описание : Модификация одного предварительно выбранного ордера.           |
//+----------------------------------------------------------------------------+
//|  Параметры:                                                                |
//|    pp - цена установки ордера                                              |
//|    sl - ценовой уровень стопа                                              |
//|    tp - ценовой уровень тейка                                              |
//|    ex - дата истечения                                                     |
//+----------------------------------------------------------------------------+
void ModifyOrder(double pp=-1, double sl=0, double tp=0, datetime ex=0) {
  bool   fm;
  color  cl=IIFc(OrderType()==OP_BUY
              || OrderType()==OP_BUYLIMIT
              || OrderType()==OP_BUYSTOP, clModifyBuy, clModifySell);
  double op, pa, pb, os, ot;
  int    dg=MarketInfo(OrderSymbol(), MODE_DIGITS), er, it;

  if (pp<=0) pp=OrderOpenPrice();
  if (sl<0 ) sl=OrderStopLoss();
  if (tp<0 ) tp=OrderTakeProfit();
  
  pp=NormalizeDouble(pp, dg);
  sl=NormalizeDouble(sl, dg);
  tp=NormalizeDouble(tp, dg);
  op=NormalizeDouble(OrderOpenPrice() , dg);
  os=NormalizeDouble(OrderStopLoss()  , dg);
  ot=NormalizeDouble(OrderTakeProfit(), dg);

  if (pp!=op || sl!=os || tp!=ot) {
    for (it=1; it<=NumberOfTry; it++) {
      if (!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;
      while (!IsTradeAllowed()) Sleep(5000);
      RefreshRates();
      fm=OrderModify(OrderTicket(), pp, sl, tp, ex, cl);
      if (fm) {
        if (UseSound) PlaySound(SoundSuccess); break;
      } else {
        er=GetLastError();
        if (UseSound) PlaySound(SoundError);
        pa=MarketInfo(OrderSymbol(), MODE_ASK);
        pb=MarketInfo(OrderSymbol(), MODE_BID);
        Print("Error(",er,") modifying order: ",ErrorDescription(er),", try ",it);
        Print("Ask=",pa,"  Bid=",pb,"  sy=",OrderSymbol(),
              "  op="+GetNameOP(OrderType()),"  pp=",pp,"  sl=",sl,"  tp=",tp);
        Sleep(1000*10);
      }
    }
  }
}

//+----------------------------------------------------------------------------+
//|  Сопровождение ордеров простым тралом                                      |
//+----------------------------------------------------------------------------+
void TrailingOrders() {
  double di, pa, pb, pp, sl, tp;

  pp=MarketInfo(OrderSymbol(), MODE_POINT);
  if (OrderType()==OP_BUYSTOP) {
    pa=MarketInfo(OrderSymbol(), MODE_ASK);
    if (OrderOpenPrice()-pa>(TrailingStop+TrailingStep-1)*pp) {
      di=OrderOpenPrice()-pa-TrailingStop*pp;
      if (OrderStopLoss()  >0) sl=OrderStopLoss()  -di; else sl=0;
      if (OrderTakeProfit()>0) tp=OrderTakeProfit()-di; else tp=0;
      ModifyOrder(pa+TrailingStop*pp, sl, tp);
    }
  }
  if (OrderType()==OP_SELLSTOP) {
    pb=MarketInfo(OrderSymbol(), MODE_BID);
    if (pb-OrderOpenPrice()>(TrailingStop+TrailingStep-1)*pp) {
      di=OrderOpenPrice()-pb-TrailingStop*pp;
      if (OrderStopLoss()  >0) sl=OrderStopLoss()  -di; else sl=0;
      if (OrderTakeProfit()>0) tp=OrderTakeProfit()-di; else tp=0;
      ModifyOrder(pb-TrailingStop*pp, sl, tp);
    }
  }
}
//+------------------------------------------------------------------+

