//+----------------------------------------------------------------------------+
//|                                                e-CloseByPercentProfit.mq4  |
//|                                                                            |
//|  Идея      : $anto$,  http://www.community.finlist.org/member.php?u=152    |
//|        http://www.community.finlist.org/showpost.php?p=80058&postcount=96  |
//|  Разработка: Ким Игорь В. aka KimIV,  http://www.kimiv.ru                  |
//|                                                                            |
//|  08.11.2007  Советник закрывает все позиции                                |
//|              при достижении заданного процента прибыли.                    |
//|  21.11.2007  Закрытие всех позиции при превышении процента общего убытка.  |
//|  19.12.2007  Закрытие терминала после закрытия всех позиций.               |
//|              Предложил Legge.                                              |
//|           http://forex.kbpauk.ru/showprofile.php?Cat=0&User=10595&what=login
//+----------------------------------------------------------------------------+
#property copyright "Ким Игорь В. aka KimIV"
#property link      "http://www.kimiv.ru"

//------- Внешние параметры советника ------------------------------------------
extern string _P_Expert = "---------- Параметры советника";
extern double PercentProfit   = 1.00;            // Процент профита
extern double PercentLoss     = 5.00;            // Процент убытка
extern bool   DeleteOrders    = False;           // Удалять ордера
extern bool   CloseTerminal   = False;           // Закрывать терминал
extern bool   ShowComment     = True;            // Показывать комментарий
extern int    NumberAccount   = 0;               // Номер торгового счёта
extern bool   UseSound        = False;           // Использовать звуковой сигнал
extern string NameFileSound   = "expert.wav";    // Наименование звукового файла
extern int    Slippage        = 3;               // Проскальзывание цены
extern int    NumberOfTry     = 5;               // Количество попыток
extern int    PauseAfterError = 75;              // Пауза после ошибки в секундах

//------- Глобальные переменные советника --------------------------------------
bool  gbDisabled  = False;        // Флаг блокировки советника
color clCloseBuy  = Blue;         // Цвет значка закрытия покупки
color clCloseSell = Red;          // Цвет значка закрытия продажи
color clDelete    = Yellow;       // Цвет значка удаления ордеров

//------- Поключение внешних модулей -------------------------------------------
#include <stdlib.mqh>
#include <WinUser32.mqh>


//+----------------------------------------------------------------------------+
//|                                                                            |
//|  ПРЕДОПРЕДЕЛЁННЫЕ ФУНКЦИИ                                                  |
//|                                                                            |
//+----------------------------------------------------------------------------+
//|  expert initialization function                                            |
//+----------------------------------------------------------------------------+
void init() {
  gbDisabled=False;
  if (!IsTradeAllowed()) {
    Message("Для нормальной работы советника необходимо\n"+
            "Разрешить советнику торговать");
    gbDisabled=True; return;
  }
  if (!IsDllsAllowed()) {
    Message("Для нормальной работы советника необходимо\n"+
            "Разрешить импорт функций из DLL");
    gbDisabled=True; return;
  }
  if (!IsLibrariesAllowed()) {
    Message("Для нормальной работы советника необходимо\n"+
            "Разрешить импорт из внешних экспертов");
    gbDisabled=True; return;
  }
  if (!IsTesting()) {
    if (IsExpertEnabled()) Message("Советник будет запущен следующим тиком");
    else Message("Отжата кнопка \"Разрешить запуск советников\"");
  }
}

//+----------------------------------------------------------------------------+
//|  expert deinitialization function                                          |
//+----------------------------------------------------------------------------+
void deinit() { if (!IsTesting()) Comment(""); }

//+----------------------------------------------------------------------------+
//|  expert start function                                                     |
//+----------------------------------------------------------------------------+
void start() {
  if (gbDisabled) {
    Message("Не удалось инициализировать советник!"); return;
  }
  if (!IsTesting()) {
    if (NumberAccount>0 && NumberAccount!=AccountNumber()) {
      Comment("Торговля на счёте: "+AccountNumber()+" ЗАПРЕЩЕНА!");
      return;
    } else Comment("");
    if (ShowComment) {
      string st="PercentProfit="+DoubleToStr(PercentProfit, 2)
               +"  PercentLoss="+DoubleToStr(PercentLoss, 2)+"\n"
               +"Текущие: Баланс="+DoubleToStr(AccountBalance(), 2)
               +"  Эквити="+DoubleToStr(AccountEquity(), 2)
               +"  Прибыль="+DoubleToStr((AccountEquity()/AccountBalance()-1)*100, 2)+" %"
               ;
      Comment(st);
    } else Comment("");
  }

  if (AccountEquity()>=AccountBalance()*(1+PercentProfit/100)
  ||  AccountEquity()<=AccountBalance()*(1-PercentLoss  /100)) {
    ClosePosFirstProfit();
    DeleteOrders();
  }
}


//+----------------------------------------------------------------------------+
//|                                                                            |
//|  ПОЛЬЗОВАТЕЛЬСКИЕ ФУНКЦИИ                                                  |
//|                                                                            |
//+----------------------------------------------------------------------------+
//|  Закрытие одной предварительно выбранной позиции                           |
//+----------------------------------------------------------------------------+
void ClosePosBySelect() {
  bool   fc;
  color  clClose;
  double ll, pAsk, pBid, pp;
  int    err, it;

  if (OrderType()==OP_BUY || OrderType()==OP_SELL) {
    for (it=1; it<=NumberOfTry; it++) {
      if (!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;
      while (!IsTradeAllowed()) Sleep(5000);
      RefreshRates();
      pAsk=MarketInfo(OrderSymbol(), MODE_ASK);
      pBid=MarketInfo(OrderSymbol(), MODE_BID);
      if (OrderType()==OP_BUY) {
        pp=pBid; clClose=clCloseBuy;
      } else {
        pp=pAsk; clClose=clCloseSell;
      }
      ll=OrderLots();
      fc=OrderClose(OrderTicket(), ll, pp, Slippage, clClose);
      if (fc) {
        if (UseSound) PlaySound(NameFileSound); break;
      } else {
        err=GetLastError();
        if (err==146) while (IsTradeContextBusy()) Sleep(1000*PauseAfterError);
        Print("Error(",err,") Close ",GetNameOP(OrderType())," ",
              ErrorDescription(err),", try ",it);
        Print(OrderTicket(),"  Ask=",pAsk,"  Bid=",pBid,"  pp=",pp);
        Print("sy=",OrderSymbol(),"  ll=",ll,"  sl=",OrderStopLoss(),
              "  tp=",OrderTakeProfit(),"  mn=",OrderMagicNumber());
        Sleep(1000*PauseAfterError);
      }
    }
  } else Print("Некорректная торговая операция. Close ",GetNameOP(OrderType()));
}

//+----------------------------------------------------------------------------+
//|  Закрытие позиций по рыночной цене сначала прибыльных                      |
//+----------------------------------------------------------------------------+
void ClosePosFirstProfit() {
  int i, k=OrdersTotal();

  // Сначала закрываем прибыльные позиции
  for (i=k-1; i>=0; i--) {
    if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
      if (OrderType()==OP_BUY || OrderType()==OP_SELL) {
        if (OrderProfit()+OrderSwap()>0) ClosePosBySelect();
      }
    }
  }
  // Потом все остальные
  k=OrdersTotal();
  for (i=k-1; i>=0; i--) {
    if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
      if (OrderType()==OP_BUY || OrderType()==OP_SELL) ClosePosBySelect();
    }
  }
  if (CloseTerminal && !ExistPositions()) CloseTerminal();
}

//+----------------------------------------------------------------------------+
//|  Закрывает торговый терминал.                                              |
//+----------------------------------------------------------------------------+
void CloseTerminal() {
Print("Сработала функция CloseTerminal()");
  int hwnd=WindowHandle(Symbol(), Period());
  int hwnd_parent=0;

  while(!IsStopped()) {
    hwnd=GetParent(hwnd);
    if (hwnd==0) break;
    hwnd_parent=hwnd;
  }
  if (hwnd_parent!=0) PostMessageA(hwnd_parent, WM_CLOSE, 0, 0);
}

//+----------------------------------------------------------------------------+
//|  Автор    : Ким Игорь В. aka KimIV,  http://www.kimiv.ru                   |
//+----------------------------------------------------------------------------+
//|  Версия   : 28.11.2006                                                     |
//|  Описание : Удаление ордеров                                               |
//+----------------------------------------------------------------------------+
//|  Параметры:                                                                |
//|    sy - наименование инструмента   (""   - любой символ,                   |
//|                                     NULL - текущий символ)                 |
//|    op - операция                   (-1   - любой ордер)                    |
//|    mn - MagicNumber                (-1   - любой магик)                    |
//+----------------------------------------------------------------------------+
void DeleteOrders(string sy="", int op=-1, int mn=-1) {
  bool fd;
  int  err, i, it, k=OrdersTotal(), ot;

  if (sy=="0") sy=Symbol();
  for (i=k-1; i>=0; i--) {
    if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
      ot=OrderType();
      if (ot>1 && ot<6) {
        if ((OrderSymbol()==sy || sy=="") && (op<0 || ot==op)) {
          if (mn<0 || OrderMagicNumber()==mn) {
            for (it=1; it<=NumberOfTry; it++) {
              if (!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;
              while (!IsTradeAllowed()) Sleep(5000);
              fd=OrderDelete(OrderTicket(), clDelete);
              if (fd) {
                if (UseSound) PlaySound(NameFileSound); break;
              } else {
                err=GetLastError();
                Print("Error(",err,") delete order ",GetNameOP(ot),": ",ErrorDescription(err),", try ",it);
                Sleep(1000*5);
              }
            }
          }
        }
      }
    }
  }
}

//+----------------------------------------------------------------------------+
//|  Возвращает флаг существования позиций                                     |
//|  Параметры:                                                                |
//|    sy - наименование инструмента   (""   - любой символ,                   |
//|                                     NULL - текущий символ)                 |
//|    op - операция                   (-1   - любая позиция)                  |
//|    mn - MagicNumber                (-1   - любой магик)                    |
//+----------------------------------------------------------------------------+
bool ExistPositions(string sy="", int op=-1, int mn=-1) {
  int i, k=OrdersTotal();

  if (StringLen(sy)==1 && StringGetChar(sy, 0)==48) sy=Symbol();
  for (i=0; i<k; i++) {
    if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
      if (OrderSymbol()==sy || sy=="") {
        if (OrderType()==OP_BUY || OrderType()==OP_SELL) {
          if (op<0 || OrderType()==op) {
            if (mn<0 || OrderMagicNumber()==mn) return(True);
          }
        }
      }
    }
  }
  return(False);
}

//+----------------------------------------------------------------------------+
//|  Возвращает наименование операции                                          |
//+----------------------------------------------------------------------------+
string GetNameOP(int op) {
	switch (op) {
		case OP_BUY      : return("Buy");
		case OP_SELL     : return("Sell");
		case OP_BUYLIMIT : return("Buy Limit");
		case OP_SELLLIMIT: return("Sell Limit");
		case OP_BUYSTOP  : return("Buy Stop");
		case OP_SELLSTOP : return("Sell Stop");
		default          : return("Unknown Operation");
	}
}

//+----------------------------------------------------------------------------+
//|  Вывод сообщения в коммент и в журнал                                      |
//+----------------------------------------------------------------------------+
void Message(string m) {
  Comment(m);
  if (StringLen(m)>0) Print(m);
}
//+----------------------------------------------------------------------------+

