Чтение новостей в формате RSS средствами MQL4

vgs | 11 июля, 2011


Вступление

В данной статье рассматриватся пример чтения RSS разметки средствами MQL4, используя функции из статьи "Разбор HTML средствами MQL4". Предполагается, что читатель читал статью или хотя бы имеет общее понимание изложенных в ней идей.


Что такое RSS и зачем он нам в MQL4?

RSS - это XML-формат, предназначенный для передачи различного рода информации от одного источника к другому.

Очень широкое распостранение RSS получил в интернете на сайтах новостных агентств, компаний, да и просто на различных информационных сайтах.

RSS может быть собран (или прочитан) различными специальными программами (читалками) и доставлен пользователю в удобном для него виде. В этой статье мы попытаемся сделать заготовку, на базе которой можно будет сделать, например, новостной индикатор или просто RSS-читалку, только на языке MQL4. Какая информация нас интересует в RSS? Это, конечно же, новости.

Как уже было сказано выше, RSS - это по сути XML-документ. Что же такое XML?

Xml (eXtensible Markup Language - расширяемый язык разметки) - текстовый формат, предназначенный для хранения структурированных данных. Визуально структура может быть представлена в виде дерева элементов. Элементы XML описываются тегами.

Пример простого XML-документа:

<!--?xml version="1.0" encoding="windows-1252"?-->
<weeklyevents>
        <event>
                <title>Rightmove HPI m/m</title>
                <country>GBP</country>
                <date><!--[CDATA[05-15-2011]]--></date>
                <time><!--[CDATA[23:01]]--></time>
                <impact><!--[CDATA[Medium]]--></impact>
                <forecast>
                <previous><!--[CDATA[1.7%]]--></previous>
        </forecast></event>
</weeklyevents>


Реализация

Как мы видим из примера выше, XML чем-то напоминает HTML. Поэтому, чтобы не "изобретать велосипед", мы воспользуемся кодом из статьи "Разбор HTML средствами MQL4".

Первое что нам необходимо, это подключить функции разбора HTML к нашему проекту (индикатору). Для этого скачаем файл ReportHTMLtoCSV-2.mq4 и положим его в папочку experts/include. Поскольку файл мы будем использовать как функциональную библиотеку, в нем нужно закомментировать функцию start().

Также предлагаю переименовать файл (например в HTMLTagsLib.mq4) просто для наглядности.

Файл готов, подключаем его к индикатору (файл заготовки для индикатора можно будет скачать в приложении к статье):

#include <htmltagslib.mq4>

Теперь нам нужно подключить стандартную библиотеку Windows "wininet.dll" для работы со ссылками:

#include <winuser32.mqh>
#import "wininet.dll"
  int InternetAttemptConnect(int x);
  int InternetOpenA(string sAgent, int lAccessType, 
                    string sProxyName = "", string sProxyBypass = "", 
                    int lFlags = 0);
  int InternetOpenUrlA(int hInternetSession, string sUrl, 
                       string sHeaders = "", int lHeadersLength = 0,
                       int lFlags = 0, int lContext = 0);
  int InternetReadFile(int hFile, int& sBuffer[], int lNumBytesToRead, 
                       int& lNumberOfBytesRead[]);
  int InternetCloseHandle(int hInet);
#import

Для чтения URL будем использовать функцию ReadWebResource(string url). Работа этой функции не является темой для данной статьи, поэтому мы не будем на ней останавливаться.

Нас интересуют только входные и выходные аргументы. Функции передается ссылка, которую нужно прочитать, возвращает функция содержимое ресурса в виде строки.

Для анализа тегов мы будем использовать две функции из файла HTMLTagsLib.mq4: FillTagStructure() и GetContent(). Работа этих функций подробно описана в статье "Разбор HTML средствами MQL4". Следует отметить, что входные данные для анализа передаются в виде массива, поэтому после получения данных их нужно преобразовать в массив при помощи функции ReadWebResource(string url).

В этом нам поможет функция ArrayFromString():

//+------------------------------------------------------------------+
int ArrayFromString(string & webResData[], string inputStr, string divider) 
{   
   if (inputStr == "") 
   {
     Print ("Не задана входная строка"); 
     return(0);
   }
   if (divider == "") 
   {
      Print ("Не задан разделитель"); 
      return(0);
   }
   int i, stringCounter = 0;
   
   string tmpChar, tmpString, tmpArr[64000];   
   int inputStringLen = StringLen(inputStr);
   for (i = 0; i < inputStringLen; i++ ) 
   {
      tmpChar = StringSubstr(inputStr, i, 1);
      tmpString = tmpString + tmpChar;
      tmpArr[stringCounter] = tmpString; 
      if (tmpChar == divider) 
      {          
          stringCounter++;
          tmpString = "";
      }               
   }
   if (stringCounter > 0) 
   {
      ArrayResize(webResData, stringCounter);   
      for (i = 0; i < stringCounter; i++) webResData[i] = tmpArr[i];
   }
   return (stringCounter);
}

На вход функции передаются три аргумента. Первый - это ссылка на массив, в котором будет храниться результат работы функции, второй - строка, которую нужно преобразовать в массив, и третий - разделитель, по которому будет происходить разделение строки. Функция возвращает количество рядов в результирующем массиве.

Теперь наши данные подготовлены для анализа.

В следующем фрагменте мы анализируем данные и выводим значения тегов title и country в консоль терминала:

   string webRss = ReadWebResource(rssUrl);
   int i, stringsCount = ArrayFromString(webResData, webRss, ">");      
            
   string tags[];    // массив для хранения тегов
   int startPos[][2];// координаты начала тега
   int endPos[][2];  // координатры конца тега
   
   FillTagStructure(tags, startPos, endPos, webResData);
   int tagsNumber = ArraySize(tags);
   
   string text = "";
   string currTag;
   int start[1][2];
   int end[1][2];
  
   for (i = 0; i < tagsNumber; i++)
      {
      currTag = tags[i];     

      if (currTag == "<weeklyevents>")
         {
            Print("Начало блока новостей;");
         }

      if (currTag == "<event>")
         {
            text = "";
            start[0][0] = -1;
            start[0][1] = -1;
         }

      if (currTag == "<title>")
         {// координаты начальной позиции для выборки содержимого между тегами
            start[0][0] = endPos[i][0];
            start[0][1] = endPos[i][1];
         }
                 
      if (currTag == "</title>")
         {// координаты конечной позиции для выборки содержимого между тегами
            end[0][0] = startPos[i][0];
            end[0][1] = startPos[i][1];
            text = text + GetContent(webResData, start, end) + ";";
         }

      if (currTag == "<country>")
         {// координаты начальной позиции для выборки содержимого между тегами
            start[0][0] = endPos[i][0];
            start[0][1] = endPos[i][1];
         }
                       
      if (currTag == "</country>")
         {// координаты конечной позиции для выборки содержимого между тегами
            end[0][0] = startPos[i][0];
            end[0][1] = startPos[i][1];
            text = text + GetContent(webResData, start, end) + " ;";
         }

      if (currTag == "</event>")
         {
            Print(text);
         }

      if (currTag == "</weeklyevents>")
         {
            Print("конец новостей;");
         }

      }

С помощью функции FillTagStructure() мы получаем количество и структуру тегов, а с помощью функции GetContent() - их значение.

Результат работы скрипта:

Рис 1. Результат работы скрипта NewsRss

В результатах работы мы видим название новости и символ валюты страны, к которой данная новость относится.


Выводы

В статье рассмотрен способ чтения RSS средствами MQL4 с использованием функций анализа HTML-тегов. О недостатках данного способа достаточно сказано в статье "Разбор HTML средствами MQL4". От себя хочу добавить, что к недостаткам реализации можно отнести некоторое "неудобство" использования функций в коде, в отличии от других стандартных библиотек для чтения XML.

После написания данной статьи и скрипта я задумался о подключении внешней библиотеки для работы с XML. К плюсам я бы отнес быстроту реализации.