通过 MQL4 读取 RSS 新闻递送

vgs | 11 四月, 2016

简介

本文讨论了利用使用 MQL4 进行 HTML 预排一文中的函数通过 MQL4 阅读 RSS 标记的示例。 本文假定读者已经阅读了上述文章或者至少对上文描述的理念基本理解。



什么是 RSS?为什么在 MQL4 中需要 RSS?

RSS 是一种将不同数据从一个数据源传输到另一个数据源的 XML 格式。

RSS 被通讯社、公司以及各种新闻站点广泛使用。

RSS 能够由多种专门应用程序(阅读器)进行聚合(或读取),并且以一种方便的形式传递给用户。 本文中,我们将尝试制作一个半成品,它可以继续转变为新闻指示器或 MQL4 语言的 RSS 阅读器。 在 RSS 中我们对哪种信息感兴趣呢? 当然是新闻了。

如上所述,RSS 是一种 XML 文件。 那么,什么是 XML?

Xml(可扩展标记语言)是用于储存结构化数据的文本格式。 该结构可以形象的表现为元素树。 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 有些类似。 因此,为了避免“无谓的重复工作”,我们将利用使用 MQL4 进行 HTML 预排一文中的代码。

首先我们需要将 HTML 预排函数关联我们的项目(指标)。 为此,下载 ReportHTMLtoCSV-2.mq4 文件并放到 experts/include 文件夹。 由于我们打算将该文件作为函数库,需要在里面对 start() 函数添加注释。

为了更加明确,我还建议对文件重命名(例如,重命名为 HTMLTagsLib.mq4)。

文件已经就绪。 现在,将其关联到指标(指标的半成品文件附在下面):

#include <htmltagslib.mq4>

现在,我们需要包含 wininet.dll Windows 标准库以使用链接:

#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

我们将使用 ReadWebResource(链接地址)函数来读取 URL。 函数的运行并非本文要讨论的内容。 因此,我们不予详述。

我们只对输入和输出参数感兴趣。 函数接收要读取的链接并返回作为字符串的源内容。

为了分析标签,我们将使用 HTMLTagsLib.mq4 文件中的两个函数 - FillTagStructure() 和 GetContent()。 对这些函数在使用 MQL4 进行 HTML 预排一文中有详细的描述。 应该注意的是,用于分析的输入数据作为数组进行传递。 因此,在收到数据后,应该使用 ReadWebResource(链接地址)函数将其转换为数组。

ArrayFromString() 函数可以帮助我们:

//+------------------------------------------------------------------+
int ArrayFromString(string & webResData[], string inputStr, string divider) 
{   
   if (inputStr == "") 
   {
     Print ("Input string is not set"); 
     return(0);
   }
   if (divider == "") 
   {
      Print ("Separator is not set"); 
      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);
}

将三个参数传递到函数的输入。 第一个是储存函数运行结果的数组的链接,第二个是应转换为数组的字符串,第三个是分割字符串的分隔符。 函数返回产生的数组中的行数。

现在可以对我们的数据进行分析。

在下一个片段,我们分析数据并在终端面板上显示标题和国家标签值。

   string webRss = ReadWebResource(rssUrl);
   int i, stringsCount = ArrayFromString(webResData, webRss, ">");      
            
   string tags[];    // array for storing the tags
   int startPos[][2];// tag start coordinates
   int endPos[][2];  // tag end coordinates
   
   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("News block start;");
         }

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

      if (currTag == "<title>")
         {// coordinates of the initial position for selecting the content between the tags
            start[0][0] = endPos[i][0];
            start[0][1] = endPos[i][1];
         }
                 
      if (currTag == "</title>")
         {// coordinates of the end position for selecting the contents between the tags
            end[0][0] = startPos[i][0];
            end[0][1] = startPos[i][1];
            text = text + GetContent(webResData, start, end) + ";";
         }

      if (currTag == "<country>")
         {// coordinates of the initial position for selecting the content between the tags
            start[0][0] = endPos[i][0];
            start[0][1] = endPos[i][1];
         }
                       
      if (currTag == "</country>")
         {// coordinates of the end position for selecting the contents between the tags
            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("end of the news;");
         }

      }

利用 FillTagStructure() 函数,我们得到标签的数量和结构,而 GetContent() 函数则提供了它们的值。

脚本运行结果:

脚本运行结果

图 1 NewsRss 脚本运行结果

从结果中,可以看到新闻标题和新闻相关的国家货币符号。



总结

我们检验了利用 HTML 标签分析的函数通过 MQL4 读取 RSS 的方法。 对于这种方法的缺点,在使用 MQL4 进行 HTML 预排一文中有详细的描述。 我还想补充一点,跟其他读取 XML 的标准库相比,这种方法的缺点是在代码中使用函数“不太方便”。

在完成了本文和脚本后,我打算考虑关联外部库以利用 XML。 至于优点,我认为实现速度是其中之一。