Criando um feed de notícias personalizado para o MetaTrader 5

Francis Dube | 4 abril, 2018


Introdução

No terminal MetaTrader 5, existem muitas funções que podem ser úteis para o usuário, independentemente de seu estilo de negociação, inclusive a capacidade de acessar um feed de notícias. Isso dá ao trader um contexto comercial, cuja importância é difícil de superestimar, porque ele pode influenciar os mercados. A única limitação é o volume de notícias fornecido. Acredito que os traders podem se beneficiar do acesso a um canal de notícias mais flexível, que oferece a oportunidade de escolher não apenas o tipo de notícia, mas também sua fonte.


Feed de notícias integrado

Dependendo da corretora com quem você trabalha, o feed de notícias pode ser muito útil ou, ao contrário, completamente inútil. Afinal, você tem que confiar apenas em como este recurso é implementado pela sua corretora. Algumas empresas de corretagem fornecem acesso a feeds de notícias relevantes de agências de notícias confiáveis. Você pode estudar a criação de um aplicativo que satisfaça esse pedido.

API de notícias

Como todas as notícias de que necessitamos estão disponíveis gratuitamente na web, tudo o que precisamos é ter acesso direto às de que precisamos. Uma maneira de conseguir isso é usar as ferramentas de RSS. Eu já escrevi um artigo sobre como escrever código do leitor RSS para o MetaTrader 5. A maior desvantagem desse método é que você deve inserir manualmente cada URL. Isso, combinado com as configurações adicionais necessárias para resolver consulta à Web no terminal, pode ser tedioso.

Na minha opinião, a melhor solução é usar uma API Web. Após uma longa pesquisa, encontrei uma API gratuita que fornece acesso a vários canais de notícias. Ela é chamada de NewsAPI e está disponível via solicitação HTTP Get, que retorna metadados do formato json. Essa interface permite receber notícias publicadas no canal selecionado. Ela já tem muitas notícias para escolher, e afirma-se que serão adicionadas mais. Também é bem-vindo o fato de os usuários oferecerem novas fontes. Parece que o serviço não tem diversidade linguística suficiente, uma vez que predominam as fontes de notícias dos EUA e da Europa. No entanto, acho que esta é uma opção aceitável. Outra vantagem é o acesso a todas as fontes a partir de um único endereço Web.

Acesso ao NewsAPI

Para trabalhar com o NewsAPI, você deve estar autorizado a acessar todos os seus serviços. Para fazer isso, vá para o site oficial e clique no botão Get API Key. Registre seu e-mail e você receberá uma chave de API que precisará a fim de acessar todas as funções.

Site da Web do NewsAPI


Usando a API

O acesso a todos os recursos da API está disponível mediante solicitação usando duas URL:

  1. https://newsapi.org/v1/sources? - uma consulta feita neste formulário retornará uma lista de todos os recursos de notícias disponíveis na API.
    Essa lista também inclui informações sobre o identificador - para cada recurso - que deve ser especificado ao consultar os cabeçalhos das notícias mais recentes. A URL do recurso também pode ser otimizada com parâmetros opcionais que determinam qual tipo de lista de origem será retornado.
  2. https://newsapi.org/v1/articles? - URL do artigo que retorna manchetes e fragmentos de notícias de determinadas fontes. A URL deve conter dois parâmetros obrigatórios. O primeiro é um identificador que aponta exclusivamente para a fonte requerida. A segunda é a chave da API para autorização.

Parâmetros
Descrição dos parâmetros
Possíveis valores de parâmetros
Fontes/Artigos
 Exemplo
Categoria (opcional)
Categoria de notícias para as quais você gostaria de receber fontes Negócios, entretenimento, jogos, geral, música, política, ciência e natureza, esportes, tecnologia ... Fontes de informação
https://newsapi.org/v1/sources?category=business


Idioma (opcional)
Idioma de fontes de notícias
en, de, fr Fontes de informação
https://newsapi.org/v1/sources?language=en
País (opcional)
País em que está localizada a fonte
au, de, gb, in, it, us Fontes de informação
https://newsapi.org/v1/sources?country=us
Fonte (obrigatório)
Identificador de fonte de notícias
Selecione qualquer uma fonte da lista retornado mediante consulta usando a URL
Artigos
https://newsapi.org/v1/articles?source=cnbc&apiKey=API_KEY
Chave de API (obrigatório)
Token de autorização do usuário

Artigos
ver exemplo acima
 Classificar por A maneira como as notícias serão classificadas: popularidade, em ordem de aparição no site, em ordem cronológica.
 top, latest, popular  Artigos  https://newsapi.org/v1/articles?source=cnbc&sortBy=top&apiKey=API_KEY

A tabela acima mostra os principais parâmetros que você pode usar nas configurações da API junto com duas URL. Para ver sua lista completa, consulte a documentação disponível no site.

Script para teste de API

Agora que temos uma ideia geral de como usar a API, é hora de testá-la. O script que criaremos serve para nos familiarizarmos com as respostas que a API fornece em resposta à consulta. Isso requer que o script possa fazer uma consulta à Web e salvar as respostas num arquivo de texto. Ao usar o script, deveremos testar qualquer solicitação da API e observar a resposta.

Código do script NewsAPI_test:

//+------------------------------------------------------------------+ 
//|                                                 NewsAPI_test.mq5 |
//|                                          Copyright 2017, ufranco |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+ 
#property copyright "Copyright 2017, ufranco"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property script_show_inputs


#define BASE_URL "https://newsapi.org/v1/"
#define SRCE "sources?"
#define ATCLE "articles?source="
#define API_KEY "&apiKey=484c84eb9765418fb58ea936908a47ac"
//+------------------------------------------------------------------+ 
//|                                                                  |
//+------------------------------------------------------------------+ 
enum mode 
  {
   sources,
   articles
  };

input string sFilename="sorce.txt";
input mode Mode=sources;
input string parameters="";
int timeout=5000;
//+------------------------------------------------------------------+ 
//| Script program start function                                     |
//+------------------------------------------------------------------+ 
void OnStart()
  {
//--- 
   TestWebRequest();
  }
//+------------------------------------------------------------------+ 
//| TestWebRequest                                                   |
//+------------------------------------------------------------------+ 
void TestWebRequest(void)
  {
   string cookie=NULL,headers;
   char post[],result[];
   int res;
   string _url;
//--- 
   switch(Mode)
     {
      case sources:
         _url=BASE_URL+SRCE+parameters;
         break;
      case articles:
         _url=BASE_URL+ATCLE+parameters+API_KEY;
         break;
     }
//--- 
   ResetLastError();
   res=WebRequest("GET",_url,cookie,NULL,timeout,post,0,result,headers);

   if(res==-1)
     {
      Alert("Could not download file");
      return;
     }
   else Print("Download success");

   string pStream=CharArrayToString(result,0,-1,CP_UTF8);

   int hFile=FileOpen(sFilename,FILE_BIN|FILE_WRITE);

   if(hFile==INVALID_HANDLE)
     {
      Print("Invalid file handle");
      return;
     }

   FileWriteString(hFile,pStream);
   FileClose(hFile);

   return;
  }


Primeiro, existem diretivas define que representam os vários componentes da URL que compõem a solicitação da API. Como a primeira variável de usuário, temos sFilename. Digite o nome do arquivo no qual as respostas da API serão colocadas. O parâmetro Mode é uma enumeração que permite alternar entre as duas URL principais da API.

O parâmetro personalizado parameters é usado para inserir parâmetros de URL adicionais (obrigatórios ou opcionais) para inclusão na solicitação da API. Em nosso script, haverá apenas uma função criando uma chamada API de URL, dependendo das configurações selecionadas. Se a função tiver concluído com êxito a consulta, os metadados serão salvos no arquivo.

Agora podemos realizar vários testes e estudar as respostas. Primeiro, testamos o início do script usando os parâmetros padrão. Em seguida, abrimos o arquivo: a resposta da API pode ser lida. É importante observar a estrutura do objeto json, quando precisamos extrair informações específicas da matriz de dados.

{
   "status":"ok","sources":
   [
     {"id":"abc-news-au","name":"ABC News (AU)","description":"Australia's most trusted source of local, national and world news. Comprehensive, independent, in-depth analysis, the latest business, sport, weather and more.","url":"http://www.abc.net.au/news","category":"general","language":"en","country":"au","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"al-jazeera-english","name":"Al Jazeera English","description":"News, analysis from the Middle East and worldwide, multimedia and interactives, opinions, documentaries, podcasts, long reads and broadcast schedule.","url":"http://www.aljazeera.com","category":"general","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"ars-technica","name":"Ars Technica","description":"The PC enthusiast's resource. Power users and the tools they love, without computing religion.","url":"http://arstechnica.com","category":"technology","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"associated-press","name":"Associated Press","description":"The AP delivers in-depth coverage on the international, politics, lifestyle, business, and entertainment news.","url":"https://apnews.com/","category":"general","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"bbc-news","name":"BBC News","description":"Use BBC News for up-to-the-minute news, breaking news, video, audio and feature stories. BBC News provides trusted World and UK news as well as local and regional perspectives. Also entertainment, business, science, technology and health news.","url":"http://www.bbc.co.uk/news","category":"general","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"bbc-sport","name":"BBC Sport","description":"The home of BBC Sport online. Includes live sports coverage, breaking news, results, video, audio and analysis on Football, F1, Cricket, Rugby Union, Rugby League, Golf, Tennis and all the main world sports, plus major events such as the Olympic Games.","url":"http://www.bbc.co.uk/sport","category":"sport","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"bild","name":"Bild","description":"Die Seite 1 für aktuelle Nachrichten und Themen, Bilder und Videos aus den Bereichen News, Wirtschaft, Politik, Show, Sport, und Promis.","url":"http://www.bild.de","category":"general","language":"de","country":"de","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"bloomberg","name":"Bloomberg","description":"Bloomberg delivers business and markets news, data, analysis, and video to the world, featuring stories from Businessweek and Bloomberg News.","url":"http://www.bloomberg.com","category":"business","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"breitbart-news","name":"Breitbart News","description":"Syndicated news and opinion website providing continuously updated headlines to top news and analysis sources.","url":"http://www.breitbart.com","category":"politics","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"business-insider","name":"Business Insider","description":"Business Insider is a fast-growing business site with deep financial, media, tech, and other industry verticals. Launched in 2007, the site is now the largest business news site on the web.","url":"http://www.businessinsider.com","category":"business","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"business-insider-uk","name":"Business Insider (UK)","description":"Business Insider is a fast-growing business site with deep financial, media, tech, and other industry verticals. Launched in 2007, the site is now the largest business news site on the web.","url":"http://uk.businessinsider.com","category":"business","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"buzzfeed","name":"Buzzfeed","description":"BuzzFeed is a cross-platform, global network for news and entertainment that generates seven billion views each month.","url":"https://www.buzzfeed.com","category":"entertainment","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"cnbc","name":"CNBC","description":"Get latest business news on stock markets, financial & earnings on CNBC. View world markets streaming charts & video; check stock tickers and quotes.","url":"http://www.cnbc.com","category":"business","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"cnn","name":"CNN","description":"View the latest news and breaking news today for U.S., world, weather, entertainment, politics and health at CNN","url":"http://us.cnn.com","category":"general","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"daily-mail","name":"Daily Mail","description":"All the latest news, sport, showbiz, science and health stories from around the world from the Daily Mail and Mail on Sunday newspapers.","url":"http://www.dailymail.co.uk/home/index.html","category":"entertainment","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"der-tagesspiegel","name":"Der Tagesspiegel","description":"Nachrichten, News und neueste Meldungen aus dem Inland und dem Ausland - aktuell präsentiert von tagesspiegel.de.","url":"http://www.tagesspiegel.de","category":"general","language":"de","country":"de","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["latest"]},
     {"id":"die-zeit","name":"Die Zeit","description":"Aktuelle Nachrichten, Kommentare, Analysen und Hintergrundberichte aus Politik, Wirtschaft, Gesellschaft, Wissen, Kultur und Sport lesen Sie auf ZEIT ONLINE.","url":"http://www.zeit.de/index","category":"business","language":"de","country":"de","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["latest"]},
     {"id":"engadget","name":"Engadget","description":"Engadget is a web magazine with obsessive daily coverage of everything new in gadgets and consumer electronics.","url":"https://www.engadget.com","category":"technology","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"entertainment-weekly","name":"Entertainment Weekly","description":"Online version of the print magazine includes entertainment news, interviews, reviews of music, film, TV and books, and a special area for magazine subscribers.","url":"http://www.ew.com","category":"entertainment","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"espn","name":"ESPN","description":"ESPN has up-to-the-minute sports news coverage, scores, highlights and commentary for NFL, MLB, NBA, College Football, NCAA Basketball and more.","url":"http://espn.go.com","category":"sport","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"espn-cric-info","name":"ESPN Cric Info","description":"ESPN Cricinfo provides the most comprehensive cricket coverage available including live ball-by-ball commentary, news, unparalleled statistics, quality editorial comment and analysis.","url":"http://www.espncricinfo.com/","category":"sport","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"financial-times","name":"Financial Times","description":"The latest UK and international business, finance, economic and political news, comment and analysis from the Financial Times on FT.com.","url":"http://www.ft.com/home/uk","category":"business","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"focus","name":"Focus","description":"Minutenaktuelle Nachrichten und Service-Informationen von Deutschlands modernem Nachrichtenmagazin.","url":"http://www.focus.de","category":"general","language":"de","country":"de","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"football-italia","name":"Football Italia","description":"Italian football news, analysis, fixtures and results for the latest from Serie A, Serie B and the Azzurri.","url":"http://www.football-italia.net","category":"sport","language":"en","country":"it","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"fortune","name":"Fortune","description":"Fortune 500 Daily and Breaking Business News","url":"http://fortune.com","category":"business","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"four-four-two","name":"FourFourTwo","description":"The latest football news, in-depth features, tactical and statistical analysis from FourFourTwo, the UK's favourite football monthly.","url":"http://www.fourfourtwo.com/news","category":"sport","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"fox-sports","name":"Fox Sports","description":"Find live scores, player and team news, videos, rumors, stats, standings, schedules and fantasy games on FOX Sports.","url":"http://www.foxsports.com","category":"sport","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"google-news","name":"Google News","description":"Comprehensive, up-to-date news coverage, aggregated from sources all over the world by Google News.","url":"https://news.google.com","category":"general","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"gruenderszene","name":"Gruenderszene","description":"Online-Magazin für Startups und die digitale Wirtschaft. News und Hintergründe zu Investment, VC und Gründungen.","url":"http://www.gruenderszene.de","category":"technology","language":"de","country":"de","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"hacker-news","name":"Hacker News","description":"Hacker News is a social news website focusing on computer science and entrepreneurship. It is run by Paul Graham's investment fund and startup incubator, Y Combinator. In general, content that can be submitted is defined as \"anything that gratifies one's intellectual curiosity\".","url":"https://news.ycombinator.com","category":"technology","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"handelsblatt","name":"Handelsblatt","description":"Auf Handelsblatt lesen sie Nachrichten über Unternehmen, Finanzen, Politik und Technik. Verwalten Sie Ihre Finanzanlagen mit Hilfe unserer Börsenkurse.","url":"http://www.handelsblatt.com","category":"business","language":"de","country":"de","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["latest"]},
     {"id":"ign","name":"IGN","description":"IGN is your site for Xbox One, PS4, PC, Wii-U, Xbox 360, PS3, Wii, 3DS, PS Vita and iPhone games with expert reviews, news, previews, trailers, cheat codes, wiki guides and walkthroughs.","url":"http://www.ign.com","category":"gaming","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"independent","name":"Independent","description":"National morning quality (tabloid) includes free online access to news and supplements. Insight by Robert Fisk and various other columnists.","url":"http://www.independent.co.uk","category":"general","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"mashable","name":"Mashable","description":"Mashable is a global, multi-platform media and entertainment company.","url":"http://mashable.com","category":"entertainment","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"metro","name":"Metro","description":"News, Sport, Showbiz, Celebrities from Metro - a free British newspaper.","url":"http://metro.co.uk","category":"general","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"mirror","name":"Mirror","description":"All the latest news, sport and celebrity gossip at Mirror.co.uk. Get all the big headlines, pictures, analysis, opinion and video on the stories that matter to you.","url":"http://www.mirror.co.uk/","category":"general","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"mtv-news","name":"MTV News","description":"The ultimate news source for music, celebrity, entertainment, movies, and current events on the web. It's pop culture on steroids.","url":"http://www.mtv.com/news","category":"music","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"mtv-news-uk","name":"MTV News (UK)","description":"All the latest celebrity news, gossip, exclusive interviews and pictures from the world of music and entertainment.","url":"http://www.mtv.co.uk/news","category":"music","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"national-geographic","name":"National Geographic","description":"Reporting our world daily: original nature and science news from National Geographic.","url":"http://news.nationalgeographic.com","category":"science-and-nature","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"new-scientist","name":"New Scientist","description":"Breaking science and technology news from around the world. Exclusive stories and expert analysis on space, technology, health, physics, life and Earth.","url":"https://www.newscientist.com/section/news","category":"science-and-nature","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"newsweek","name":"Newsweek","description":"Newsweek provides in-depth analysis, news and opinion about international issues, technology, business, culture and politics.","url":"http://www.newsweek.com","category":"general","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"new-york-magazine","name":"New York Magazine","description":"NYMAG and New York magazine cover the new, the undiscovered, the next in politics, culture, food, fashion, and behavior nationally, through a New York lens.","url":"http://nymag.com","category":"general","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"nfl-news","name":"NFL News","description":"The official source for NFL news, schedules, stats, scores and more.","url":"http://www.nfl.com/news","category":"sport","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"polygon","name":"Polygon","description":"Polygon is a gaming website in partnership with Vox Media. Our culture focused site covers games, their creators, the fans, trending stories and entertainment news.","url":"http://www.polygon.com","category":"gaming","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"recode","name":"Recode","description":"Get the latest independent tech news, reviews and analysis from Recode with the most informed and respected journalists in technology and media.","url":"http://www.recode.net","category":"technology","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"reddit-r-all","name":"Reddit /r/all","description":"Reddit is an entertainment, social news networking service, and news website. Reddit's registered community members can submit content, such as text posts or direct links.","url":"https://www.reddit.com/r/all","category":"general","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"reuters","name":"Reuters","description":"Reuters.com brings you the latest news from around the world, covering breaking news in business, politics, entertainment, technology, video and pictures.","url":"http://www.reuters.com","category":"general","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"spiegel-online","name":"Spiegel Online","description":"Deutschlands führende Nachrichtenseite. Alles Wichtige aus Politik, Wirtschaft, Sport, Kultur, Wissenschaft, Technik und mehr.","url":"http://www.spiegel.de","category":"general","language":"de","country":"de","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"t3n","name":"T3n","description":"Das Online-Magazin bietet Artikel zu den Themen E-Business, Social Media, Startups und Webdesign.","url":"http://t3n.de","category":"technology","language":"de","country":"de","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"talksport","name":"TalkSport","description":"Tune in to the world's biggest sports radio station - Live Premier League football coverage, breaking sports news, transfer rumours & exclusive interviews.","url":"http://talksport.com","category":"sport","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"techcrunch","name":"TechCrunch","description":"TechCrunch is a leading technology media property, dedicated to obsessively profiling startups, reviewing new Internet products, and breaking tech news.","url":"https://techcrunch.com","category":"technology","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"techradar","name":"TechRadar","description":"The latest technology news and reviews, covering computing, home entertainment systems, gadgets and more.","url":"http://www.techradar.com","category":"technology","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"the-economist","name":"The Economist","description":"The Economist offers authoritative insight and opinion on international news, politics, business, finance, science, technology and the connections between them.","url":"http://www.economist.com","category":"business","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"the-guardian-au","name":"The Guardian (AU)","description":"Latest news, sport, comment, analysis and reviews from Guardian Australia","url":"https://www.theguardian.com/au","category":"general","language":"en","country":"au","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"the-guardian-uk","name":"The Guardian (UK)","description":"Latest news, sport, business, comment, analysis and reviews from the Guardian, the world's leading liberal voice.","url":"https://www.theguardian.com/uk","category":"general","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"the-hindu","name":"The Hindu","description":"The Hindu. latest news, analysis, comment, in-depth coverage of politics, business, sport, environment, cinema and arts from India's national newspaper.","url":"http://www.thehindu.com","category":"general","language":"en","country":"in","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"the-huffington-post","name":"The Huffington Post","description":"The Huffington Post is a politically liberal American online news aggregator and blog that has both localized and international editions founded by Arianna Huffington, Kenneth Lerer, Andrew Breitbart, and Jonah Peretti, featuring columnists.","url":"http://www.huffingtonpost.com","category":"general","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"the-lad-bible","name":"The Lad Bible","description":"The LAD Bible is one of the largest community for guys aged 16-30 in the world. Send us your funniest pictures and videos!","url":"http://www.theladbible.com","category":"entertainment","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"the-new-york-times","name":"The New York Times","description":"The New York Times: Find breaking news, multimedia, reviews & opinion on Washington, business, sports, movies, travel, books, jobs, education, real estate, cars & more at nytimes.com.","url":"http://www.nytimes.com","category":"general","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"the-next-web","name":"The Next Web","description":"The Next Web is one of the world’s largest online publications that delivers an international perspective on the latest news about Internet technology, business and culture.","url":"http://thenextweb.com","category":"technology","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["latest"]},
     {"id":"the-sport-bible","name":"The Sport Bible","description":"TheSPORTbible is one of the largest communities for sports fans across the world. Send us your sporting pictures and videos!","url":"http://www.thesportbible.com","category":"sport","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"the-telegraph","name":"The Telegraph","description":"Latest news, business, sport, comment, lifestyle and culture from the Daily Telegraph and Sunday Telegraph newspapers and video from Telegraph TV.","url":"http://www.telegraph.co.uk","category":"general","language":"en","country":"gb","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"the-times-of-india","name":"The Times of India","description":"Times of India brings the Latest News and Top Breaking headlines on Politics and Current Affairs in India and around the World, Sports, Business, Bollywood News and Entertainment, Science, Technology, Health and Fitness news, Cricket and opinions from leading columnists.","url":"http://timesofindia.indiatimes.com","category":"general","language":"en","country":"in","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"the-verge","name":"The Verge","description":"The Verge covers the intersection of technology, science, art, and culture.","url":"http://www.theverge.com","category":"technology","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"the-wall-street-journal","name":"The Wall Street Journal","description":"WSJ online coverage of breaking news and current headlines from the US and around the world. Top stories, photos, videos, detailed analysis and in-depth reporting.","url":"http://www.wsj.com","category":"business","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"the-washington-post","name":"The Washington Post","description":"Breaking news and analysis on politics, business, world national news, entertainment more. In-depth DC, Virginia, Maryland news coverage including traffic, weather, crime, education, restaurant reviews and more.","url":"https://www.washingtonpost.com","category":"general","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top"]},
     {"id":"time","name":"Time","description":"Breaking news and analysis from TIME.com. Politics, world news, photos, video, tech reviews, health, science and entertainment news.","url":"http://time.com","category":"general","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"usa-today","name":"USA Today","description":"Get the latest national, international, and political news at USATODAY.com.","url":"http://www.usatoday.com/news","category":"general","language":"en","country":"us","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"wired-de","name":"Wired.de","description":"Wired reports on how emerging technologies affect culture, the economy and politics.","url":"https://www.wired.de","category":"technology","language":"de","country":"de","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["top","latest"]},
     {"id":"wirtschafts-woche","name":"Wirtschafts Woche","description":"Das Online-Portal des führenden Wirtschaftsmagazins in Deutschland. Das Entscheidende zu Unternehmen, Finanzen, Erfolg und Technik.","url":"http://www.wiwo.de","category":"business","language":"de","country":"de","urlsToLogos":{"small":"","medium":"","large":""},"sortBysAvailable":["latest"]}
   ]
  }

Ao abrir o arquivo, vemos que a resposta contém uma matriz de objetos json representando todos os canais de notícias dos quais você pode solicitar cabeçalhos de notícias.

O próximo teste é enviar a consulta de API, da fonte selecionada. Abrimos o arquivo novamente e examinamos a resposta.

{
   "status":"ok","source":"cnbc","sortBy":"top","articles":
   [
     {"author":"Reuters","title":"'Singles Day' China shopping festival smashes record at the halfway mark","description":"Alibaba said its Singles Day sales surged past last year's total just after midday Saturday, hitting a record $18 billion.","url":"https://www.cnbc.com/2017/11/11/singles-day-china-shopping-festival-smashes-record-at-the-halfway-mark.html","urlToImage":"https://fm.cnbc.com/applications/cnbc.com/resources/img/editorial/2017/11/10/104835461-RTS1JDT7-singles-day.1910x1000.jpg","publishedAt":"2017-11-11T10:50:08Z"},
     {"author":"The Associated Press","title":"Trump: Putin again denies meddling in 2016 election","description":"President Donald Trump said Saturday that Russia's Vladimir Putin again denied interfering in the 2016 U.S. elections.","url":"https://www.cnbc.com/2017/11/11/trump-putin-again-denies-meddling-in-2016-election.html","urlToImage":"https://fm.cnbc.com/applications/cnbc.com/resources/img/editorial/2017/08/18/104661874-RTS19PQA-vladimir-putin.1910x1000.jpg","publishedAt":"2017-11-11T12:07:32Z"},
     {"author":"Jeff Cox","title":"GE limps into investor day with shareholders demanding answers on dividend and turnaround plan","description":"As General Electric limps into its investor day presentation Monday, it has gone from a paradigm of success to a morass of excess.","url":"https://www.cnbc.com/2017/11/10/ge-faces-investor-day-with-questions-about-its-past-and-future.html","urlToImage":"https://fm.cnbc.com/applications/cnbc.com/resources/img/editorial/2017/10/20/104786151-JohnFlannery2.1910x1000.jpg","publishedAt":"2017-11-10T16:16:05Z"},
     {"author":"Sarah Whitten","title":"Here's where military service members can get freebies on Veterans Day","description":"Businesses across the country are saying \"thank you\" to Veterans on Friday by offering freebies to active and retired military members.","url":"https://www.cnbc.com/2016/11/10/heres-where-military-service-members-can-get-freebies-on-veterans-day.html","urlToImage":"https://fm.cnbc.com/applications/cnbc.com/resources/img/editorial/2016/11/10/104097817-GettyImages-496717392.1910x1000.jpg","publishedAt":"2016-11-10T18:30:41Z"},
     {"author":"Morgan Brennan","title":"With an eye toward the North Korean threat, a 'missile renaissance' blooms in the US","description":"Raytheon is cranking out about 20 Standard Missile variants per month, as part of the effort to help repel a possible attack from North Korea.","url":"https://www.cnbc.com/2017/11/11/north-korea-threat-leads-to-a-us-missile-renaissance.html","urlToImage":"https://fm.cnbc.com/applications/cnbc.com/resources/img/editorial/2017/08/03/104631031-RTS1A3SU.1910x1000.jpg","publishedAt":"2017-11-11T14:00:56Z"},
     {"author":"Larry Kudlow","title":"Larry Kudlow: A pro-growth GOP tax cut is on the way — this year","description":"One way or another, Congress will come up with a significant pro-growth bill, writes Larry Kudlow.","url":"https://www.cnbc.com/2017/11/11/larry-kudlow-pro-growth-gop-tax-cut-is-on-the-way--this-year.html","urlToImage":"https://fm.cnbc.com/applications/cnbc.com/resources/img/editorial/2017/11/02/104816986-GettyImages-869498942.1910x1000.jpg","publishedAt":"2017-11-11T14:22:58Z"},
     {"author":"Reuters","title":"Trans-Pacific trade deal advances without United States","description":"Last-minute resistance from Canada had raised new doubts about its survival.","url":"https://www.cnbc.com/2017/11/11/trans-pacific-trade-deal-advances-without-united-states.html","urlToImage":"https://fm.cnbc.com/applications/cnbc.com/resources/img/editorial/2016/11/22/104123278-GettyImages-624177112.1910x1000.jpg","publishedAt":"2017-11-11T10:23:03Z"},
     {"author":"Jacob Pramuk","title":"McConnell says he 'misspoke' about middle-class tax hikes","description":"Mitch McConnell told The New York Times that \"you can't guarantee that no one sees a tax increase.\"","url":"https://www.cnbc.com/2017/11/10/mitch-mcconnell-says-he-misspoke-about-republican-tax-plan.html","urlToImage":"https://fm.cnbc.com/applications/cnbc.com/resources/img/editorial/2017/09/22/104726784-RTX3FY40-mcconnell.1910x1000.jpg","publishedAt":"2017-11-10T23:04:47Z"},
     {"author":"Erin Barry","title":"Start-up Dia&Co is catering the 70 percent of US women the fashion industry ignores","description":"There are more than 100 million plus-size women in the U.S., but finding fashionable clothes in their size can be a challenge.","url":"https://www.cnbc.com/2017/11/10/diaco-caters-to-the-70-percent-of-us-women-fashion-ignores.html","urlToImage":"https://fm.cnbc.com/applications/cnbc.com/resources/img/editorial/2017/02/22/104298276-Lydia-Gilbert--Nadia-Boujarwah-2_credit-DiaCo_r.1910x1000.jpg","publishedAt":"2017-11-11T14:01:01Z"},
     {"author":"Elizabeth Gurdus","title":"Cramer shares a little-known investing concept critical to buying stocks","description":"Jim Cramer explained why the idea of suitability is crucial when it comes to individual investing.","url":"https://www.cnbc.com/2017/11/10/cramer-shares-an-investing-concept-critical-to-buying-stocks.html","urlToImage":"https://fm.cnbc.com/applications/cnbc.com/resources/img/editorial/2017/11/10/104835669-GettyImages-825493934.1910x1000.jpg","publishedAt":"2017-11-10T23:10:58Z"}
   ]
  }


Neste exemplo, a resposta da API contém uma matriz de objetos json em que cada objeto é uma manchete.

Para finalizar, vamos entender qual resposta recebemos enviando uma consulta de API incorreta. Veja os resultados retornados ao usar a chave incorreta de API:

{
  "status":"error",
  "code":"apiKeyInvalid",
  "message":"Your API key is invalid or incorrect. Check your key, or go to https://newsapi.org to create a free API
  key."  
}


Outro exemplo de um erro de resposta: aqui a consulta foi feita com um ID de origem incorreto.

{
 "status":"error",
 "code":"sourceDoesntExist",
 "message":"The news source you've entered doesn't exist. Check your spelling, or see /v1/sources for a list of valid sources."
}

Depois de experimentar a API, podemos ver como você pode extrair rapidamente os dados com o analisador json.

Analisamos os metadados JSON

Na biblioteca de códigos MQL5.com estão disponíveis duas bibliotecas json. A primeira com a qual tentaremos trabalhar é json.mqh. A compilação do script de teste que usa essa biblioteca mostrou vários erros e avisos. Esses erros são armazenados nos próprios arquivos da biblioteca. Na página em que a biblioteca é publicada, o autor afirma que o código é ativamente suportado no GitHub. No entanto, o autor não atualizou o arquivo do código disponível na biblioteca em mql5.com.

Corrigir erros de compilação foi bem simples. Foi necessário apenas conectar o arquivo hash diretamente ao arquivo json.mqh. Todos os avisos foram causados ​​por uma coerção de tipo implícita. O arquivo de biblioteca corrigido é mostrado abaixo:

// $Id: json.mqh 102 2014-02-24 03:39:28Z ydrol $
#include "hash.mqh"
#ifndef YDROL_JSON_MQH
#define YDROL_JSON_MQH

// (C)2014 Andrew Lord forex@NICKNAME@lordy.org.uk
// Parse a JSON String - Adapted for mql4++ from my gawk implementation
// ( https://code.google.com/p/oversight/source/browse/trunk/bin/catalog/json.awk )

/*
   TODO the constants true|false|null could be represented as fixed objects.
      To do this the deleting of _hash and _array must skip these objects.

   TODO test null

   TODO Parse Unicode Escape
*/

/*
   O exemplo json_demo é mostrado abaixo.

 Requer que o arquivo hash.mqh esteja instalado no computador ( http://codebase.mql4.com/9238 , http://lordy.co.nf/hash )

 */

enum ENUM_JSON_TYPE { JSON_NULL,JSON_OBJECT,JSON_ARRAY,JSON_NUMBER,JSON_STRING,JSON_BOOL };

class JSONString;
// Classe comum para todos os tipos JSON (Number, String, Bool, Array, Object )
class JSONValue : public HashValue 
  {
private:
   ENUM_JSON_TYPE    _type;

public:
                     JSONValue() {}
                    ~JSONValue() {}
   ENUM_JSON_TYPE getType() { return _type; }
   void setType(ENUM_JSON_TYPE t) { _type=t; }

   // Tipos de métodos
   bool isString() { return _type==JSON_STRING; }
   bool isNull() { return _type==JSON_NULL; }
   bool isObject() { return _type==JSON_OBJECT; }
   bool isArray() { return _type==JSON_ARRAY; }
   bool isNumber() { return _type==JSON_NUMBER; }
   bool isBool() { return _type==JSON_BOOL; }

   // Substituição em classes filhas
   virtual string toString() 
     {
      return "";
     }

   // Alguns métodos auxiliares para apresentação de subtipos
   string getString()
     {
      return ((JSONString *)GetPointer(this)).getString();
     }
   double getDouble()
     {
      return ((JSONNumber *)GetPointer(this)).getDouble();
     }
   long getLong()
     {
      return ((JSONNumber *)GetPointer(this)).getLong();
     }
   int getInt()
     {
      return ((JSONNumber *)GetPointer(this)).getInt();
     }
   bool getBool()
     {
      return ((JSONBool *)GetPointer(this)).getBool();
     }

   // Métodos estáticos para Array and Object que retornam os resultados filhos.
   // Eles permitem que o programa obtenha o valor sem suspender o programa  
   // (às vezes convém suspender o programa, pois o Expert Advisor continuará trabalhando com dados incorretos)
   static bool getString(JSONValue *val,string &out)
     {
      if(val!=NULL && val.isString()) 
        {
         out = val.getString();
         return true;
        }
      return false;
     }
   static bool getBool(JSONValue *val,bool &out)
     {
      if(val!=NULL && val.isBool()) 
        {
         out = val.getBool();
         return true;
        }
      return false;
     }
   static bool getDouble(JSONValue *val,double &out)
     {
      if(val!=NULL && val.isNumber()) 
        {
         out = val.getDouble();
         return true;
        }
      return false;
     }
   static bool getLong(JSONValue *val,long &out)
     {
      if(val!=NULL && val.isNumber()) 
        {
         out = val.getLong();
         return true;
        }
      return false;
     }
   static bool getInt(JSONValue *val,int &out)
     {
      if(val!=NULL && val.isNumber()) 
        {
         out = val.getInt();
         return true;
        }
      return false;
     }
  };
// -----------------------------------------
....


O código do script de teste newstest_json é detalhado abaixo. O script simplesmente lê o arquivo que contém os metadados em formato json salvos como resultado da consulta de API (nós o fizemos no teste anterior). Após executar o script, a lista de todas as fontes de notícias disponíveis contidas no arquivo de dados será exibida no terminal.

//+------------------------------------------------------------------+ 
//|                                                newstest_json.mq5 |
//|                                          Copyright 2017, ufranco |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+ 
#property copyright "Copyright 2017, ufranco"
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <json.mqh>
//+------------------------------------------------------------------+ 
//| Script program start function                                     |
//+------------------------------------------------------------------+ 
void OnStart()
  {
//--- 
   Test();
  }
//+------------------------------------------------------------------+ 
//| Test                                                             |
//+------------------------------------------------------------------+ 
bool Test()
  {

   string pStream;
   string sources_filename="sources.txt";

   int hFile,iStringSize;

// read file contents 
   hFile=::FileOpen(sources_filename,FILE_TXT|FILE_READ|FILE_UNICODE);
   if(hFile==INVALID_HANDLE)
     {
      ::Print("error opening file "+sources_filename);
      return(false);
     }

   while(!::FileIsEnding(hFile))
     {
      iStringSize = ::FileReadInteger(hFile, INT_VALUE);
      pStream    += ::FileReadString(hFile, iStringSize);
     }

   ::FileClose(hFile);

   Print("success opening and reading file");

   JSONParser *parser=new JSONParser();

   JSONValue *jv=parser.parse(pStream);

   if(jv==NULL) 
     {
      Print("error:"+(string)parser.getErrorCode()+parser.getErrorMessage());
        } else {

      if(jv.isObject())
        {
         JSONObject *jo = jv;
         JSONArray  *jd =  jo.getArray("sources");

         for(int i=0;i<jd.size();i++)
           {
            Print(jd.getObject(i).getString("id"));
           }
        }
      delete jv;
     }
   delete parser;

   return(true);
  }


Quando é usado o arquivo correto, a biblioteca funciona corretamente.

library test result


Agora, demos uma olhada na segunda biblioteca para trabalhar com json: JAson.mqh. O teste de execução da biblioteca não mostrou nenhum erro, ela imediatamente funcionou perfeitamente. Para testar essa biblioteca, foi usado o script newstest_JAson .

//+------------------------------------------------------------------+ 
//|                                               newstest_JAson.mq5 |
//|                                          Copyright 2017, ufranco |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+ 
#property copyright "Copyright 2017, ufranco"
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <JAson.mqh>
//+------------------------------------------------------------------+ 
//| Script program start function                                     |
//+------------------------------------------------------------------+ 
void OnStart()
  {
//--- 
   Test();
  }
//+------------------------------------------------------------------+ 
//| Test                                                             |
//+------------------------------------------------------------------+ 
bool Test()
  {

   string pStream;
   string sources_filename="sources.txt";

   int hFile,iStringSize;

// leitura do conteúdo do arquivo 
   hFile=::FileOpen(sources_filename,FILE_TXT|FILE_READ|FILE_UNICODE);
   if(hFile==INVALID_HANDLE)
     {
      ::Print("error opening file "+sources_filename);
      return(false);
     }

   while(!::FileIsEnding(hFile))
     {
      iStringSize = ::FileReadInteger(hFile, INT_VALUE);
      pStream    += ::FileReadString(hFile, iStringSize);
     }

   ::FileClose(hFile);

   Print("success opening and reading file");

   CJAVal  srce;

   if(!srce.Deserialize(pStream))
     {
      ::Print("Json deserialize error");
      return(false);
     }

   CJAVal *json_array=new CJAVal(srce["sources"]);

   for(int i=0;i<ArraySize(json_array.m_e);i++)
     {
      Print(json_array[i]["id"].ToStr());
     }

   delete json_array;

   return(true);
  }


Veja os resultados do teste:

Resultados do teste da biblioteca JAson.mqh

Se você comparar esta biblioteca com a discutida acima (json.mqh), poderá notar que ambas suportam todos os tipos de dados json. A principal diferença é que json.mqh implementa cada tipo de dados json como uma classe e define várias classes. Ao mesmo tempo, em JAson.mqh, os tipos de dados json são definidos pela propriedade pública da classe, portanto, a biblioteca define apenas uma classe.

Seguimos em frente. Agora podemos escrever um aplicativo que exibe notícias para o MetaTrader 5. O aplicativo usará a biblioteca JAson.mqh. Nós o realizaremos na forma de um EA que exibirá uma lista de recursos de notícias. Ao selecionar um item de lista, o campo de texto seguinte exibe as últimas notícias disponíveis, a partir da fonte.

Classe CNewsFeed

No artigo anterior, usei uma biblioteca padrão para criar uma interface gráfica do usuário. Desta vez eu quero estudar o uso da biblioteca de GUI desenvolvida por Anatóli Kajárski. Como a biblioteca parece estar em testes beta e ser atualizada regularmente pelo autor (novas funções são adicionadas a ela), ela tem várias versões estendidas. Eu decidi usar a versão fornecida no artigo Interfaces gráficas XI: refatoração do código da biblioteca. Como me parece, tem tudo o que precisamos e, ao mesmo tempo, nada é supérfluo.

Nosso aplicativo será bastante simples: não precisa de uma barra de menu, nem abas. Vamos começar com o arquivo include que conterá a classe principal para criar o aplicativo.

//+------------------------------------------------------------------+ 
//|                                              NewsFeedProgram.mqh |
//|                                          Copyright 2017, ufranco |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+ 
#property copyright "Copyright 2017, ufranco"
#property link      "https://www.mql5.com"
#include <EasyAndFastGUI\WndEvents.mqh>
#include <EasyAndFastGUI\TimeCounter.mqh>
#include <JAson.mqh>

#define BASE_URL "https://newsapi.org/v1/"
#define SRCE "sources?"
#define ATCLE "articles?source="
#define LATEST "&sortBy=latest"
#define API_KEY "&apiKey=484c84eb9765418fb58ea936908a47ac"
//+------------------------------------------------------------------+ 
//| Classe para criar o aplicativo                                    |
//+------------------------------------------------------------------+ 
class CNewsFeed : public CWndEvents
  

NewsFeedprogram.mqh incluirá a biblioteca de GUI e a biblioteca json. Como no script, os componentes da URL são armazenados em diretivas.

//+------------------------------------------------------------------+ 
//|                                              NewsFeedProgram.mqh |
//|                                          Copyright 2017, ufranco |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+ 
#property copyright "Copyright 2017, ufranco"
#property link      "https://www.mql5.com"
#include <EasyAndFastGUI\WndEvents.mqh>
#include <EasyAndFastGUI\TimeCounter.mqh>
#include <JAson.mqh>

#define BASE_URL "https://newsapi.org/v1/"
#define SRCE "sources?"
#define ATCLE "articles?source="
#define LATEST "&sortBy=latest"
#define API_KEY "&apiKey=484c84eb9765418fb58ea936908a47ac"
//+------------------------------------------------------------------+ 
//| Classe para criar o aplicativo                                    |
//+------------------------------------------------------------------+ 
class CNewsFeed : public CWndEvents
  {
private:
   //--- Contador de tempo
   CTimeCounter      m_counter; // para atualizar itens na barra de status
   //--- Janela principal
   CWindow           m_window;
   //--- Barra de status
   CStatusBar        m_status_bar;
   //--- Listas
   CListView         m_listview;
   //--- Caixa de edição
   CTextBox          m_text_box;
   //--- Objetos Json básicos 
   CJAVal            srce;
   CJAVal            js;
   //--- Ponteiros json para referências a elementos aninhados
   CJAVal           *articles;
   CJAVal           *articlesArrayElement;
   CJAVal           *sources;
   CJAVal           *sourcesArrayElement;

A classe principal de CNewsFeed é herdada de CWndEvents. Suas propriedades privadas são os componentes dos controles dos quais o aplicativo é composto, ou seja, a forma da janela principal à qual estão conectados a lista, o campo de texto e a barra de status. O contador de tempo está ativado para atualizar a barra de status. As propriedades privadas restantes do tipo CJAVal incluem o analisador Json, as propriedades srce e js. Elas serão contidas pelos objetos json retornados após chamar as fontes de notícias e algumas notícias de um feed específico. As outras propriedades são ponteiros que fazem referência aos objetos aninhados json.

O resto da classe é mostrado abaixo.

//+------------------------------------------------------------------+ 
//|                                              NewsFeedProgram.mqh |
//|                                          Copyright 2017, ufranco |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+ 
#property copyright "Copyright 2017, ufranco"
#property link      "https://www.mql5.com"
#include <EasyAndFastGUI\WndEvents.mqh>
#include <EasyAndFastGUI\TimeCounter.mqh>
#include <JAson.mqh>

#define BASE_URL "https://newsapi.org/v1/"
#define SRCE "sources?"
#define ATCLE "articles?source="
#define LATEST "&sortBy=latest"
#define API_KEY "&apiKey=484c84eb9765418fb58ea936908a47ac"
//+------------------------------------------------------------------+ 
//| Classe para criar o aplicativo                                    |
//+------------------------------------------------------------------+ 
class CNewsFeed : public CWndEvents
  {
private:
   //--- Contador de tempo
   CTimeCounter      m_counter; // para atualizar itens na barra de status
   //--- Janela principal
   CWindow           m_window;
   //--- Barra de status
   CStatusBar        m_status_bar;
   //--- Listas
   CListView         m_listview;
   //--- Caixa de edição
   CTextBox          m_text_box;
   //--- Objetos Json básicos 
   CJAVal            srce;
   CJAVal            js;
   //--- Ponteiros json para referências a elementos aninhados
   CJAVal           *articles;
   CJAVal           *articlesArrayElement;
   CJAVal           *sources;
   CJAVal           *sourcesArrayElement;
public:
                     CNewsFeed(void);
                    ~CNewsFeed(void);
   //--- Inicialização/desinicialização
   bool              OnInitEvent(void);
   void              OnDeinitEvent(const int reason);
   //--- Temporizador
   void              OnTimerEvent(void);
   //--- Manipulador de eventos do gráfico
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);

   //--- Cria uma interface gráfica do programa
   bool              CreateGUI(void);
private:
   //--- Janela principal
   bool              CreateWindow(const string text);
   //--- Barra de status
   bool              CreateStatusBar(const int x_gap,const int y_gap);
   //--- Listas
   bool              CreateListView(const int x_gap,const int y_gap);
   //--- Caixa de edição
   bool              CreateTextBox(const int x_gap,const int y_gap);
   //--- Preenchimento de objeto Json com lista de fontes
   bool              PrepareSources(void);
   //--- Preenchimento do objeto Json com artigos localizados no item selecionado da lista de fontes Json 
   bool              PrepareArticles(int listview_index);
   //--- Carga de dados
   string            DownLoad(string url,string file_name);
  };

Descrições detalhadas dos métodos relacionados à interface gráfica do usuário podem ser encontradas em artigos de Anatóli Kajárski.

Alteração da classe CTextBox

Vamos discutir aqui apenas uma parte da biblioteca, porque eu tive de mudá-la um pouco para obter a funcionalidade que precisamos. Foram feitas alterações no elemento de controle "caixa de texto". Durante os testes, notei que o método update() do campo de texto não respondia, como esperado, ao atualizar o campo de entrada com novo conteúdo. Este problema foi resolvido adicionando alguns métodos privados da mesma classe ao método de atualização, como mostrado abaixo.

A atualização do conteúdo no campo de texto também causou outros problemas, que ocorrem quando o aplicativo é minimizado e expandido. Neste caso, o culpado também foi o campo de entrada. Esses problemas são principalmente devidos ao redimensionamento automático.

//+------------------------------------------------------------------+ 
//| Updating the control                                             |
//+------------------------------------------------------------------+ 
void CTextBox::Update(const bool redraw=false)
  {
//--- Redesenho da tabela, se especificado
   if(redraw)
     {
      //--- Draw
      //ChangeTextBoxSize();
      WordWrap();
      Draw();
      CalculateTextBoxSize();
      ChangeScrollsSize();
      //--- Apply
      m_canvas.Update();
      m_textbox.Update();
      return;
     }
//--- Apply
   m_canvas.Update();
   m_textbox.Update();
  }


Primeiro, encontramos um problema com as barras de rolagem. A rolagem horizontal e vertical funciona parcial e incorretamente depois que o campo de texto é atualizado. Eu digo "parcialmente", porque quando um certo ponto é atingido, o conteúdo rolado desaparece de repente. Reparei que ocorrem problemas quando o novo conteúdo inserido no campo de entrada tem um tamanho maior (uma largura máxima de linha e o número de linhas no texto) do que o código fonte exibido durante a inicialização. Para corrigir esses problemas, liguei o modo de quebra de linha, para que a barra de rolagem horizontal não fosse mais necessária, e inicializei um campo de texto com muitas linhas em branco. O formato da lista e do campo de texto no plano vertical foram desativados.

Portanto, se você deseja executar o aplicativo e tiver uma biblioteca de GUI carregada, basta alterar nela o arquivo TextBox.mqh para o mesmo arquivo do aplicativo para este artigo.

Métodos para processamento dos objetos Json

//+------------------------------------------------------------------+ 
//| Método para consulta à Web e cache de dados                      |
//+------------------------------------------------------------------+      
string CNewsFeed::DownLoad(string url,string file_name="")
  {

// Se o terminal não estiver conectado, o Expert Advisor assume que não há conexão  
   if(!(bool)::TerminalInfoInteger(TERMINAL_CONNECTED))return(NULL);

   string cookie=NULL,headers,pStream;
   char post[],result[];
   int res,hFile;

   ::ResetLastError();
   int timeout=5000;
// Consulta à Web
   res=::WebRequest("GET",url,cookie,NULL,timeout,post,0,result,headers);

   if(res==-1)
     {
      ::Print("WebRequest failure");
      return(NULL);
     }

// Fluxo de dados carregado
   pStream=::CharArrayToString(result,0,-1,CP_UTF8);

   if(file_name!="")
     {

      hFile=::FileOpen(file_name,FILE_BIN|FILE_WRITE);

      if(hFile==INVALID_HANDLE)
        {
         return(pStream);
         ::Print("Invalid file handle - "+file_name+" - could not save data to file");
        }
      // Registro de dados carregados no arquivo
      ::FileWriteString(hFile,pStream);
      ::FileClose(hFile);
     }
//Print ("Carregamento bem-sucedido");
   return(pStream);
  }

Download() - é usado para chamada da API por meio da função webrequest e retorna uma resposta como um valor de string. Se o segundo parâmetro de string for especificado, a string de resposta será salva no arquivo. Se ocorrer um erro, será retornado NULL.

//+------------------------------------------------------------------+ 
//| downloads data to fill sources json object                       |
//+------------------------------------------------------------------+     
bool CNewsFeed::PrepareSources(void)
  {
   string sStream;
   int    iStringSize,hFile;

   string sources_filename="sources.txt";
// Carregamento de dados
   sStream=DownLoad(BASE_URL+SRCE,sources_filename);

   if(sStream==NULL)
     {
      if(!::FileIsExist(sources_filename))
        {
         ::Print("error : required file does not exit");
         return(false);
        }
      // Leitura e gravação o conteúdo do arquivo
      hFile=::FileOpen(sources_filename,FILE_TXT|FILE_READ|FILE_UNICODE);
      if(hFile==INVALID_HANDLE)
        {
         ::Print("error opening file "+sources_filename);
         return(false);
        }

      while(!::FileIsEnding(hFile))
        {
         iStringSize = ::FileReadInteger(hFile, INT_VALUE);
         sStream    += ::FileReadString(hFile, iStringSize);
        }

      ::FileClose(hFile);
     }
// Análise de dados json 
   if(!srce.Deserialize(sStream))
     {
      ::Print("Json deserialize error");
      return(false);
     }
// Adição do objeto json às fontes
   if(srce["status"].ToStr()=="ok")
     {
      sources=srce["sources"];
      return(true);
     }
   else
     {
      Print("error json api access denied");
      return(false);
     }
  }

PrepareSources() é chamado durante a inicialização do Expert Advisor uma vez, para fazer uma solicitação da API para obter fontes de notícias disponíveis. A resposta é armazenada num arquivo e analisada usando o método Deserialize do analisador Json. Portanto, a matriz de fontes de objetos json é atribuída a um ponteiro para as fontes. Se não houver conectividade e o arquivo das fontes .txt ainda não tiver sido criado, o Expert Advisor não será inicializado com sucesso.

//+------------------------------------------------------------------+ 
//| downloads data to fill articles json object                      |
//+------------------------------------------------------------------+      
bool CNewsFeed::PrepareArticles(int listview_index)
  {
   string sStream,id;
   int iStringSize,hFile;
// Verificação das fontes do objeto json 
   if(sources==NULL)
     {
      ::Print("Invalid pointer access");
      return(false);
     }

// Verificação do índice 
   if(listview_index>=::ArraySize(sources.m_e))
     {
      Print("invalid array index reference");
      return(false);
     }
// Criar uma referência de objeto json para elementos da matriz de fontes 
   sourcesArrayElement=sources[listview_index];
// recepção de nomes das fontes de notícias
   id=sourcesArrayElement["id"].ToStr();
// redefinir o objeto json sourcesArrayElement
   sourcesArrayElement=NULL;

// carregamento de dados para uma determinada fonte de notícias
   sStream=DownLoad(BASE_URL+ATCLE+id+API_KEY,id+".txt");
   if(sStream==NULL)
     {
      if(!::FileIsExist(id+".txt"))
        {
         ::Print("error : required file does not exit");
         return(false);
        }

      // leitura do arquivo de dados json 
      hFile=::FileOpen(id+".txt",FILE_TXT|FILE_READ|FILE_UNICODE);
      if(hFile==INVALID_HANDLE)
        {
         ::Print("error opening file "+id+".txt");
         return(false);
        }

      while(!::FileIsEnding(hFile))
        {
         iStringSize = ::FileReadInteger(hFile, INT_VALUE);
         sStream    += ::FileReadString(hFile, iStringSize);
        }

      ::FileClose(hFile);
     }

// análise do arquivo json 
   if(!js.Deserialize(sStream))
     {
      ::Print("Json deserialize error");
      return(false);
     }
// atribuição do objeto json usando os ponteiros para os artigos
   if(js["status"].ToStr()=="ok")
     {
      articles=js["articles"];
      return(true);
     }
   else
     {
      Print("error json api access denied");
      return(false);
     }
  }


PrepareArticles(): esta função é usada no método do manipulador de eventos para o gráfico principal. Com sua ajuda, solicitamos notícias à API a partir de uma determinada fonte, antes que ela possa ser exibida no campo de texto. O valor inteiro passado para a função representa o índice do item de lista selecionado. Esse índice é usado para identificar a fonte de notícias selecionada para que possa ser criada uma solicitação de URL válida, a partir da API. A resposta da API é tratada da mesma forma que é processada no método PrepareSources.

Observe também que os dois métodos descritos podem funcionar sem conexão, se e somente se a solicitação da API corresponder ao arquivo existente.

Atualização da caixa de texto

Agora examinaremos o método OnchartEvent. Se você clicar num item da lista, a caixa de texto rolará automaticamente para o início. Isso é necessário para evitar a exibição incorreta do novo conteúdo da janela. Os métodos do objeto de lista SelectedItemText() e SelectedItemIndex() são usados ​​para obter o nome e o índice do item de lista no qual clicamos. Em nosso caso, esse elemento define o nome da fonte de notícias selecionada e sua posição na matriz de fontes do objeto json. Com base nessas informações, você pode criar uma URL correta para fazer uma consulta de API de cabeçalhos de notícias usando o método PrepareArtilces(). Se isso for bem-sucedido, o campo de texto será atualizado com os cabeçalhos mais recentes. Caso contrário, o campo de texto exibe uma mensagem de erro.

//+------------------------------------------------------------------+ 
//| Chart event handler                                              |
//+------------------------------------------------------------------+ 
void CNewsFeed::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
// se houver um clique numa das fontes de notícias
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LIST_ITEM)
     {
      string nameofobject="";        // nome da fonte selecionada
      int selected,asize,g;          // selected - índice do item de lista selecionado; asize - tamanho da matriz de objetos json representando artigos; g - o índice da matriz
      bool ar=false;                 // ar - valor retornado pelo método prepareArticles
                                     // primeiro a rolagem automática do campo de texto para o início, somente se você precisar de rolagem vertical
      if(m_text_box.GetScrollVPointer().IsScroll())
         m_text_box.VerticalScrolling(0);
      //--- 
      nameofobject=m_listview.SelectedItemText();
      //--- 
      selected=m_listview.SelectedItemIndex();
      //---  
      ar=PrepareArticles(selected);
      //--- 
      asize=(articles!=NULL)? ::ArraySize(articles.m_e):0;
      //--- remoção do conteúdo atual do campo de texto
      m_text_box.ClearTextBox();
      //--- adição de um cabeçalho para o novo conteúdo do campo de texto
      m_text_box.AddText(0,nameofobject+" Top HeadLines:");
      //--- dependendo de se a execução do método PrepareArticles for bem-sucedida, o campo de texto é preenchido com novo conteúdo
      if(asize>0 && ar)// se o método PrepareArticles for executado com sucesso
        {
         string descrip,des;
         for(g=0; g<asize;g++)
           {
            // definir o objeto json para um item da matriz de objetos json de artigos 
            articlesArrayElement=articles[g];
            // obter valor
            des=articlesArrayElement["description"].ToStr();
            // definir texto adicional para exibição, dependendo de sua disponibilidade
            descrip=(des!="null" && des!="")? " -> "+des:".";
            // adicionar novo texto à caixa de texto 
            m_text_box.AddLine(string(g+1)+". "+articlesArrayElement["title"].ToStr()+descrip);
           }
        }
      else // se o método PrepareArticles não funcionar com sucesso
        {
         asize=1; // definir o valor asize = 1 
         for(g=0; g<asize;g++)
           {
            // exibe uma mensagem de erro na caixa de texto
            m_text_box.AddLine("Error retrieving data from feed.");
           }
        }
      //-- redesenhar o campo de texto     
      m_text_box.Update(true);
      //-- redefinir o valor do objeto com os artigos
      articles=NULL;
      //Print("clicked listview item is "+nameofobject);
      return;
     }
  }

Isso completa a definição da classe CNewsFeed e agora ela pode ser ligada ao Expert Advisor.

Expert Advisor NewsFeedProgram

Abaixo está uma demonstração do código, bem como algumas capturas de tela mostrando a aparência do aplicativo na inicialização. 

//+------------------------------------------------------------------+ 
//|                                               NewsFeedExpert.mq5 |
//|                                          Copyright 2017, ufranco |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+ 
#property copyright "Copyright 2017, ufranco"
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <NewsFeedProgram.mqh>
CNewsFeed program;
//+------------------------------------------------------------------+ 
//| Expert initialization function                                     |
//+------------------------------------------------------------------+ 
int OnInit()
  {

   if(!program.OnInitEvent())
     {
      ::Alert("Check your internet connection and set up the terminal \n"+
              "for Web requests");
      return(INIT_FAILED);
     }

//--- Instalamos o painel de negociação
   if(!program.CreateGUI())
     {
      ::Print("Failed to create graphical interface!");
      return(INIT_FAILED);
     }
//--- Inicialização bem-sucedida
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+ 
//| Função de desinicialização do Expert Advisor                                 |
//+------------------------------------------------------------------+ 
void OnDeinit(const int reason)
  {
//--- remoção do temporizador
   program.OnDeinitEvent(reason);

  }
//+------------------------------------------------------------------+ 
//| Função de ticks do Expert Advisor                                         |
//+------------------------------------------------------------------+ 
void OnTick()
  {
//--- 

  }
//+------------------------------------------------------------------+ 
//| Timer function                                                   |
//+------------------------------------------------------------------+ 
void OnTimer()
  {
//--- 
   program.OnTimerEvent();
  }
//+------------------------------------------------------------------+ 
//| Função ChartEvent                                              |
//+------------------------------------------------------------------+ 
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- 
   program.ChartEvent(id,lparam,dparam,sparam);
  }


Tipo de aplicativo na inicialização

Tela de notícias


Fim do artigo

No artigo, exploramos as possibilidades de criar um feed de notícias personalizado usando uma API da web de notícias. O Expert Advisor mostrado é muito simples e, provavelmente, pode ser estendido graças a um recurso de atualização automática para que o aplicativo possa exibir as últimas notícias conforme elas são exibidas. Espero que isso seja de alguma utilidade para alguém.

Atenção, para o Expert Advisor funcionar corretamente, você precisa baixar a biblioteca de GUI para o seu computador. Em seguida, você precisará substituir o arquivo TextBox.mqh pelo que está anexado a este artigo.

Programas e arquivos usados ​​no artigo

Nome 
Tipo
Descrição dos parâmetros
JAson.mqh
Arquivo de cabeçalho
Serialização e desserialização um objeto JSON no MQL
json.mqh
Arquivo de cabeçalho
classe para analisar Json
TextBox.mqh
Arquivo de cabeçalho
Classe modificada de campo de texto para exibir texto formatado num gráfico
NewsFeedProgram.mqh
Arquivo de cabeçalho
Classe principal para o Expert Advisor que exibe o feed de notícias
NewsFeedExpert.mq5
Arquivo do Expert Advisor
Implementação da classe para exibir o feed de notícias no Expert Advisor
NewsAPI_test.mq5
Script
Script para testar chamadas de API
newstest_JAson.mq5
Script
Script de teste para acessar os recursos da biblioteca JAson.mqh
newstest_json.mq5
Script
Script de teste para acessar os recursos da biblioteca json.mqh