﻿//+------------------------------------------------------------------+
//|                                    ExportCalendarForTester-S.mq5   |
//|              Экспорт отфильтрованных событий в бинарный ресурс   |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property description "Экспорт событий экономического календаря в бинарный файл"

#property script_show_inputs
#property strict


//--- входные параметры
input string                          InpCurrencies     = "USD,EUR";
input datetime                        InpDateFrom       = D'2025.01.01';
input datetime                        InpDateTo         = D'2026.01.01';
input string                          InpEventCodes     = "";
input ENUM_CALENDAR_EVENT_IMPORTANCE  InpMinImportance  = CALENDAR_IMPORTANCE_HIGH;
input string                          InpOutputFile     = "calendar_test_res.bin";
input bool                            InpUseCommonDir   = true;

//+------------------------------------------------------------------+
//| Точка входа скрипта                                              |
//+------------------------------------------------------------------+
void OnStart()
 {
  MqlCalendarValue    raw_values[];
  int                 raw_values_size = 0;

  MqlCalendarValue    values[];
  ArrayResize(values, 0);

  MqlCalendarEvent    event;
  MqlCalendarCountry  country;

  string              event_codes[];
  int                 event_codes_Size = 0;
  string              currencies[];
  int                 currencies_size = 0;

  int                 values_size[];
  ArrayResize(values_size, 0);

  Print("🔄 Экспорт календаря:");
  Print("----------------------------------");
  Print("Параметры фильтрации:");
  Print(" 🟨 Интервал = ", InpDateFrom, " — ", InpDateTo);
  Print(" 🟨 Currencies = ", InpCurrencies, "\n 🟨 Event Codes = ", InpEventCodes, "\n 🟨 Min Importance = ", EnumToString(InpMinImportance));
  Print("----------------------------------");

//--- инициализация фильтра по валютам
  ArrayResize(currencies, 0);
  if(InpCurrencies == "")
    return;
  StringSplit(InpCurrencies, ',', currencies);
  currencies_size = ArraySize(currencies);
  for(int i = 0; i < currencies_size; i++)
    StringToUpper(currencies[i]);

//--- инициализация фильтра по кодам событий
  ArrayResize(event_codes, 0);
  if(InpEventCodes != "")
    StringSplit(InpEventCodes, ',', event_codes);
  event_codes_Size = ArraySize(event_codes);

//--- загрузка значений календаря с ФИЛЬТРОМ ПО ВАЛЮТЕ (если он задан)
  if(currencies_size > 0)
   {
    ArrayResize(values_size, currencies_size);
    ArrayFill(values_size, 0, currencies_size, 0);

    for(int i = 0; i < currencies_size; i++)
     {
      if(LoadCalendar(raw_values, InpDateFrom, InpDateTo, "", currencies[i]))
       {
        raw_values_size = ArraySize(raw_values);
        //--- загрузка событий с ФИЛЬТРОМ ПО ВАЖНОСТИ И КОДУ СОБЫТИЯ
        for(int k = 0; k < raw_values_size; k++)
         {
          //--- получим описание события
          if(CalendarEventById(raw_values[k].event_id, event))
           {
            //--- берем только индикаторы
            if(event.type != CALENDAR_TYPE_INDICATOR)
              continue;                                   // дальше фильтровать нечего

            //--- проверка по ВАЖНОСТИ
            if(event.importance < InpMinImportance)
              continue;                                   // дальше фильтровать нечего

            //--- проверка по КОДУ СОБЫТИЯ (если он задан)
            if(event_codes_Size > 0)
             {
              bool code_allowed = false;
              for(int c = 0; c < event_codes_Size; c++)
               {
                StringToUpper(event.event_code);
                if(StringFind(event.event_code, event_codes[c]) >= 0)
                 {
                  code_allowed = true;
                  break;
                 }
               }
              if(code_allowed == false)
                continue;
             }

            //--- получим описание страны
            if(CalendarCountryById(event.country_id, country))
             {
             }

            //--- пополним массив отфильтрованных событий
            int event_index = ArraySize(values);
            ArrayResize(values, event_index + 1);
            values[event_index] = raw_values[k];
            values_size[i]++;
           }
         }
        Print("✅ Получено значений ПО ВАЛЮТЕ \"", currencies[i], "\": ", raw_values_size, " → Из них отфильтровано: ", values_size[i]);
       }
      else
       {
        int error = GetLastError();
        if(error == 0)
          Print("⚠ LoadCalendar Info: No Events for ", currencies[i]);
        else
          Print("❌ LoadCalendar Error: ", error, " for ", currencies[i]);
        return;                                     // дальше фильтровать нечего
       }
     }
   }

//--- сохранение в бинарный файл
  if(ArraySize(values) > 0)
    SaveToBinary(values, values_size, InpOutputFile, currencies);
 }
//+------------------------------------------------------------------+
//| Сохранение массива в бинарный файл                               |
//+------------------------------------------------------------------+
void SaveToBinary(MqlCalendarValue &values[], const int &vls_size[], const string filename, const string &currencies[])
 {
  if(ArraySize(values) == 0)
   {
    Print("⚠️ Nothing to save");
    return;
   }

  Print("----------------------------------");
  int offset = 0;
  for(int i = 0; i < ArraySize(vls_size); i++)
   {
    int file_handle = FileOpen(currencies[i] + "_" + filename, FILE_WRITE | FILE_BIN | (InpUseCommonDir ? FILE_COMMON : 0));

    if(file_handle == INVALID_HANDLE)
     {
      Print("❌ FileSave failed: ", GetLastError());
      return;
     }

    FileWriteArray(file_handle, values, offset, vls_size[i]);
    FileFlush(file_handle);
    FileClose(file_handle);

    Print("✅ Saved: ", currencies[i] + "_" + filename, "   Size: ", vls_size[i] * sizeof(MqlCalendarValue), " bytes", "  (", vls_size[i], " events)");

    offset += vls_size[i];
   }
 }
//+------------------------------------------------------------------+
//| Загрузка календаря из сервера                                    |
//+------------------------------------------------------------------+
bool LoadCalendar(MqlCalendarValue &values[], const datetime from, const datetime to,
                  const string country_code = NULL, const string currency = NULL,
                  const int max_retries = 5)
 {
  int retry_count = 0;
  while(retry_count < max_retries)
   {
    ResetLastError();
    int result = CalendarValueHistory(values, from, to, country_code, currency);
    if(result > 0)
      return true;

    int error = GetLastError();
    if(error == 5201 || error == 5200)
     {
      retry_count++;
      Sleep(1000);
      continue;
     }
    Print("❌ Critical Calendar Error: ", error);
    return false;
   }
  Print("❌ Failed to load calendar after ", max_retries, " attempts.");
  return false;
 }
//+------------------------------------------------------------------+
