
Трейдинг с экономическим календарем MQL5 (Часть 4): Обновление новостей в панели управления в реальном времени
Введение
В этой статье я продолжу улучшать панель экономического календаря на основе MetaQuotes Language 5 (MQL5). Я добавлю функционал для обновления важнейших экономических новостей в реальном времени. В предыдущей части мы разработали и внедрили панель инструментов для сортировки новостей по валюте, важности и времени. Теперь мы пойдем дальше и добавим обновления в реальном времени, гарантируя, что в нашем календаре будут отображаться самые последние данные для своевременного принятия решений. Мы рассмотрим следующие темы:
Это усовершенствование превратит нашу панель в динамичный инструмент, постоянно обновляемый в соответствии с последними экономическими событиями. Внедряя функцию обновления в реальном времени, мы гарантируем, что наш календарь останется точным и актуальным, поддерживая своевременные торговые решения в MetaTrader 5 или торговом терминале.
Реализация обновлений новостей в реальном времени на MQL5
Чтобы реализовать оперативные обновления для нашей панели, нам необходимо обеспечить сохранение и периодическое сравнение новостей для выявления любых изменений. Для этого требуется поддерживать массивы для хранения данных о текущих и предыдущих событиях, что позволяет нам идентифицировать обновления и точно отражать их на панели. Благодаря этому мы можем гарантировать, что панель управления будет динамически подстраиваться для отображения последних экономических событий в реальном времени. Ниже определим массивы, которые будем использовать для этой цели:
string current_eventNames_data[]; string previous_eventNames_data[];
Здесь мы определим строковые массивы current_eventNames_data и previous_eventNames_data, которые мы будем использовать для управления и сравнения данных об экономических событиях для оперативного обновления панели. Массив current_eventNames_data будет хранить последние события, извлеченные из экономического календаря, а previous_eventNames_data будет содержать данные из последнего цикла обновления. Сравнивая эти два массива, мы можем выявить любые изменения или новые дополнения к событиям, что позволяет нам динамически обновлять панель управления.
Используя эти массивы, нам нужно будет получить текущие значения для каждого события, выбранного в разделе инициализации, и сохранить их в текущем массиве держателя данных, а затем позже скопировать их в предыдущий держатель, который мы будем использовать для выполнения сравнения на следующем ценовом тике.
ArrayResize(current_eventNames_data,ArraySize(current_eventNames_data)+1); current_eventNames_data[ArraySize(current_eventNames_data)-1] = event.name;
Здесь мы динамически расширяем массив current_eventNames_data и добавляем в него новое имя события. Мы используем функцию ArrayResize для увеличения размера массива на единицу, освобождая место для новой записи. После изменения размера мы присваиваем имя события последнему индексу массива, используя выражение "current_eventNames_data[ArraySize(current_eventNames_data)-1]". Это гарантирует, что каждое новое название события, извлеченное из экономического календаря, сохраняется в массиве, что позволяет нам поддерживать актуальный список событий для дальнейшей обработки и сравнения.
Однако перед добавлением событий в массив нам нужно убедиться, что мы начинаем все заново, то есть нам нужен пустой массив.
ArrayFree(current_eventNames_data);
Здесь мы используем функцию ArrayFree для удаления всех элементов из массива current_eventNames_data и его сброса в пустое состояние. Таким образом массив не сохранит устаревшие данные из предыдущих итераций и будет готов к сохранению нового набора имен событий во время цикла обработки. После заполнения массива нам необходимо скопировать его в предыдущий контейнер и использовать его позже для сравнения.
Print("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data)); ArrayPrint(current_eventNames_data); Print("PREVIOUS EVENT NAMES DATA SIZE (Before) = ",ArraySize(previous_eventNames_data)); ArrayCopy(previous_eventNames_data,current_eventNames_data); Print("PREVIOUS EVENT NAMES DATA SIZE (After) = ",ArraySize(previous_eventNames_data)); ArrayPrint(previous_eventNames_data);
Здесь мы фиксируем и управляем перемещением данных между массивами current_eventNames_data и previous_eventNames_data. Сначала используем функцию Print для отображения размера массива current_eventNames_data, обеспечивающего видимость количества имен событий, сохраненных на данный момент. Затем вызываем функцию ArrayPrint, чтобы вызвать содержимое массива для дальнейшей проверки. Затем мы фиксируем размер массива previous_eventNames_data перед копированием, что дает нам базовый уровень для сравнения.
Используя функцию ArrayCopy, мы копируем содержимое current_eventNames_data в previous_eventNames_data, фактически передавая последние имена событий для будущих сравнений. Затем мы выводим размер массива previous_eventNames_data после копирования, чтобы подтвердить успешное обновление. Наконец, мы вызываем функцию ArrayPrint для вывода обновленного содержимого previous_eventNames_data, гарантируя точность и полноту передачи данных. Это все изменения в обработчике событий OnInit для хранения начальных событий. Давайте выделим их для большей ясности.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ //--- ArrayFree(current_eventNames_data); //--- Loop through each calendar value up to the maximum defined total for (int i = 0; i < valuesTotal; i++){ //--- //--- Loop through calendar data columns for (int k=0; k<ArraySize(array_calendar); k++){ //--- //--- Prepare news data array with time, country, and other event details string news_data[ArraySize(array_calendar)]; news_data[0] = TimeToString(values[i].time,TIME_DATE); //--- Event date news_data[1] = TimeToString(values[i].time,TIME_MINUTES); //--- Event time news_data[2] = country.currency; //--- Event country currency //--- Determine importance color based on event impact color importance_color = clrBlack; if (event.importance == CALENDAR_IMPORTANCE_LOW){importance_color=clrYellow;} else if (event.importance == CALENDAR_IMPORTANCE_MODERATE){importance_color=clrOrange;} else if (event.importance == CALENDAR_IMPORTANCE_HIGH){importance_color=clrRed;} //--- Set importance symbol for the event news_data[3] = ShortToString(0x25CF); //--- Set event name in the data array news_data[4] = event.name; //--- Populate actual, forecast, and previous values in the news data array news_data[5] = DoubleToString(value.GetActualValue(),3); news_data[6] = DoubleToString(value.GetForecastValue(),3); news_data[7] = DoubleToString(value.GetPreviousValue(),3); //--- } ArrayResize(current_eventNames_data,ArraySize(current_eventNames_data)+1); current_eventNames_data[ArraySize(current_eventNames_data)-1] = event.name; } Print("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data)); ArrayPrint(current_eventNames_data); Print("PREVIOUS EVENT NAMES DATA SIZE (Before) = ",ArraySize(previous_eventNames_data)); ArrayCopy(previous_eventNames_data,current_eventNames_data); Print("PREVIOUS EVENT NAMES DATA SIZE (After) = ",ArraySize(previous_eventNames_data)); ArrayPrint(previous_eventNames_data); //Print("Final News = ",news_filter_count); updateLabel(TIME_LABEL,"Server Time: "+TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS)+" ||| Total News: "+ IntegerToString(news_filter_count)+"/"+IntegerToString(allValues)); //--- return(INIT_SUCCEEDED); }
Мы внесли изменения, которые помогут нам получить исходные данные о событиях. Для наглядности мы выделили их желтым цветом. Далее нам нужно обновить значения на панели управления при обнаружении изменений во время сравнения. Для этого мы создадим пользовательскую функцию, которая будет содержать всю логику обновления событий и пересчета панели мониторинга соответственно.
//+------------------------------------------------------------------+ //| Function to update dashboard values | //+------------------------------------------------------------------+ void update_dashboard_values(){ //--- }
Здесь мы определяем функцию update_dashboard_values, которую будем использовать для обработки динамического обновления панели экономического календаря. Эта функция будет содержать основную логику для сравнения сохраненных новостных данных, выявления любых изменений и применения необходимых обновлений к интерфейсу панели мониторинга. Поместив эту возможность в отдельную функцию, мы обеспечим чистую и модульную структуру кода, что упростит управление будущими модификациями или улучшениями. Далее мы вызовем функцию в обработчике событий OnTick следующим образом.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ //--- update_dashboard_values(); }
Здесь мы просто вызываем пользовательскую функцию на каждом тике, чтобы выполнить обновления. После компиляции и запуска программы имеем следующие результаты:
На изображении видно, что мы собираем все новости в "текущий" (current) массив, который затем копируем в новый "предыдущий" (previous) массив для хранения, что идеально соответствует нашим потребностям. Теперь мы можем приступить к использованию этих скопированных данных для дальнейшего анализа. В функции мы просто получаем текущие события следующим образом:
//--- Declare variables for tracking news events and status int totalNews = 0; bool isNews = false; MqlCalendarValue values[]; //--- Array to store calendar values //--- Define start and end time for calendar event retrieval datetime startTime = TimeTradeServer() - PeriodSeconds(PERIOD_H12); datetime endTime = TimeTradeServer() + PeriodSeconds(PERIOD_H12); //--- Set a specific country code filter (e.g., "US" for USD) string country_code = "US"; string currency_base = SymbolInfoString(_Symbol,SYMBOL_CURRENCY_BASE); //--- Retrieve historical calendar values within the specified time range int allValues = CalendarValueHistory(values,startTime,endTime,NULL,NULL); //--- Print the total number of values retrieved and the array size //Print("TOTAL VALUES = ",allValues," || Array size = ",ArraySize(values)); //--- Define time range for filtering news events based on daily period datetime timeRange = PeriodSeconds(PERIOD_D1); datetime timeBefore = TimeTradeServer() - timeRange; datetime timeAfter = TimeTradeServer() + timeRange; //--- Print the furthest time look-back and current server time //Print("FURTHEST TIME LOOK BACK = ",timeBefore," >>> CURRENT = ",TimeTradeServer()); //--- Limit the total number of values to display int valuesTotal = (allValues <= 11) ? allValues : 11; string curr_filter[] = {"AUD","CAD","CHF","EUR","GBP","JPY","NZD","USD"}; int news_filter_count = 0; ArrayFree(current_eventNames_data); // Define the levels of importance to filter (low, moderate, high) ENUM_CALENDAR_EVENT_IMPORTANCE allowed_importance_levels[] = {CALENDAR_IMPORTANCE_LOW, CALENDAR_IMPORTANCE_MODERATE, CALENDAR_IMPORTANCE_HIGH}; //--- Loop through each calendar value up to the maximum defined total for (int i = 0; i < valuesTotal; i++){ MqlCalendarEvent event; //--- Declare event structure CalendarEventById(values[i].event_id,event); //--- Retrieve event details by ID MqlCalendarCountry country; //--- Declare country structure CalendarCountryById(event.country_id,country); //--- Retrieve country details by event's country ID MqlCalendarValue value; //--- Declare calendar value structure CalendarValueById(values[i].id,value); //--- Retrieve actual, forecast, and previous values //--- Check if the event’s currency matches any in the filter array (if the filter is enabled) bool currencyMatch = false; if (enableCurrencyFilter) { for (int j = 0; j < ArraySize(curr_filter); j++) { if (country.currency == curr_filter[j]) { currencyMatch = true; break; } } //--- If no match found, skip to the next event if (!currencyMatch) { continue; } } //--- Check importance level if importance filter is enabled bool importanceMatch = false; if (enableImportanceFilter) { for (int k = 0; k < ArraySize(allowed_importance_levels); k++) { if (event.importance == allowed_importance_levels[k]) { importanceMatch = true; break; } } //--- If importance does not match the filter criteria, skip the event if (!importanceMatch) { continue; } } //--- Apply time filter and set timeMatch flag (if the filter is enabled) bool timeMatch = false; if (enableTimeFilter) { datetime eventTime = values[i].time; if (eventTime <= TimeTradeServer() && eventTime >= timeBefore) { timeMatch = true; //--- Event is already released } else if (eventTime >= TimeTradeServer() && eventTime <= timeAfter) { timeMatch = true; //--- Event is yet to be released } //--- Skip if the event doesn't match the time filter if (!timeMatch) { continue; } } //--- If we reach here, the currency matches the filter news_filter_count++; //--- Increment the count of filtered events //--- Set alternating colors for each data row holder color holder_color = (news_filter_count % 2 == 0) ? C'213,227,207' : clrWhite; //--- Loop through calendar data columns for (int k=0; k<ArraySize(array_calendar); k++){ //--- Print event details for debugging //Print("Name = ",event.name,", IMP = ",EnumToString(event.importance),", COUNTRY = ",country.name,", TIME = ",values[i].time); //--- Skip event if currency does not match the selected country code // if (StringFind(_Symbol,country.currency) < 0) continue; //--- Prepare news data array with time, country, and other event details string news_data[ArraySize(array_calendar)]; news_data[0] = TimeToString(values[i].time,TIME_DATE); //--- Event date news_data[1] = TimeToString(values[i].time,TIME_MINUTES); //--- Event time news_data[2] = country.currency; //--- Event country currency //--- Determine importance color based on event impact color importance_color = clrBlack; if (event.importance == CALENDAR_IMPORTANCE_LOW){importance_color=clrYellow;} else if (event.importance == CALENDAR_IMPORTANCE_MODERATE){importance_color=clrOrange;} else if (event.importance == CALENDAR_IMPORTANCE_HIGH){importance_color=clrRed;} //--- Set importance symbol for the event news_data[3] = ShortToString(0x25CF); //--- Set event name in the data array news_data[4] = event.name; //--- Populate actual, forecast, and previous values in the news data array news_data[5] = DoubleToString(value.GetActualValue(),3); news_data[6] = DoubleToString(value.GetForecastValue(),3); news_data[7] = DoubleToString(value.GetPreviousValue(),3); } ArrayResize(current_eventNames_data,ArraySize(current_eventNames_data)+1); current_eventNames_data[ArraySize(current_eventNames_data)-1] = event.name; } //Print("Final News = ",news_filter_count); updateLabel(TIME_LABEL,"Server Time: "+TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS)+" ||| Total News: "+ IntegerToString(news_filter_count)+"/"+IntegerToString(allValues));
Это всего лишь предыдущий фрагмент кода, который мы использовали в разделе инициализации, но он нам нужен на каждом тике для получения обновлений. Пройдемся по нему вкратце. Мы уделяем особое внимание динамическому обновлению панели мониторинга последними экономическими новостями на каждом этапе, и для этого мы оптимизируем логику, отказываясь от создания графических объектов, и вместо этого концентрируемся на эффективном управлении данными о событиях. Начнем с определения переменных для отслеживания общего количества новостей и критериев сортировки, таких как валюта, важность и временные диапазоны. Эти фильтры гарантируют, что для дальнейшей обработки будут рассматриваться только соответствующие события.
Мы проходим по извелченным данным календаря, применяя фильтры для определения событий, соответствующих указанным условиям. Для каждого совпадающего события мы извлекаем ключевые данные, такие как название события, время, валюта и уровень важности. Эти данные хранятся в массиве current_eventNames_data, размер которого динамически изменяется для размещения новых записей. Этот массив имеет решающее значение для отслеживания событий и позволяет нам выявлять изменения между тиками, сравнивая их с предыдущими данными. Наконец, мы обновляем метку панели, чтобы она отражала общее количество отфильтрованных событий и текущее время сервера, гарантируя, что панель мониторинга всегда будет отображать последние данные о событиях без создания ненужных объектов. Такой подход позволяет эффективно собирать и обновлять экономические новости в реальном времени.
Далее нам необходимо отслеживать, произошли ли изменения в массивах хранения, используя вновь полученные данные. Для этого мы используем пользовательскую функцию.
//+------------------------------------------------------------------+ //| Function to compare two string arrays and detect changes | //+------------------------------------------------------------------+ bool isChangeInStringArrays(string &arr1[], string &arr2[]) { bool isChange = false; int size1 = ArraySize(arr1); // Get the size of the first array int size2 = ArraySize(arr2); // Get the size of the second array // Check if sizes are different if (size1 != size2) { Print("Arrays have different sizes. Size of Array 1: ", size1, ", Size of Array 2: ", size2); isChange = true; return (isChange); } // Loop through the arrays and compare corresponding elements for (int i = 0; i < size1; i++) { // Compare the strings at the same index in both arrays if (StringCompare(arr1[i], arr2[i]) != 0) { // If strings are different // Action when strings differ at the same index Print("Change detected at index ", i, ": '", arr1[i], "' vs '", arr2[i], "'"); isChange = true; return (isChange); } } // If no differences are found, you can also log this as no changes detected //Print("No changes detected between arrays."); return (isChange); }
Здесь мы определяем булеву функцию isChangeInStringArrays, которая сравнивает два строковых массива, arr1 и arr2, для обнаружения любых изменений между ними. Начнем с определения размеров обоих массивов с помощью функции ArraySize и сохраним эти размеры в size1 и size2. Если размеры массивов различаются, мы выводим соответствующие размеры, устанавливаем флаг isChange в значение true и возвращаем true, что указывает на изменение. Если размеры одинаковы, то переходим к сравнению элементов массивов с помощью цикла for. Для каждого индекса мы используем функцию StringCompare для проверки идентичности строк в обоих массивах. Если какие-либо строки различаются, мы выводим сведения об изменении и устанавливаем isChange в true, чтобы сигнализировать об обновлении. Если после цикла никаких различий не обнаружено, функция возвращает false, что указывает на отсутствие изменений. Такой подход необходим для обнаружения обновлений, таких как новые или обновленные новостные события, которые необходимо отразить на панели управления.
Вооружившись этой функцией, мы можем использовать ее для обновления событий.
if (isChangeInStringArrays(previous_eventNames_data,current_eventNames_data)){ Print("CHANGES IN EVENT NAMES DETECTED. UPDATE THE DASHBOARD VALUES"); ObjectsDeleteAll(0,DATA_HOLDERS); ObjectsDeleteAll(0,ARRAY_NEWS); ArrayFree(current_eventNames_data); //--- }
Здесь мы проверяем, произошли ли какие-либо изменения между массивами previous_eventNames_data и current_eventNames_data, вызывая функцию isChangeInStringArrays. Если функция возвращает true, что указывает на то, что изменения обнаружены, мы выводим сообщение "CHANGES IN EVENT NAMES DETECTED. UPDATE THE DASHBOARD VALUES" (Обнаружены изменения в именах событий. Обновите значения панели). После этого мы удаляем все объекты, связанные с держателями данных и массивами новостей на графике с помощью функции ObjectsDeleteAll, указав идентификаторы DATA_HOLDERS и ARRAY_NEWS в качестве префиксов объектов. Мы делаем это для того, чтобы удалить всю устаревшую информацию перед обновлением панели последними данными о событиях. Наконец, мы освобождаем память, используемую массивом current_eventNames_data с помощью функции ArrayFree, обеспечивая очистку массива при подготовке к следующему обновлению. После этого мы обновляем данные о событиях как обычно, но на этот раз создаем держатели данных и обновляем новостные события на новой панели мониторинга. Логика представлена ниже.
if (isChangeInStringArrays(previous_eventNames_data,current_eventNames_data)){ Print("CHANGES IN EVENT NAMES DETECTED. UPDATE THE DASHBOARD VALUES"); ObjectsDeleteAll(0,DATA_HOLDERS); ObjectsDeleteAll(0,ARRAY_NEWS); ArrayFree(current_eventNames_data); //--- Initialize starting y-coordinate for displaying news data int startY = 162; //--- Loop through each calendar value up to the maximum defined total for (int i = 0; i < valuesTotal; i++){ MqlCalendarEvent event; //--- Declare event structure CalendarEventById(values[i].event_id,event); //--- Retrieve event details by ID MqlCalendarCountry country; //--- Declare country structure CalendarCountryById(event.country_id,country); //--- Retrieve country details by event's country ID MqlCalendarValue value; //--- Declare calendar value structure CalendarValueById(values[i].id,value); //--- Retrieve actual, forecast, and previous values //--- Check if the event’s currency matches any in the filter array (if the filter is enabled) bool currencyMatch = false; if (enableCurrencyFilter) { for (int j = 0; j < ArraySize(curr_filter); j++) { if (country.currency == curr_filter[j]) { currencyMatch = true; break; } } //--- If no match found, skip to the next event if (!currencyMatch) { continue; } } //--- Check importance level if importance filter is enabled bool importanceMatch = false; if (enableImportanceFilter) { for (int k = 0; k < ArraySize(allowed_importance_levels); k++) { if (event.importance == allowed_importance_levels[k]) { importanceMatch = true; break; } } //--- If importance does not match the filter criteria, skip the event if (!importanceMatch) { continue; } } //--- Apply time filter and set timeMatch flag (if the filter is enabled) bool timeMatch = false; if (enableTimeFilter) { datetime eventTime = values[i].time; if (eventTime <= TimeTradeServer() && eventTime >= timeBefore) { timeMatch = true; //--- Event is already released } else if (eventTime >= TimeTradeServer() && eventTime <= timeAfter) { timeMatch = true; //--- Event is yet to be released } //--- Skip if the event doesn't match the time filter if (!timeMatch) { continue; } } //--- If we reach here, the currency matches the filter news_filter_count++; //--- Increment the count of filtered events //--- Set alternating colors for each data row holder color holder_color = (news_filter_count % 2 == 0) ? C'213,227,207' : clrWhite; //--- Create rectangle label for each data row holder createRecLabel(DATA_HOLDERS+string(news_filter_count),62,startY-1,716,26+1,holder_color,1,clrNONE); //--- Initialize starting x-coordinate for each data entry int startX = 65; //--- Loop through calendar data columns for (int k=0; k<ArraySize(array_calendar); k++){ //--- Print event details for debugging //Print("Name = ",event.name,", IMP = ",EnumToString(event.importance),", COUNTRY = ",country.name,", TIME = ",values[i].time); //--- Skip event if currency does not match the selected country code // if (StringFind(_Symbol,country.currency) < 0) continue; //--- Prepare news data array with time, country, and other event details string news_data[ArraySize(array_calendar)]; news_data[0] = TimeToString(values[i].time,TIME_DATE); //--- Event date news_data[1] = TimeToString(values[i].time,TIME_MINUTES); //--- Event time news_data[2] = country.currency; //--- Event country currency //--- Determine importance color based on event impact color importance_color = clrBlack; if (event.importance == CALENDAR_IMPORTANCE_LOW){importance_color=clrYellow;} else if (event.importance == CALENDAR_IMPORTANCE_MODERATE){importance_color=clrOrange;} else if (event.importance == CALENDAR_IMPORTANCE_HIGH){importance_color=clrRed;} //--- Set importance symbol for the event news_data[3] = ShortToString(0x25CF); //--- Set event name in the data array news_data[4] = event.name; //--- Populate actual, forecast, and previous values in the news data array news_data[5] = DoubleToString(value.GetActualValue(),3); news_data[6] = DoubleToString(value.GetForecastValue(),3); news_data[7] = DoubleToString(value.GetPreviousValue(),3); //--- Create label for each news data item if (k == 3){ createLabel(ARRAY_NEWS+IntegerToString(i)+" "+array_calendar[k],startX,startY-(22-12),news_data[k],importance_color,22,"Calibri"); } else { createLabel(ARRAY_NEWS+IntegerToString(i)+" "+array_calendar[k],startX,startY,news_data[k],clrBlack,12,"Calibri"); } //--- Increment x-coordinate for the next column startX += buttons[k]+3; } ArrayResize(current_eventNames_data,ArraySize(current_eventNames_data)+1); current_eventNames_data[ArraySize(current_eventNames_data)-1] = event.name; //--- Increment y-coordinate for the next row of data startY += 25; //Print(startY); //--- Print current y-coordinate for debugging } Print("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data)); ArrayPrint(current_eventNames_data); Print("PREVIOUS EVENT NAMES DATA SIZE (Before) = ",ArraySize(previous_eventNames_data)); ArrayPrint(previous_eventNames_data); ArrayFree(previous_eventNames_data); ArrayCopy(previous_eventNames_data,current_eventNames_data); Print("PREVIOUS EVENT NAMES DATA SIZE (After) = ",ArraySize(previous_eventNames_data)); ArrayPrint(previous_eventNames_data); }
Здесь мы обновляем панель управления на основе новых полученных данных, чтобы гарантировать вступление в силу обновлений. Используя логику копирования, мы регистрируем данные в "предыдущем" держателе данных, чтобы иметь возможность использовать текущие данные при следующей проверке. Мы выделили логику, которая решает эту проблему, но давайте рассмотрим ее более подробно.
Print("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data)); ArrayPrint(current_eventNames_data); Print("PREVIOUS EVENT NAMES DATA SIZE (Before) = ",ArraySize(previous_eventNames_data)); ArrayPrint(previous_eventNames_data); ArrayFree(previous_eventNames_data); ArrayCopy(previous_eventNames_data,current_eventNames_data); Print("PREVIOUS EVENT NAMES DATA SIZE (After) = ",ArraySize(previous_eventNames_data)); ArrayPrint(previous_eventNames_data);
Здесь мы начинаем с вывода текущего размера массива current_eventNames_data с помощью функции ArraySize и отображения ее содержимого с помощью функции ArrayPrint. Это поможет нам проверить текущий набор названий событий, которые мы отслеживаем. Далее мы выводим размер массива previous_eventNames_data до его обновления, а затем - его содержимое.
Затем мы освобождаем память, используемую previous_eventNames_data с помощью функции ArrayFree, гарантирующей очистку всех предыдущих данных, сохраненных в массиве, во избежание проблем с памятью. После освобождения памяти мы используем функцию ArrayCopy для копирования содержимого массива current_eventNames_data в previous_eventNames_data, фактически обновляя его именами последних событий.
Наконец, мы выводим обновленный размер массива previous_eventNames_data и его содержимое, чтобы подтвердить, что массив теперь содержит самые последние имена событий. Это гарантирует, что названия предыдущих событий будут корректно обновлены для дальнейшего сравнения. После запуска программы мы получили следующий результат.
Обновления времени.
Обновление событий.
Обновление панели.
Мы видим, что вновь зарегистрированные данные точно обновляются на панели. Чтобы еще раз убедиться в этом, мы можем снова подождать некоторое время, чтобы убедиться в том, можем ли мы отслеживать эти данные. Вот результат.
Обновление данных о событиях.
Обновление панели.
На изображении видно, что как только в ранее сохраненных данных происходят изменения, они обнаруживаются и обновляются в соответствии с вновь зарегистрированными данными и сохраняются для дальнейшего использования. Сохраненные данные используются для обновления интерфейса панели в реальном времени, отображая текущие новости и тем самым подтверждая, что наша цель достигнута.
Заключение
Мы внедрили надежную систему мониторинга и обнаружения изменений в экономических новостях MQL5 путем сравнения ранее сохраненных данных о событиях с вновь полученными обновлениями. Этот механизм сравнения гарантирует, что любые различия в названиях событий или деталях будут оперативно выявлены, что приведет к обновлению панели управления для поддержания точности и релевантности. Сортируя данные по валюте, важности и времени, мы еще больше усовершенствовали процесс, чтобы сосредоточиться на важных событиях, динамически обновляя интерфейс.
В следующих частях серии мы интегрируем экономические новости в торговые стратегии, обеспечивая практическое применение данных. Кроме того, мы улучшим функциональность панели, сделав ее мобильнее и отзывчивее, чтобы гарантировать трейдерам более удобный и интерактивный интерфейс. Оставайтесь с нами!
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/16386





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Пользователям, вероятно, будет интересно узнать, что те же темы подробно рассмотрены в книге по алготрейдингу (а на сайте это почему-то не отображается в автоматических предложениях), включая отслеживание и сохранение изменений событий, фильтрацию событий по нескольким условиям (с различными логическими операторами) для расширенного набора полей, отображение настраиваемого на лету подмножества календаря в панели на графике и встраивание для торговли в советники с поддержкой переноса полного архива календаря в тестер.