//+------------------------------------------------------------------+
//|                                                   SafeTradePro.mq4 |
//|                                                   Copyright © 2010 |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2010"
#property link      ""
#property version   "1.01"

#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Red      // Стрелка вниз (сигнал SELL)
#property indicator_color2 Blue     // Стрелка вверх (сигнал BUY)

//-- Внешние параметры
extern bool AlertOn = true;                 // Включить всплывающие оповещения
extern bool EmailOn = false;                 // Включить email оповещения
extern bool SignalOnClosedCandle = true;     // Сигнал только на закрытой свече

//-- Глобальные переменные
string TrendText = "";              // Текст текущего тренда
string PriceConditionText = "";      // Текст состояния цены
int Trend = 0;                       // Направление последнего сигнала (1 = Buy, -1 = Sell)
int SignalCandle = 0;                 // Смещение для сигнала (0 или 1)

//-- Буферы индикатора
double BuyArrowBuffer[];   // Буфер для синих стрелок (BUY)
double SellArrowBuffer[];  // Буфер для красных стрелок (SELL)

//+------------------------------------------------------------------+
//| Функция инициализации индикатора                                 |
//+------------------------------------------------------------------+
void init() 
{
   //-- Настройка буферов
   SetIndexBuffer(0, SellArrowBuffer);  // Красная стрелка (продажа)
   SetIndexBuffer(1, BuyArrowBuffer);   // Синяя стрелка (покупка)
   
   //-- Пустые значения
   SetIndexEmptyValue(0, 0);
   SetIndexEmptyValue(1, 0);
   
   //-- Стиль отрисовки - стрелки
   SetIndexStyle(0, DRAW_ARROW);
   SetIndexArrow(0, 234); // Красная стрелка вниз (сигнал SELL)
   
   SetIndexStyle(1, DRAW_ARROW);
   SetIndexArrow(1, 233); // Синяя стрелка вверх (сигнал BUY)
   
   //-- Учет параметра SignalOnClosedCandle
   if (SignalOnClosedCandle) 
      SignalCandle = 1;
   else 
      SignalCandle = 0;
}

//+------------------------------------------------------------------+
//| Основная функция                                                 |
//+------------------------------------------------------------------+
void start() 
{
   int countedBars = IndicatorCounted();
   int limit, i;
   double arrowOffset;
   
   //-- Расчет среднего диапазона цены для отступа стрелок
   arrowOffset = 0;
   for(i = 1; i <= 20; i++) 
      arrowOffset += 0.3 * (High[i] - Low[i]) / 20.0;
   
   //-- Определение текущего тренда по EMA на H1
   double emaFast = iMA(NULL, PERIOD_H1, 50, 0, MODE_EMA, PRICE_MEDIAN, 0);
   double emaSlow = iMA(NULL, PERIOD_H1, 200, 0, MODE_EMA, PRICE_MEDIAN, 0);
   
   if(emaFast > emaSlow) 
      TrendText = "UP Trend/Buy";
   if(emaSlow > emaFast) 
      TrendText = "Down Trend/Sell";
   
   //-- Определение состояния цены по стохастику
   double stochMain = iStochastic(NULL, 0, 9, 3, 3, MODE_EMA, 0, MODE_MAIN, 0);
   
   if(stochMain > 70.0) 
      PriceConditionText = "OverBought / Wave Reversal or Breakout!";
   else if(stochMain < 30.0) 
      PriceConditionText = "OverSold / Wave Reversal or Breakout!";
   else 
      PriceConditionText = "In Trend Channel";
   
   //-- Расчет количества баров для обработки
   if(countedBars >= 0) 
   {
      if(countedBars > 0) 
         countedBars--;
      
      limit = MathMin(Bars - countedBars, 400); // Максимум 400 баров
      
      //-- Основной цикл расчета сигналов
      for(i = 10; i <= limit + 10; i++) 
      {
         SellArrowBuffer[i] = 0;
         BuyArrowBuffer[i] = 0;
         
         //-- Сигнал на продажу (красная стрелка вниз)
         if(IsSellSignal(i, 10) == 1) 
            SellArrowBuffer[i] = High[i] + arrowOffset;
         
         //-- Сигнал на покупку (синяя стрелка вверх)
         if(IsBuySignal(i, 10) == 1) 
            BuyArrowBuffer[i] = Low[i] - arrowOffset;
      }
   }
   
   //-- Генерация оповещений о сигналах
   for(i = SignalCandle; i <= 10; i++) 
   {
      //-- Сигнал на покупку
      if(BuyArrowBuffer[i] > 0.0 && Trend < 1) 
      {
         if(AlertOn) 
            Alert("STP Buy Alert on ", Symbol(), " [", Period(), "m]");
         
         if(EmailOn) 
            SendMail("STP Buy Alert!", "Buy alert on " + Symbol() + " [" + Period() + "m]");
         
         Trend = 1; // Запоминаем, что был сигнал на покупку
         break;
      }
      //-- Сигнал на продажу
      else if(SellArrowBuffer[i] > 0.0 && Trend > -1) 
      {
         if(AlertOn) 
            Alert("STP Sell Alert on ", Symbol(), " [", Period(), "m]");
         
         if(EmailOn) 
            SendMail("STP Sell Alert!", "Sell alert on " + Symbol() + " [" + Period() + "m]");
         
         Trend = -1; // Запоминаем, что был сигнал на продажу
      }
   }
}

//+------------------------------------------------------------------+
//| Проверка сигнала на покупку (синяя стрелка вверх)                |
//| Ищет локальный минимум                                           |
//+------------------------------------------------------------------+
int IsBuySignal(int barIndex, int searchDepth) 
{
   bool isMinimum = TRUE;
   
   for(int j = 3; j <= searchDepth; j++) 
   {
      //-- Проверка границ массива
      if(barIndex + j >= Bars || barIndex - j < 0) 
         return (0);
      
      //-- Проверяем, является ли текущий минимум самым низким
      isMinimum = isMinimum && 
                  Low[barIndex] <= Low[barIndex + j] && 
                  Low[barIndex] <= Low[barIndex - j];
   }
   
   return (isMinimum);
}

//+------------------------------------------------------------------+
//| Проверка сигнала на продажу (красная стрелка вниз)               |
//| Ищет локальный максимум                                          |
//+------------------------------------------------------------------+
int IsSellSignal(int barIndex, int searchDepth) 
{
   bool isMaximum = TRUE;
   
   for(int j = 3; j <= searchDepth; j++) 
   {
      //-- Проверка границ массива
      if(barIndex + j >= Bars || barIndex - j < 0) 
         return (0);
      
      //-- Проверяем, является ли текущий máximo самым высоким
      isMaximum = isMaximum && 
                  High[barIndex] >= High[barIndex + j] && 
                  High[barIndex] >= High[barIndex - j];
   }
   
   return (isMaximum);
}
//+------------------------------------------------------------------+
