#property copyright "Исправлено"
#property link      ""
#property version   "1.03"
#property strict

#include <Trade\Trade.mqh>   // Для CTrade

//--------------------------------------------------------------------
// Внешние параметры
//--------------------------------------------------------------------
input group "Индикатор Parabolic"
input double  ParabolicStep          = 0.02;    // Шаг параболика
input double  ParabolicMax           = 0.2;     // Максимум параболика

input group "Управление капиталом"
input double  Lots                   = 0.01;    // Фиксированный размер лота
input int     StopLossPoints         = 100;     // Желаемый Stop Loss в пунктах (0 - не ставить)
input int     TakeProfitPoints       = 200;     // Желаемый Take Profit в пунктах (0 - не ставить)
//input double  Risk                   = 1.0;     // Риск на сделку в % (пока не используется)

input group "Управление ордерами"
input int     MaxOpenPositionsInDir  = 1;       // Макс. позиций в одном направлении
input long    MagicNumber            = 12345;   // Мэджик ордеров
input int     SlippagePoints         = 5;       // Допустимое проскальзывание в пунктах

input group "Фильтр MA"
input bool    UseMAFilter            = true;    // Использовать фильтр MA?
input ENUM_MA_METHOD MA_Method       = MODE_SMA;// Метод сглаживания
input int     MA_Period              = 50;      // Период MA
input ENUM_APPLIED_PRICE MA_Price    = PRICE_CLOSE; // Тип цены для MA

input group "Фильтр RSI"
input bool    UseRSIFilter           = true;   // Использовать фильтр RSI?
input int     RSI_Period             = 14;      // Период RSI
input double  RSI_Upper              = 70.0;    // Верхний уровень RSI
input double  RSI_Lower              = 30.0;    // Нижний уровень RSI

//--------------------------------------------------------------------
// Глобальные объекты и переменные
//--------------------------------------------------------------------
CTrade trade;   // Класс для работы с торговыми операциями

int sar_handle     = INVALID_HANDLE;
int ma_handle_main = INVALID_HANDLE; // Для основного ТФ
int rsi_handle     = INVALID_HANDLE;

int   g_lastSignalDirection = 0;
int   g_signalCount         = 0;
bool  g_tradeOpenedOnSignal = false; // Флаг, что по ПОСЛЕДНЕЙ серии сигналов уже открылись

//--- Для хранения хэндлов MA на других ТФ (для CheckTrendOnAllTF)
int ma_handles_other_tf[5];
ENUM_TIMEFRAMES other_timeframes[] = {PERIOD_M5, PERIOD_M15, PERIOD_H1, PERIOD_H4, PERIOD_D1};

//--------------------------------------------------------------------
// Функция инициализации (OnInit)
//--------------------------------------------------------------------
int OnInit()
{
  //--- Инициализация торгового объекта
  trade.SetExpertMagicNumber(MagicNumber);
  trade.SetDeviationInPoints(SlippagePoints);
  trade.SetTypeFillingBySymbol(_Symbol); // Установка политики исполнения по символу

  //--- Хэндл Parabolic
  sar_handle = iSAR(_Symbol, _Period, ParabolicStep, ParabolicMax);
  if(sar_handle == INVALID_HANDLE)
  {
    Print("Не удалось создать хэндл Parabolic SAR. Код ошибки: ", GetLastError());
    return INIT_FAILED;
  }

  //--- Хэндл MA для основного фильтра
  if(UseMAFilter)
  {
    ma_handle_main = iMA(_Symbol, _Period, MA_Period, 0, MA_Method, MA_Price);
    if(ma_handle_main == INVALID_HANDLE)
    {
      Print("Не удалось создать хэндл основного MA. Код ошибки: ", GetLastError());
      return INIT_FAILED;
    }
  }

  //--- Хэндл RSI
  if(UseRSIFilter)
  {
    rsi_handle = iRSI(_Symbol, _Period, RSI_Period, PRICE_CLOSE);
    if(rsi_handle == INVALID_HANDLE)
    {
      Print("Не удалось создать хэндл RSI. Код ошибки: ", GetLastError());
      return INIT_FAILED;
    }
  }

  //--- Хэндлы MA для других ТФ
  for(int i = 0; i < ArraySize(other_timeframes); i++)
  {
    ma_handles_other_tf[i] = iMA(_Symbol, other_timeframes[i], MA_Period, 0, MA_Method, MA_Price);
    if(ma_handles_other_tf[i] == INVALID_HANDLE)
      Print("Не удалось создать MA для ", EnumToString(other_timeframes[i]), ". Ошибка: ", GetLastError());
  }

  g_lastSignalDirection = 0;
  g_signalCount         = 0;
  g_tradeOpenedOnSignal = false;

  Print("Советник ", MQLInfoString(MQL_PROGRAM_NAME), 
      " v", _version, 
      " инициализирован.");
  Print("Символ: ", _Symbol, ", ТФ: ", EnumToString(_Period));
  Print("Параметры: Lots=", Lots, ", SL_pips=", StopLossPoints, ", TP_pips=", TakeProfitPoints, ", Magic=", MagicNumber);
  Print("Фильтры: MA=", (UseMAFilter?"On":"Off"), ", RSI=", (UseRSIFilter?"On":"Off"));
  return INIT_SUCCEEDED;
}

//--------------------------------------------------------------------
// Функция деинициализации (OnDeinit)
//--------------------------------------------------------------------
void OnDeinit(const int reason)
{
  if(sar_handle     != INVALID_HANDLE) IndicatorRelease(sar_handle);
  if(ma_handle_main != INVALID_HANDLE) IndicatorRelease(ma_handle_main);
  if(rsi_handle     != INVALID_HANDLE) IndicatorRelease(rsi_handle);

  for(int i = 0; i < ArraySize(ma_handles_other_tf); i++)
  {
    if(ma_handles_other_tf[i] != INVALID_HANDLE)
      IndicatorRelease(ma_handles_other_tf[i]);
  }

  Print("Советник ", MQLInfoString(MQL_PROGRAM_NAME), " деинициализирован. Причина: ", reason);
}

//--------------------------------------------------------------------
// Основная функция, вызывается при каждом тике (OnTick)
//--------------------------------------------------------------------
void OnTick()
{
  // --- Получаем цены ---
  MqlTick latest_tick;
  if(!SymbolInfoTick(_Symbol, latest_tick))
  {
    Print("Ошибка получения тика для ", _Symbol, ": ", GetLastError());
    return;
  }
  double ask_price = latest_tick.ask;
  double bid_price = latest_tick.bid;
  // Для сравнения с SAR лучше брать цену закрытия предыдущего бара
  double close_price_prev_bar_arr[1];
  if(CopyClose(_Symbol, _Period, 1, 1, close_price_prev_bar_arr) < 1)
  {
     Print("Ошибка получения цены закрытия");
     return;
  }
  double close_price_prev_bar = close_price_prev_bar_arr[0];

  // --- Считываем Parabolic SAR ---
  // Нужны два значения для определения момента разворота
  double sar_value[2];
  if(CopyBuffer(sar_handle, 0, 0, 2, sar_value) < 2)
  {
    Print("Не удалось прочитать данные Parabolic SAR. ", GetLastError());
    return;
  }
  double parabolic_current = sar_value[0];
  double parabolic_prev    = sar_value[1];

  // --- Определяем направление сигнала ---
  int currentSignalDirection = 0;
  // Сигнал на покупку: SAR развернулся под цену (или уже под ценой)
  if(parabolic_current < close_price_prev_bar)
    currentSignalDirection = 1;
  // Сигнал на продажу: SAR развернулся над ценой (или уже над ценой)
  else if(parabolic_current > close_price_prev_bar)
    currentSignalDirection = -1;

  if(currentSignalDirection == 0) return;

  // --- Логика "третьего подряд сигнала" (подряд баров с SAR в одном положении) ---
  if(currentSignalDirection == g_lastSignalDirection)
  {
    g_signalCount++;
  }
  else
  {
    g_signalCount         = 1; // Первый бар с новым направлением
    g_lastSignalDirection = currentSignalDirection;
    g_tradeOpenedOnSignal = false; // Сброс флага при смене направления
  }

  // --- Проверка условий для входа ---
  // Ждем 3-го бара с одинаковым сигналом и если еще не входили по этой серии
  if(g_signalCount >= 3 && !g_tradeOpenedOnSignal)
  {
    if(currentSignalDirection == 1) // --- Условия для BUY ---
    {
      if(UseMAFilter && !CheckMAFilter(1)) return;
      if(UseRSIFilter && !CheckRSIFilter(1)) return;
      if(!CheckTrendOnAllTF(1)) return;
      if(!CanOpenAnotherPosition(ORDER_TYPE_BUY)) return;

      // --- Открытие BUY ---
      if(OpenOrder(ORDER_TYPE_BUY, Lots, StopLossPoints, TakeProfitPoints, "Buy_Parabolic"))
      {
        g_tradeOpenedOnSignal = true; // Вход по этой серии сигналов выполнен
      }
    }
    else if(currentSignalDirection == -1) // --- Условия для SELL ---
    {
      if(UseMAFilter && !CheckMAFilter(-1)) return;
      if(UseRSIFilter && !CheckRSIFilter(-1)) return;
      if(!CheckTrendOnAllTF(-1)) return;
      if(!CanOpenAnotherPosition(ORDER_TYPE_SELL)) return;

      // --- Открытие SELL ---
      if(OpenOrder(ORDER_TYPE_SELL, Lots, StopLossPoints, TakeProfitPoints, "Sell_Parabolic"))
      {
        g_tradeOpenedOnSignal = true; // Вход по этой серии сигналов выполнен
      }
    }
  }
}

//--------------------------------------------------------------------
// Функция открытия ордера (исправленная, с CTrade)
//--------------------------------------------------------------------
bool OpenOrder(const ENUM_ORDER_TYPE order_type, double lot,
               int stopLossPips, int takeProfitPips, string comment)
{
  // --- Получаем актуальные цены и параметры символа ---
  MqlTick latest_tick;
  if(!SymbolInfoTick(_Symbol, latest_tick))
  {
    Print("OpenOrder: Ошибка получения тика для ", _Symbol, ": ", GetLastError());
    return false;
  }
  double ask_price = latest_tick.ask;
  double bid_price = latest_tick.bid;
  double point_val = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
  int digits_val = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);

  // --- Получаем минимальный отступ для стопов в пунктах от брокера ---
  long stops_level_pips_long = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
  if(stops_level_pips_long < 0) stops_level_pips_long = 0;
  // SymbolInfoInteger(SYMBOL_SPREAD_FLOAT) не всегда надежен, используем _Digits
  double min_stop_distance_price;
  if (digits_val <= 3) // Для 2,3-значных инструментов (металлы, индексы)
      min_stop_distance_price = stops_level_pips_long * point_val;
  else // Для 4,5-значных (валюты)
      min_stop_distance_price = stops_level_pips_long * point_val;

  if (min_stop_distance_price <= 0) // Если брокер не дает или 0, берем спред + немного
  {
      min_stop_distance_price = (double)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) * point_val + 2 * point_val;
      Print("OpenOrder: Не удалось получить SYMBOL_TRADE_STOPS_LEVEL, используем расчетный отступ: ", NormalizeDouble(min_stop_distance_price, digits_val));
  }

  // --- Расчет уровней SL/TP ---
  double sl_price = 0.0;
  double tp_price = 0.0;
  double open_price = 0.0; // CTrade сам определит цену

  if(order_type == ORDER_TYPE_BUY)
  {
    open_price = ask_price; // Цена для расчета
    // SL для Buy
    if(stopLossPips > 0)
    {
      double requested_sl = NormalizeDouble(open_price - stopLossPips * point_val, digits_val);
      // SL должен быть ниже цены открытия и не ближе минимального отступа
      if(requested_sl < open_price - min_stop_distance_price)
        sl_price = requested_sl;
      else
      {
        sl_price = NormalizeDouble(open_price - min_stop_distance_price - point_val, digits_val);
        Print("OpenOrder BUY: Запрошенный SL (", stopLossPips, " п.) слишком близко. Устанавливаем минимально возможный: ", sl_price);
      }
    }
    // TP для Buy
    if(takeProfitPips > 0)
    {
      double requested_tp = NormalizeDouble(open_price + takeProfitPips * point_val, digits_val);
      // TP должен быть выше цены открытия и не ближе минимального отступа
      if(requested_tp > open_price + min_stop_distance_price)
        tp_price = requested_tp;
      else
      {
        tp_price = NormalizeDouble(open_price + min_stop_distance_price + point_val, digits_val);
        Print("OpenOrder BUY: Запрошенный TP (", takeProfitPips, " п.) слишком близко. Устанавливаем минимально возможный: ", tp_price);
      }
    }
  }
  else if(order_type == ORDER_TYPE_SELL)
  {
    open_price = bid_price; // Цена для расчета
    // SL для Sell
    if(stopLossPips > 0)
    {
      double requested_sl = NormalizeDouble(open_price + stopLossPips * point_val, digits_val);
      // SL должен быть выше цены открытия и не ближе минимального отступа
      if(requested_sl > open_price + min_stop_distance_price)
        sl_price = requested_sl;
      else
      {
        sl_price = NormalizeDouble(open_price + min_stop_distance_price + point_val, digits_val);
        Print("OpenOrder SELL: Запрошенный SL (", stopLossPips, " п.) слишком близко. Устанавливаем минимально возможный: ", sl_price);
      }
    }
    // TP для Sell
    if(takeProfitPips > 0)
    {
      double requested_tp = NormalizeDouble(open_price - takeProfitPips * point_val, digits_val);
      // TP должен быть ниже цены открытия и не ближе минимального отступа
      if(requested_tp < open_price - min_stop_distance_price)
        tp_price = requested_tp;
      else
      {
        tp_price = NormalizeDouble(open_price - min_stop_distance_price - point_val, digits_val);
        Print("OpenOrder SELL: Запрошенный TP (", takeProfitPips, " п.) слишком близко. Устанавливаем минимально возможный: ", tp_price);
      }
    }
  }
  else
    return false;

  // --- Нормализация лота (CTrade сделает это, но проверим) ---
  double min_lot, max_lot, step_lot, volume_limit;
  if(!SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN, min_lot) ||
     !SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX, max_lot) ||
     !SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP, step_lot) ||
     !SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_LIMIT, volume_limit))
  {
     Print("OpenOrder: Ошибка получения лимитов объема для ", _Symbol);
     return false;
  }
  double adjusted_lot = lot;
  if (adjusted_lot < min_lot) adjusted_lot = min_lot;
  if (adjusted_lot > max_lot) adjusted_lot = max_lot;
  if (volume_limit > 0 && adjusted_lot > volume_limit) adjusted_lot = volume_limit;
  adjusted_lot = MathFloor(adjusted_lot / step_lot) * step_lot;

  if(adjusted_lot <= 0)
  {
      Print("OpenOrder: Неверный лот после нормализации: ", adjusted_lot);
      return false;
  }

  // --- Отправка ордера через CTrade ---
  bool result = false;
  string sl_str = (sl_price == 0.0 ? "No" : DoubleToString(sl_price, digits_val));
  string tp_str = (tp_price == 0.0 ? "No" : DoubleToString(tp_price, digits_val));
  Print("OpenOrder: Попытка ", (order_type == ORDER_TYPE_BUY ? "BUY" : "SELL"),
        " ", _Symbol, ", Lot=", adjusted_lot, " (исходный: ", lot,
        "), SL=", sl_str, ", TP=", tp_str,
        ", Ask=", ask_price, ", Bid=", bid_price,
        ", StopsLevel(pips)=", stops_level_pips_long,
        ", MinStopDist=", NormalizeDouble(min_stop_distance_price, digits_val));

  if(order_type == ORDER_TYPE_BUY)
  {
    result = trade.Buy(adjusted_lot, _Symbol, 0, sl_price, tp_price, comment);
  }
  else if(order_type == ORDER_TYPE_SELL)
  {
    result = trade.Sell(adjusted_lot, _Symbol, 0, sl_price, tp_price, comment);
  }

  if(!result)
  {
    Print("Ошибка открытия ордера: ", trade.ResultRetcodeDescription(),
          " (", trade.ResultRetcode(), "), OrderSend Error: ", GetLastError());
    return false;
  }
  else
  {
    Print("Ордер успешно открыт: #", trade.ResultOrder(),
          ", Цена: ", trade.ResultPrice(),
          ", SL: ", sl_str, ", TP: ", tp_str);
    return true;
  }
}

//--------------------------------------------------------------------
// Функция расчета лота (ПОКА НЕ ИСПОЛЬЗУЕТСЯ, требует доработки)
//--------------------------------------------------------------------
/*
double CalculateLot(double riskPercent, int stopLossPips)
{
    if(stopLossPips <= 0) return Lots; // Если SL не задан, используем фиксированный

    double equity = AccountInfoDouble(ACCOUNT_EQUITY);
    if(equity <= 0) return Lots;

    double point_val = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    double tick_value, tick_size;
    if(!SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE, tick_value) ||
       !SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE, tick_size))
    {
        Print("CalculateLot: Ошибка получения tick_value/tick_size");
        return Lots;
    }
    if (tick_size <= 0) return Lots;
    double price_per_point = tick_value / tick_size * point_val;
    if(price_per_point <= 0)
    {
        // Попытка рассчитать для кроссов
        double lot_size = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_CONTRACT_SIZE);
        price_per_point = point_val * lot_size;
        // Нужна конвертация в валюту депозита
        // Это сложнее, CTrade::LotToMoney может помочь
        Print("CalculateLot: Не удалось точно рассчитать стоимость пункта, используем Lots");
        return Lots;
    }

    double money_risk = equity * riskPercent / 100.0;
    double sl_money_per_lot = stopLossPips * price_per_point;
    if(sl_money_per_lot <= 0) return Lots;

    double calculated_lot = money_risk / sl_money_per_lot;

    // Нормализация лота
    double min_lot, max_lot, step_lot;
    if(!SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN, min_lot) ||
       !SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX, max_lot) ||
       !SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP, step_lot))
    {
       return Lots;
    }
    if (calculated_lot < min_lot) calculated_lot = min_lot;
    if (calculated_lot > max_lot) calculated_lot = max_lot;
    calculated_lot = MathFloor(calculated_lot / step_lot) * step_lot;

    return calculated_lot;
}
*/

//--------------------------------------------------------------------
// Фильтр по MA
//--------------------------------------------------------------------
bool CheckMAFilter(int direction)
{
  if(ma_handle_main == INVALID_HANDLE) return true;

  double ma_val[1];
  if(CopyBuffer(ma_handle_main, 0, 0, 1, ma_val) < 1)
  {
    Print("CheckMAFilter: Не удалось прочитать MA");
    return false; // Ошибка чтения - лучше не торговать
  }
  double ma = ma_val[0];

  // Получаем цену, по которой строилась MA
  double price_for_ma_arr[1];
  if(CopyBuffer(ma_handle_main, 0, 1, 1, price_for_ma_arr, MA_Price, _Symbol, _Period) < 1)
  {
      // Если не можем получить, пробуем Close
      if(CopyClose(_Symbol, _Period, 1, 1, price_for_ma_arr) <1)
      {
          Print("CheckMAFilter: Не удалось получить цену для сравнения с MA");
          return false;
      }
  }
  double price_for_ma = price_for_ma_arr[0];

  if(direction == 1 && price_for_ma < ma) return false; // Цена ниже MA для покупки
  if(direction == -1 && price_for_ma > ma) return false; // Цена выше MA для продажи

  return true;
}

//--------------------------------------------------------------------
// Фильтр по RSI
//--------------------------------------------------------------------
bool CheckRSIFilter(int direction)
{
  if(rsi_handle == INVALID_HANDLE) return true;

  double rsi_val[1];
  if(CopyBuffer(rsi_handle, 0, 1, 1, rsi_val) < 1) // Берем значение с предыдущего бара
  {
    Print("CheckRSIFilter: Не удалось прочитать RSI");
    return false; // Ошибка чтения - лучше не торговать
  }
  double rsi = rsi_val[0];

  if(direction == 1 && rsi > RSI_Upper) return false; // Перекупленность для покупки
  if(direction == -1 && rsi < RSI_Lower) return false; // Перепроданность для продажи

  return true;
}

//--------------------------------------------------------------------
// Проверка тренда на всех таймфреймах (по MA)
//--------------------------------------------------------------------
bool CheckTrendOnAllTF(int direction)
{
  for(int i=0; i<ArraySize(other_timeframes); i++)
  {
    if(ma_handles_other_tf[i] == INVALID_HANDLE) continue; // Пропускаем, если хэндл не создан

    double ma_val[1];
    if(CopyBuffer(ma_handles_other_tf[i], 0, 0, 1, ma_val) < 1)
    {
      // Не блокируем торговлю, если не удалось прочитать, но сообщаем
      Print("CheckTrendOnAllTF: Не удалось прочитать MA для ", EnumToString(other_timeframes[i]));
      continue;
    }
    double ma = ma_val[0];

    // Получаем цену для сравнения
    double price_for_ma_arr[1];
    if(CopyBuffer(ma_handles_other_tf[i], 0, 1, 1, price_for_ma_arr, MA_Price, _Symbol, other_timeframes[i]) < 1)
    {
      if(CopyClose(_Symbol, other_timeframes[i], 1, 1, price_for_ma_arr)<1)
         continue;
    }
    double price_for_ma = price_for_ma_arr[0];

    if(direction == 1 && price_for_ma < ma) return false; // Тренд вниз на старшем ТФ
    if(direction == -1 && price_for_ma > ma) return false; // Тренд вверх на старшем ТФ
  }
  return true;
}

//--------------------------------------------------------------------
// Проверить, можем ли мы открыть ещё одну позицию в ту же сторону
// (Исправлено)
//--------------------------------------------------------------------
bool CanOpenAnotherPosition(ENUM_ORDER_TYPE order_type_to_open)
{
  int positions_in_direction = 0;
  uint total_positions = PositionsTotal();

  for(uint i=0; i<total_positions; i++)
  {
    ulong ticket = PositionGetTicket(i);
    if(ticket > 0)
    {
      if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
         PositionGetInteger(POSITION_MAGIC) == MagicNumber)
      {
        ENUM_POSITION_TYPE pos_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
        if((order_type_to_open == ORDER_TYPE_BUY && pos_type == POSITION_TYPE_BUY) ||
           (order_type_to_open == ORDER_TYPE_SELL && pos_type == POSITION_TYPE_SELL))
        {
          positions_in_direction++;
        }
      }
    }
  }

  return (positions_in_direction < MaxOpenPositionsInDir);
}

//--- Вспомогательная функция для копирования буфера цены
int CopyBuffer(int handle, int buffer_num, int start_pos, int count, double &arr[],
                ENUM_APPLIED_PRICE price_type, string symbol, ENUM_TIMEFRAMES tf)
{
   MqlRates rates[];
   int copied = CopyRates(symbol, tf, price_type, start_pos, count, rates);
   if(copied <= 0) return -1;
   ArrayResize(arr, copied);
   for(int i=0; i<copied; i++)
   {
      switch(price_type)
      {
         case PRICE_CLOSE:     arr[i] = rates[i].close; break;
         case PRICE_OPEN:      arr[i] = rates[i].open; break;
         case PRICE_HIGH:      arr[i] = rates[i].high; break;
         case PRICE_LOW:       arr[i] = rates[i].low; break;
         case PRICE_MEDIAN:    arr[i] = (rates[i].high+rates[i].low)/2.0; break;
         case PRICE_TYPICAL:   arr[i] = (rates[i].high+rates[i].low+rates[i].close)/3.0; break;
         case PRICE_WEIGHTED:  arr[i] = (rates[i].high+rates[i].low+rates[i].close*2.0)/4.0; break;
         default: arr[i] = rates[i].close;
      }
   }
   return copied;
}

'_version' - undeclared identifier	параболик.mq5	108	13
'CopyRates' - no one of the overloads can be applied to the function call	параболик.mq5	560	17
исправь только это