//+------------------------------------------------------------------+
//|                                              e-mdrNightTrade.mq4 |
//|                                           Ким Игорь В. aka KimIV |
//|                                              http://www.kimiv.ru |
//|                                                                  |
//|  14.02.2006  Ночные покупки. Мультидневная версия.               |
//|  21.02.2006  К поддержке USDJPY добавил USDCHF.                  |
//|  21.02.2006  Добавил поддержку EURUSD и GBPUSD.                  |
//|  23.02.2006  Версия для OnLine-торговли.                         |
//+------------------------------------------------------------------+
#property copyright "Ким Игорь В. aka KimIV"
#property link      "http://www.kimiv.ru"

//------- Внешние параметры советника --------------------------------
extern string _P_Expert = "---------- Параметры советника";
extern int    MAGIC         = 20060223;
extern bool   UseOneAccount = True;         // Торговать только на одном счёте
extern int    NumberAccount = 5596;        // Номер торгового счёта
extern string Name_Expert   = "e-mdrNightTrade";
extern bool   UseSound      = False;        // Использовать звуковой сигнал
extern string NameFileSound = "expert.wav"; // Наименование звукового файла
extern bool   ShowComment   = True;         // Показывать комментарии

extern string _P_Trade = "---------- Параметры торговли";
extern int Slippage        = 3;      // Проскальзывание цены
extern int NumberOfTry     = 7;      // Количество попыток
extern int PauseAfterError = 21;     // Пауза после ошибки в секундах

//---- Глобальные переменные советника -------------------------------
color clOpenBuy   = LightBlue;
color clOpenSell  = LightCoral;
color clCloseBuy  = Blue;
color clCloseSell = Red;
bool  bCanTrade, bTradeBuy;
int   HourOpenPos, MinuteOpenPos;  // Время открытия позиции
int   DepthHistory, RangeCutOff;   // Для анализа движения
int   StopLoss, TakeProfit;        // Размеры стопа и тэйка
int   HourClosePos;                // Час закрытия позиции

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


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

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
void start() {
  if (!IsTesting()) {
    if (UseOneAccount && AccountNumber()!=NumberAccount) {
      Comment("На счёте "+AccountNumber()+" торговля ЗАПРЕЩЕНА!");
      return;
    } else Comment("");
    if (Period()>PERIOD_M15) {
      Comment("Советник "+Name_Expert+" НЕ поддерживает ТФ выше M15!");
      return;
    } else Comment("");
  }

  if (InitParameters()) {
    if (Hour()==HourOpenPos
    && Minute()>=MinuteOpenPos && Minute()<=MinuteOpenPos+4) OpenPositions();

    if (!IsTesting() && ShowComment) {
      Lots=GetSizeLot();
      Comment("TimeOpen="+toTime(HourOpenPos, MinuteOpenPos)+
              "  Lots="+DoubleToStr(Lots, 1)+
              "  LS="+StopLoss+" п.  TP="+TakeProfit+" п."+
              "  TimeClose="+toTime(HourClosePos));
    }
    if (Hour()==HourClosePos) CloseAllPositions();
  }
}

//+------------------------------------------------------------------+
//| Инициализация параметров                                         |
//+------------------------------------------------------------------+
bool InitParameters() {
  if (Symbol()=="EURUSD") {
    bTradeBuy=False;
    switch (DayOfWeek()) {
      case 1:
        HourOpenPos=23;
        MinuteOpenPos=30;
        DepthHistory=36;
        RangeCutOff=10;
        StopLoss=32;
        TakeProfit=38;
        HourClosePos=15;
        return(True);
      case 2:
        HourOpenPos=23;
        MinuteOpenPos=45;
        DepthHistory=16;
        RangeCutOff=4;
        StopLoss=36;
        TakeProfit=28;
        HourClosePos=3;
        return(True);
      case 3:
        HourOpenPos=23;
        MinuteOpenPos=45;
        DepthHistory=14;
        RangeCutOff=12;
        StopLoss=66;
        TakeProfit=20;
        HourClosePos=2;
        return(True);
      case 4:
        HourOpenPos=23;
        MinuteOpenPos=0;
        DepthHistory=36;
        RangeCutOff=24;
        StopLoss=66;
        TakeProfit=36;
        HourClosePos=15;
        return(True);
      case 5:
        HourOpenPos=21;
        MinuteOpenPos=45;
        DepthHistory=28;
        RangeCutOff=6;
        StopLoss=32;
        TakeProfit=50;
        HourClosePos=3;
        return(True);
    }
  } else if (Symbol()=="GBPUSD") {
    bTradeBuy=False;
    switch (DayOfWeek()) {
      case 1:
        HourOpenPos=23;
        MinuteOpenPos=15;
        DepthHistory=30;
        RangeCutOff=14;
        StopLoss=38;
        TakeProfit=27;
        HourClosePos=14;
        return(True);
      case 2:
        HourOpenPos=23;
        MinuteOpenPos=0;
        DepthHistory=14;
        RangeCutOff=18;
        StopLoss=32;
        TakeProfit=36;
        HourClosePos=3;
        return(True);
      case 3:
        HourOpenPos=23;
        MinuteOpenPos=0;
        DepthHistory=26;
        RangeCutOff=34;
        StopLoss=46;
        TakeProfit=22;
        HourClosePos=2;
        return(True);
      case 4:
        HourOpenPos=23;
        MinuteOpenPos=0;
        DepthHistory=32;
        RangeCutOff=27;
        StopLoss=37;
        TakeProfit=20;
        HourClosePos=4;
        return(True);
      case 5:
        HourOpenPos=21;
        MinuteOpenPos=45;
        DepthHistory=8;
        RangeCutOff=22;
        StopLoss=30;
        TakeProfit=20;
        HourClosePos=3;
        return(True);
    }
  } else if (Symbol()=="USDCHF") {
    bTradeBuy=True;
    switch (DayOfWeek()) {
      case 1:
        HourOpenPos=23;
        MinuteOpenPos=0;
        DepthHistory=8;
        RangeCutOff=4;
        StopLoss=38;
        TakeProfit=48;
        HourClosePos=15;
        return(True);
      case 2:
        HourOpenPos=23;
        MinuteOpenPos=45;
        DepthHistory=30;
        RangeCutOff=20;
        StopLoss=64;
        TakeProfit=36;
        HourClosePos=3;
        return(True);
      case 3:
        HourOpenPos=23;
        MinuteOpenPos=15;
        DepthHistory=12;
        RangeCutOff=12;
        StopLoss=60;
        TakeProfit=58;
        HourClosePos=3;
        return(True);
      case 4:
        HourOpenPos=23;
        MinuteOpenPos=30;
        DepthHistory=44;
        RangeCutOff=42;
        StopLoss=48;
        TakeProfit=62;
        HourClosePos=13;
        return(True);
      case 5:
        HourOpenPos=21;
        MinuteOpenPos=45;
        DepthHistory=40;
        RangeCutOff=40;
        StopLoss=40;
        TakeProfit=60;
        HourClosePos=13;
        return(True);
    }
  } else if (Symbol()=="USDJPY") {
    bTradeBuy=True;
    switch (DayOfWeek()) {
      case 1:
        HourOpenPos=22;
        MinuteOpenPos=45;
        DepthHistory=6;
        RangeCutOff=6;
        StopLoss=30;
        TakeProfit=16;
        HourClosePos=0;
        return(True);
      case 2:
        HourOpenPos=22;
        MinuteOpenPos=45;
        DepthHistory=32;
        RangeCutOff=26;
        StopLoss=56;
        TakeProfit=16;
        HourClosePos=6;
        return(True);
      case 3:
        HourOpenPos=20;
        MinuteOpenPos=45;
        DepthHistory=60;
        RangeCutOff=40;
        StopLoss=48;
        TakeProfit=14;
        HourClosePos=3;
        return(True);
      case 4:
        HourOpenPos=22;
        MinuteOpenPos=0;
        DepthHistory=16;
        RangeCutOff=9;
        StopLoss=48;
        TakeProfit=14;
        HourClosePos=1;
        return(True);
      case 5:
        HourOpenPos=17;
        MinuteOpenPos=30;
        DepthHistory=4;
        RangeCutOff=14;
        StopLoss=48;
        TakeProfit=16;
        HourClosePos=3;
        return(True);
    }
  } else {
    Comment("Советник НЕ поддерживает работу с "+Symbol());
    return(False);
  }
}

//+------------------------------------------------------------------+
//| Добавляет "0"                                                    |
//+------------------------------------------------------------------+
string AddZero(string s) {
  switch (StringLen(s)) {
    case 0: s="00"; return(s);
    case 1: s="0"+s; return(s);
    case 2: return(s);
    default: return(StringSubstr(s,StringLen(s)-2));
  }
}

//+------------------------------------------------------------------+
//| Преобразует два целых числа в формат времени                     |
//+------------------------------------------------------------------+
string toTime(int h=0, int m=0, int s=0) {
  string st="";

  if (h==0) st="00:"; else st=AddZero(h)+":";
  if (m==0) st=st+"00"; else st=st+AddZero(m);
  if (s!=0) st=st+":"+AddZero(s);

  return(st);
}

//+------------------------------------------------------------------+
//| Открытие позиций                                                 |
//+------------------------------------------------------------------+
void OpenPositions() {
  double ldStop=0, ldTake=0;
  int    bs=GetTradeSignal();

  if (!ExistPosition()) {
    if (bs>0) {
      if (StopLoss!=0) ldStop=Ask-StopLoss*Point;
      if (TakeProfit!=0) ldTake=Ask+TakeProfit*Point;
      OpenPosition(OP_BUY, ldStop, ldTake);
    }
    if (bs<0) {
      if (StopLoss!=0) ldStop=Bid+StopLoss*Point;
      if (TakeProfit!=0) ldTake=Bid-TakeProfit*Point;
      OpenPosition(OP_SELL, ldStop, ldTake);
    }
  }
}

//+------------------------------------------------------------------+
//| Возвращает торговый сигнал:                                      |
//|    1 - покупай                                                   |
//|    0 - сиди, кури бамбук                                         |
//|   -1 - продавай                                                  |
//+------------------------------------------------------------------+
int GetTradeSignal() {
  int bs=0, nb;

  if (bTradeBuy) {
    nb=Highest(NULL, 15, MODE_HIGH, DepthHistory, 1);
    if (High[nb]-Close[1]>RangeCutOff*Point) bs=1;
  } else {
    nb=Lowest(NULL, 15, MODE_LOW, DepthHistory, 1);
    if (Close[1]-Low[nb]>RangeCutOff*Point) bs=-1;
  }

  return(bs);
}

//+------------------------------------------------------------------+
//| Возвращает флаг существования позиции                            |
//+------------------------------------------------------------------+
bool ExistPosition() {
  bool Exist=False;
  for (int i=0; i<OrdersTotal(); i++) {
    if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
      if (OrderSymbol()==Symbol() && OrderMagicNumber()==MAGIC) {
        if (OrderType()==OP_BUY || OrderType()==OP_SELL) {
          Exist=True; break;
        }
      }
    }
  }
  return(Exist);
}

//+------------------------------------------------------------------+
//| Открытие позиции                                                 |
//| Параметры:                                                       |
//|   op     - операция                                              |
//|   ldStop - уровень стоп                                          |
//|   ldTake - уровень тейк                                          |
//+------------------------------------------------------------------+
void OpenPosition(int op, double ldStop, double ldTake) {
  color  clOpen;
  double pp;
  int    err, it, ticket;
  string lsComm=GetCommentForOrder();

  if (op==OP_BUY) clOpen=clOpenBuy; else clOpen=clOpenSell;
  Lots=GetSizeLot();
  for (it=1; it<=NumberOfTry; it++) {
    while (!IsTradeAllowed()) Sleep(5000);
    RefreshRates();
    if (op==OP_BUY) pp=Ask; else pp=Bid;
    pp=NormalizeDouble(pp, Digits);
    ticket=OrderSend(Symbol(),op,Lots,pp,Slippage,ldStop,ldTake,lsComm,MAGIC,0,clOpen);
    if (ticket>0) {
      if (UseSound) PlaySound(NameFileSound); break;
    } else {
      err=GetLastError();
      Print("Error(",err,") opening position: ",ErrorDescription(err),", try ",it);
      Sleep(1000*PauseAfterError);
    }
  }
}

//+------------------------------------------------------------------+
//| Генерирует и возвращает строку коментария для ордера или позиции |
//+------------------------------------------------------------------+
string GetCommentForOrder() {
  return(Name_Expert+" "+GetNameTF(Period()));
}

//+------------------------------------------------------------------+
//| Возвращает наименование таймфрейма                               |
//+------------------------------------------------------------------+
string GetNameTF(int TimeFrame) {
	switch (TimeFrame) {
		case PERIOD_MN1: return("Monthly");
		case PERIOD_W1:  return("Weekly");
		case PERIOD_D1:  return("Daily");
		case PERIOD_H4:  return("H4");
		case PERIOD_H1:  return("H1");
		case PERIOD_M30: return("M30");
		case PERIOD_M15: return("M15");
		case PERIOD_M5:  return("M5");
		case PERIOD_M1:  return("M1");
		default:		     return("UnknownPeriod");
	}
}

//+------------------------------------------------------------------+
//| Закрытие всех позиций по рыночной цене                           |
//+------------------------------------------------------------------+
void CloseAllPositions() {
  bool fc;
  int  err, it;

  for (int i=OrdersTotal()-1; i>=0; i--) {
    if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
      if (OrderSymbol()==Symbol() && OrderMagicNumber()==MAGIC) {
        fc=False;
        for (it=1; it<=NumberOfTry; it++) {
          while (!IsTradeAllowed()) Sleep(5000);
          RefreshRates();
          if (OrderType()==OP_BUY) {
            fc=OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, clCloseBuy);
            if (fc) {
              if (UseSound) PlaySound(NameFileSound); break;
            } else {
              err=GetLastError();
              Print("Error(",err,") closing buy: ",ErrorDescription(err),", try ",it);
              Sleep(1000*PauseAfterError);
            }
          }
          if (OrderType()==OP_SELL) {
            fc=OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, clCloseSell);
            if (fc) {
              if (UseSound) PlaySound(NameFileSound); break;
            } else {
              err=GetLastError();
              Print("Error(",err,") closing sell: ",ErrorDescription(err),", try ",it);
              Sleep(1000*PauseAfterError);
            }
          }
        }
      }
    }
  }
}
//+------------------------------------------------------------------+

