English Русский 中文 Deutsch 日本語 Português
Creando un feed de noticias personalizado en MetaTrader 5

Creando un feed de noticias personalizado en MetaTrader 5

MetaTrader 5Ejemplos | 18 abril 2018, 09:39
2 370 0
Francis Dube
Francis Dube

Introducción

En el terminal MetaTrader 5 hay muchas funciones útiles que pueden ayudar al usuario con independencia de su estilo de trading, incluyendo la posibilidad de acceder a un feed de noticias operativas. Esto le da al tráder un contexto comercial cuya importancia es difícil de sobreestimar, porque puede influir en los mercados. La única limitación es la cantidad de noticias ofrecidas. Creemos que sin duda resultará útil para los tráders tener acceso a un feed de noticias más flexible, que brinde la oportunidad de elegir no solo el tipo de noticias, sino también su fuente.


Feed de noticias incorporado

Dependiendo del bróker con el que trabaje, el feed de noticias puede ser o bien muy útil, o bien al contrario, totalmente inútil. Después de todo, usted deberá confiar solo en cómo su broker implementa esta función de terminal. Algunos brókeres ofrecen acceso a noticias actuales de fuentes autorizadas, otros no. También puede considerar la creación de una aplicación que satisfaga esta demanda.

API de noticias

Puesto que todas las noticias útiles están disponibles gratuitamente en la web, lo único que necesitamos es tener acceso directo a las noticias que necesitamos. Una forma de lograrlo es usando herramientas RSS. Ya escribimos en su día un artículo sobre cómo escribir el código de un lector de RSS para MetaTrader 5. El mayor inconveniente de este método es que usted deberá introducir manualmente cada URL. Esto, unido a la configuración adicional requerida para resolver las solicitudes web en la terminal, podría resultar tedioso.

En nuestra opinión, la mejor solución es usar una web API. Después de una larga búsqueda, encontramos una API gratuita que da acceso a múltiples canales de noticias. Se llama NewsAPI y está disponible a través de solicitudes HTTP Get, que retornan metadatos de formato json. Esta interfaz permite recibir los titulares de las noticias publicadas en el canal seleccionado. En este ya hay muchas publicaciones de noticias para elegir, además, se ha anunciado que se añadirán más. Por otra parte, no están en contra de que los usuarios ofrezcan nuevas fuentes de noticias. Al parecer, el servicio no tiene suficiente diversidad lingüística: en él predominan principalmente fuentes de noticias de EE.UU. y Europa. No obstante, creemos que se trata de una opción aceptable. Otra ventaja a tener en cuenta es el acceso a todos las fuentes desde una dirección web.

Acceso a NewsAPI

Para trabajar con NewsAPI, el usuario deberá tener acceso autorizado a todos sus servicios. Para ello, entre en la página web oficial y clique en el botón Get API Key. Registre su e-mail, y recibirá su clave API, que necesitará para acceder a todas las funciones.

Página web de NewsAPI


Usando la API

El acceso a todas las características de la API está disponible mediante solicitud, usando dos URL básicos:

  1. https://newsapi.org/v1/sources? — una consulta realizada de esta forma devolverá una lista de todos los recursos de noticias disponibles en la API.
    Esta lista también incluye información sobre el identificador para cada recurso, que debe especificarse al solicitar los últimos titulares de noticias. La URL del recurso también se puede optimizar con ajustes opcionales que definen qué tipo de lista fuente se retornará.
  2. https://newsapi.org/v1/articles? - el URL del artículo retorna titulares de noticias y fragmentos de ciertas fuentes. El URL debe contener dos parámetros obligatorios. El primero es un identificador que indica de manera única la fuente requerida. El segundo es la clave API para la autorización.

Parámetros
Descripción de los parámetros
Posibles valores de los parámetros
Fuentes/Artículos
 Ejemplo
Categoría (opcional)
Categoría de noticias para las cuales le gustaría recibir las fuentes Negocios, entretenimiento, juegos, general, música, política, ciencia y naturaleza, deportes, tecnología ... Fuentes de información
https://newsapi.org/v1/sources?category=business


Idioma (opcional)
Idioma preferido para las fuentes de noticias
en, de, fr Fuentes de información
https://newsapi.org/v1/sources?language=en
País (opcional)
País en el que se encuentra la fuente
au, de, gb, in, it, us Fuentes de información
https://newsapi.org/v1/sources?country=us
Fuente (obligatoria)
Identificador de la fuente de noticias
Seleccione cualquiera de la lista retornada según la solicitud utilizando el URL fuente
Artículos
https://newsapi.org/v1/articles?source=cnbc&apiKey=API_KEY
Clave API (requerida)
Token de autorización de usuario

Artículos
ver el ejemplo de arriba
 Ordenar por La forma en que se ordenarán los titulares de las noticias: según su popularidad, por orden de aparición en la página, en orden cronológico.
 top, latest, popular  Artículos  https://newsapi.org/v1/articles?source=cnbc&sortBy=top&apiKey=API_KEY

El recuadro anterior muestra los parámetros principales que podrá usar en la configuración de la API junto con los dos URL. Para ver su lista completa, consulte la Documentación, disponible en la página web.

Script para pruebas API

Ahora que tenemos una idea general de cómo usar la API, es hora de ponerla a prueba. El script que vamos a crear sirve para familiarizarse con las respuestas que da la API tras recibir la solicitud. Para ello, el script necesitará poder realizar una solicitud web y guardar las respuestas en un archivo de texto. Al usar el script, deberíamos tener la posibilidad de probar cualquier solicitud API y observar la respuesta.

Código del 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;
  }


En primer lugar, existen directivas define que representan los diversos componentes de los URL que componen la solicitud API. Como primera variable de usuario, vemos sFilename. Introducimos en ella el nombre del archivo en el que se colocarán las respuestas de la API. El parámetro Mode es una enumeración que permite alternar entre los dos principales URL de la API.

El parámetro personalizado "parameters" se usa para introducir los parámetros de los URL adicionales (ya sean obligatorios u opcionales) para incluirlos en la solicitud de la API. En nuestro script solo habrá una función para crear la llamada a la URL API, dependiendo de los ajustes de los parámetros seleccionados. Si la función ha realizado con éxito la consulta, los metadatos serán guardados en el archivo.

Ahora podemos realizar varias pruebas y estudiar las respuestas. Primero, vamos a probar el inicio del script usando los parámetros predeterminados. A continuación, vamos a abrir el archivo: se podrá leer la respuesta de la API. Es importante considerar la estructura del objeto json: resultará útil cuando necesitamos extraer información específica de la matriz de datos.

{
   "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"]}
   ]
  }

Al abrir el archivo, podemos ver que la respuesta contiene una matriz de objetos json que representa todos los canales de noticias desde los que pueden solicitar los titulares de las mismas.

La siguiente prueba consiste en enviar una solicitud de API desde la fuente seleccionada. Vamos a abrir el archivo de nuevo y analizar la respuesta.

{
   "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"}
   ]
  }


En este ejemplo, la respuesta de la API incluye una matriz de objetos json en la que cada objeto es el título de una noticia.

Finalmente, vamos a aclarar qué respuesta obtenemos al enviar una solicitud API incorrecta. Estos resultados son retornados cuando se utiliza una clave API incorrecta:

{
  "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."  
}


Otro ejemplo de un error en la respuesta: aquí la solicitud se ha realizado con una identificación de origen incorrecta.

{
 "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."
}

Después de probar la API, vamos a analizar la rapidez con que se pueden extraer los datos con el analizador json.

Parseamos los metadatos de JSON

En la biblioteca de códigos MQL5.com hay dos bibliotecas json disponibles. La primera con la que vamos a trabajar es json.mqh. La compilación del script de prueba utilizando esta biblioteca ha mostrado una serie de errores y advertencias. Estos errores se guardan en los archivos de la biblioteca. En la página donde se publica la biblioteca, el autor afirma que el código recibe soporte activo en GitHub. Sin embargo, el autor no ha actualizado el archivo del código disponible en la biblioteca en mql5.com.

Ha resultado bastante sencillo corregir los errores de compilación. Solo ha sido necesario incluir el archivo hash directamente en el archivo json.mqh. Todas las advertencias han sido provocadas por una conversión de tipo implícita. El archivo corregido de la biblioteca se muestra a continuación:

// $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
*/

/*
   Un ejemplo de json_demo se muestra más abajo.

 Requiere que el archivo hash.mqh esté instalado en la computadora ( 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;
// Clase general para todos los 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; }

   // Redefinición en las subclases
   virtual string toString() 
     {
      return "";
     }

   // Algunos métodos auxiliares para la conversión a 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 retornan resultados hijo.
   // Permiten al programa obtener un valor sin interrumpir el funcionamiento del programa  
   // (a veces es deseable interrumpir el programa: es mejor que el asesor deje de funcionar que continuar trabajando con datos incorrectos)
   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;
     }
  };
// -----------------------------------------
....


El código para el script de prueba newstest_json se expone detalladamente a continuación. El script simplemente lee el archivo que contie los metadatos en formato json, guardados como resultado de la solicitud de la API (lo hemos hecho en la prueba anterior). Después de ejecutar el script, la lista con todas las fuentes de noticias disponibles contenidas en el archivo de datos se mostrará en el 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);
  }


Si utilizamos el archivo correcto, la biblioteca funcionará correctamente.

library test result


Ahora echaremos un vistazo a la segunda biblioteca para trabajar con json: JAson.mqh. El inicio de prueba de la biblioteca no ha mostrado ningún error, funciona perfectamente y al momento. Para probar esta biblioteca, se ha utilizado el 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;

// leyendo el contenido del archivo 
   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);
  }


Aquí tenemos los resultados de la prueba:

Resultados de la prueba de la biblioteca JAson.mqh

Si comparamos esta biblioteca con la que hemos analizado anteriormente (json.mqh), podemos ver que ambas admiten todos los tipos de datos json. La principal diferencia es que json.mqh implementa cada tipo de datos json como una clase y define varias clases. Al mismo tiempo, en JAson.mqh, los tipos de datos json son definidos por la propiedad pública de la clase, por lo que la biblioteca solo define una clase.

Continuemos. Ahora podemos escribir una aplicación para MetaTrader 5 que muestre noticias. La aplicación usará la biblioteca JAson.mqh. La implementaremos como un asesor que mostrará una lista de las fuentes de noticias. Al seleccionar un elemento de la lista, el siguiente campo de texto mostrará las últimas noticias disponibles de la fuente.

Clase CNewsFeed

En el anterior artículo, utilizamos la biblioteca estándar para construir una interfaz gráfica de usuario. En esta ocasión, queremos estudiar el uso de la biblioteca de interfaces gráficas desarrollada por Anatoly Kozharsky. Dado que la biblioteca parece encontrarse en el estadio de pruebas beta y el autor la actualiza regularmente (añade nuevas funciones), existen versiones extendidas. Hemos decido usar la versión adjunta al artículo Interfaces gráficas XI: Refactorización de código de la librería. Como nos parece, dispone de todo lo necesario, y al mismo tiempo no hay nada superfluo.

Nuestra aplicación será bastante sencilla: no necesitará una barra de menú, ni pestañas. Vamos a comenzar con el archivo include, que incluirá la clase principal para crear la aplicación.

//+------------------------------------------------------------------+ 
//|                                              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"
//+------------------------------------------------------------------+ 
//| Clase para crear la biblioteca                                    |
//+------------------------------------------------------------------+ 
class CNewsFeed : public CWndEvents
  

NewsFeedprogram.mqh incluirá la biblioteca GUI y la biblioteca json. Igual que sucede en el script, los componentes URL se guardan en las directivas.

//+------------------------------------------------------------------+ 
//|                                              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"
//+------------------------------------------------------------------+ 
//| Clase para crear la biblioteca                                    |
//+------------------------------------------------------------------+ 
class CNewsFeed : public CWndEvents
  {
private:
   //--- Contador de tiempo
   CTimeCounter      m_counter; // para actualizar los elementos en la barra de estado
   //--- Ventana principal
   CWindow           m_window;
   //--- Barra de estado
   CStatusBar        m_status_bar;
   //--- Listas
   CListView         m_listview;
   //--- Campo de edición
   CTextBox          m_text_box;
   //--- Objetos principales Json 
   CJAVal            srce;
   CJAVal            js;
   //--- Punteros json para los enlaces a los elementos anidados
   CJAVal           *articles;
   CJAVal           *articlesArrayElement;
   CJAVal           *sources;
   CJAVal           *sourcesArrayElement;

La clase principal de CNewsFeed se hereda de CWndEvents. Sus propiedades privadas son los componentes de los elementos de control de los que consta la aplicación, es decir, la forma de la ventana principal a la que se fija la lista, el campo de texto y la barra de estado. El contador de tiempo está activado para actualizar la barra de estado. El resto de propiedades privadas del tipo CJAVal incluyen el parser Json, las propiedades srce y js. Las contendrán los objetos json retornados después de llamar las fuentes de noticias y ciertas noticias de una barra específica, respectivamente. Las demás propiedades son punteros que hacen referencia a los objetos anidados de json.

El resto de la clase se muestra a continuación.

//+------------------------------------------------------------------+ 
//|                                              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"
//+------------------------------------------------------------------+ 
//| Clase para crear la biblioteca                                    |
//+------------------------------------------------------------------+ 
class CNewsFeed : public CWndEvents
  {
private:
   // --- Contadores de tiempo
   CTimeCounter      m_counter; // para actualizar los elementos en la barra de estado
   // --- Ventana principal
   CWindow           m_window;
   //--- Barra de estado
   CStatusBar        m_status_bar;
   //--- Listas
   CListView         m_listview;
   //--- Campo de edición
   CTextBox          m_text_box;
   //--- Objetos principales Json 
   CJAVal            srce;
   CJAVal            js;
   //--- Punteros json para los enlaces a los elementos anidados
   CJAVal           *articles;
   CJAVal           *articlesArrayElement;
   CJAVal           *sources;
   CJAVal           *sourcesArrayElement;
public:
                     CNewsFeed(void);
                    ~CNewsFeed(void);
   //--- Inicialización/desinicialización
   bool              OnInitEvent(void);
   void              OnDeinitEvent(const int reason);
   //--- Temporizador
   void              OnTimerEvent(void);
   // --- Manejador de eventos del gráfico
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);

   // --- Crea una interfaz gráfica del programa
   bool              CreateGUI(void);
private:
   // --- Ventana principal
   bool              CreateWindow(const string text);
   //--- Barra de estado
   bool              CreateStatusBar(const int x_gap,const int y_gap);
   //--- Listas
   bool              CreateListView(const int x_gap,const int y_gap);
   //--- Campo de edición
   bool              CreateTextBox(const int x_gap,const int y_gap);
   //--- Rellenar el objeto Json con la lista de fuentes
   bool              PrepareSources(void);
   //--- Rellenar el objeto Json (por artículos), ubicado en el elemento elegido de la lista de fuentes Json 
   bool              PrepareArticles(int listview_index);
   // --- Cargando datos
   string            DownLoad(string url,string file_name);
  };

Podrá encontrar descripciones detalladas de los métodos relacionados con la interfaz gráfica de usuario en los artículos de Anatoly Kazharsky.

Modificando la clase CTextBox

Vamos a hablar aquí solo de una parte de la biblioteca, porque la hemos modificado ligeramente para obtener la funcionalidad que necesitamos. Se han realizado cambios en el elemento de control "cuadro de texto". Durante las pruebas, hemos notado que el método update() del campo de texto no responde, como se esperaba, cuando el campo de entrada se actualiza con nuevo contenido. Este problema lo hemos resuelto añadiendo algunos métodos privados de la misma clase al método de actualización, como se muestra más abajo.

La actualización del contenido en el campo de texto también ha causado otros problemas. Surgen cuando la aplicación se minimiza y se expande. El culpable aquí también ha resultado el campo de entrada. Estos problemas ocurren principalmente debido al cambio automático de tamaño.

//+------------------------------------------------------------------+ 
//| Updating the control                                             |
//+------------------------------------------------------------------+ 
void CTextBox::Update(const bool redraw=false)
  {
// --- Redibuja la tabla, si se indica
   if(redraw)
     {
      //--- Draw
      //ChangeTextBoxSize();
      WordWrap();
      Draw();
      CalculateTextBoxSize();
      ChangeScrollsSize();
      //--- Apply
      m_canvas.Update();
      m_textbox.Update();
      return;
     }
//--- Apply
   m_canvas.Update();
   m_textbox.Update();
  }


Primero, nos encontramos un problema con las barras de desplazamiento. El desplazamiento horizontal y vertical funciona de forma parcialmente incorrecta después de actualizar el campo de texto. Y decimos "parcialmente", porque al llegar a cierto punto, el contenido desplazado desaparece de repente. Hemos notado que los problemas suceden cuando el nuevo contenido introducido en el campo de entrada tiene un tamaño superior (es decir, el ancho máximo de la línea y el número de líneas en el texto) al texto fuente que se muestra durante la inicialización. Para resolver estos problemas, hemos activado el modo de traslado de palabras, de modo que ya no se necesitaba la barra de desplazamiento horizontal, y hemos inicializado un campo de texto con muchas líneas en blanco. El formato de la lista y el campo de texto en el plano vertical han sido desactivados.

Por este motivo, si usted quiere ejecutar la aplicación y ha cargado una biblioteca Gui, solo tendrá que cambiar el archivo TextBox.mqh al mismo archivo desde los adjuntos a este artículo.

Métodos para procesar los objetos Json

//+------------------------------------------------------------------+ 
//| Método para las solicitudes web y los datos de almacenamiento en la caché                      |
//+------------------------------------------------------------------+      
string CNewsFeed::DownLoad(string url,string file_name="")
  {

// Si el terminal no está conectado, el asesor entiende que no hay conexión  
   if(!(bool)::TerminalInfoInteger(TERMINAL_CONNECTED))return(NULL);

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

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

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

// Flujo de datos cargados
   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");
        }
      // Anotando los datos descargados en un archivo
      ::FileWriteString(hFile,pStream);
      ::FileClose(hFile);
     }
//Print ("La carga ha tenido éxito");
   return(pStream);
  }

Download(): se utiliza para llamar a la API a través de la función webrequest y retorna una respuesta como valor de línea. Si se indica el segundo parámetro de la línea, la línea de respuesta se guardará en el archivo. Si ocurre un error, se retorna el valor NULL.

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

   string sources_filename="sources.txt";
// Cargando datos
   sStream=DownLoad(BASE_URL+SRCE,sources_filename);

   if(sStream==NULL)
     {
      if(!::FileIsExist(sources_filename))
        {
         ::Print("error : required file does not exit");
         return(false);
        }
      // Leyendo el contenido del archivo
      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);
     }
// Parseando los datos json 
   if(!srce.Deserialize(sStream))
     {
      ::Print("Json deserialize error");
      return(false);
     }
// Añadiendo el objeto json a las fuentes
   if(srce["status"].ToStr()=="ok")
     {
      sources=srce["sources"];
      return(true);
     }
   else
     {
      Print("error json api access denied");
      return(false);
     }
  }

PrepareSources() se llama una vez durante la inicialización del asesor para realizar una solicitud de API y obtener las fuentes de noticias disponibles. La respuesta se guarda en un archivo y se parsea usando el método Deserialize del parser Json. De esta forma, la matriz de fuentes de los objetos json se asigna al puntero a las fuentes. Si no existe posibilidad de conectarse y el archivo fuente .txt aún no ha sido creado, el asesor no se inicializará con éxito.

//+------------------------------------------------------------------+ 
//| downloads data to fill articles json object                      |
//+------------------------------------------------------------------+      
bool CNewsFeed::PrepareArticles(int listview_index)
  {
   string sStream,id;
   int iStringSize,hFile;
// Comprobando las fuentes del objeto json 
   if(sources==NULL)
     {
      ::Print("Invalid pointer access");
      return(false);
     }

// Comprobando el índice 
   if(listview_index>=::ArraySize(sources.m_e))
     {
      Print("invalid array index reference");
      return(false);
     }
// Creando el enlace del objeto json a los elementos de la matriz de fuentes 
   sourcesArrayElement=sources[listview_index];
// obteniendo los nombres de las fuentes de noticias
   id=sourcesArrayElement["id"].ToStr();
// restableciendo el objeto json sourcesArrayElement
   sourcesArrayElement=NULL;

// cargando los datos para una fuente de noticias determinada
   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);
        }

      // leyendo el archivo con datos 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);
     }

// parseando el archivo json 
   if(!js.Deserialize(sStream))
     {
      ::Print("Json deserialize error");
      return(false);
     }
// asigna un objeto json a los punteros a los artículos
   if(js["status"].ToStr()=="ok")
     {
      articles=js["articles"];
      return(true);
     }
   else
     {
      Print("error json api access denied");
      return(false);
     }
  }


PrepareArticles (): esta función se utiliza en el método del controlador de eventos del gráfico principal. Con su ayuda, realizamos una solicitud de API para las noticias de una fuente en particular, antes de que se muestre en el campo de texto. El valor entero transmitido a la función representa el índice del elemento de la lista seleccionada. Este índice se utiliza para identificar la fuente de noticias seleccionada de manera que se pueda crear una solicitud de URL API válida. La respuesta de la API se procesa de la misma forma que se procesa en el método PrepareSources.

También debe tener en cuenta que los dos métodos descritos pueden funcionar sin conexión solo si la solicitud API coincide con el archivo existente.

Actualizando la ventana de texto

Ahora analizaremos el método OnchartEvent. Si clicamos en un elemento de la lista, la ventana de texto se desplazará automáticamente al principio. Esto es necesario para evitar que los nuevos contenidos de la ventana se visualicen de forma incorrecta. Los métodos de objeto de la lista SelectedItemText () y SelectedItemIndex () se utilizan para obtener el nombre y el índice del elemento de la lista en la que hemos clicado. En este caso, ese elemento define el nombre de la fuente de noticias seleccionada y su posición en la matriz fuente del objeto json. Partiendo de esta información, podemos compilar el URL correcto para realizar una solicitud API de titulares de noticias utilizando el método PrepareArtilces (). De tener éxito, el campo de texto se actualizará con los últimos titulares. De lo contrario, el campo de texto mostrará un mensaje de error.

//+------------------------------------------------------------------+ 
//| Chart event handler                                              |
//+------------------------------------------------------------------+ 
void CNewsFeed::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
// si se ha clicado en una de las fuentes de noticias
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LIST_ITEM)
     {
      string nameofobject="";        // nombre de la fuente elegida
      int selected,asize,g;          // selected - índice del elemento elegido de la lista, asize - tamaño de la matriz de objetos json presentados en el artículo, g - índice de la matriz
      bool ar=false;                 // ar - valor retornado por el método prepareArticles
                                     // primer desplazamiento automático del campo de texto hacia el principio; solo si necesita el desplazamiento 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;
      // --- eliminar el contenido actual del campo de texto
      m_text_box.ClearTextBox();
      // --- añadir un titular para los nuevos contenidos del campo de texto
      m_text_box.AddText(0,nameofobject+" Top HeadLines:");
      //--- dependiendo del éxito de la ejecución del método PrepareArticles, el campo de texto estará lleno de nuevo contenido
      if(asize>0 && ar)// si el método PrepareArticles se ha ejecutado con éxito
        {
         string descrip,des;
         for(g=0; g<asize;g++)
           {
            // establecer el objeto json para un elemento de la matriz de artículos de objetos json 
            articlesArrayElement=articles[g];
            // obtener valor
            des=articlesArrayElement["description"].ToStr();
            // establecer texto adicional para la muestra, dependiendo de su disponibilidad
            descrip=(des!="null" && des!="")? " -> "+des:".";
            // añadir texto nuevo al campo de texto 
            m_text_box.AddLine(string(g+1)+". "+articlesArrayElement["title"].ToStr()+descrip);
           }
        }
      else // si el método PrepareArticles no ha funcionado de forma correcta
        {
         asize=1; // establece el valor asize = 1 
         for(g=0; g<asize;g++)
           {
            // representar el mensaje de error en el campo de texto
            m_text_box.AddLine("Error retrieving data from feed.");
           }
        }
      //-- redibujar el campo de texto     
      m_text_box.Update(true);
      //-- restablecer el valor del objeto con los artículos
      articles=NULL;
      //Print("clicked listview item is "+nameofobject);
      return;
     }
  }

Con ello finaliza la definición de la clase CNewsFeed, y ahora puede ser incluido en el asesor.

Asesor NewsFeedProgram

A continuación se muestra el código, así como algunas capturas de pantalla que representan el aspecto de la aplicación al inicio. 

//+------------------------------------------------------------------+ 
//|                                               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 el panel comercial
   if(!program.CreateGUI())
     {
      ::Print("Failed to create graphical interface!");
      return(INIT_FAILED);
     }
// --- La inicialización ha tenido éxito
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+ 
//| Función de desinicialización del asesor                                 |
//+------------------------------------------------------------------+ 
void OnDeinit(const int reason)
  {
//--- eliminamos el temporizador
   program.OnDeinitEvent(reason);

  }
//+------------------------------------------------------------------+ 
//| Función de tick del experto                                         |
//+------------------------------------------------------------------+ 
void OnTick()
  {
//--- 

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


Aspecto de la aplicación al iniciarse

Pantalla de noticias


Conclusión

En el artículo hemos analizado las posibilidades de crear un feed de noticias personalizado con la ayuda de la web API de noticias. Hemos mostrado un asesor muy simple, que probablemente se pueda ampliar activando la función de actualización automática, para que la aplicación sea capaz de mostrar las últimas noticias tal como aparecen. Espero que la información expuesta sea de utilidad a los lectores.

Preste atención: para que el asesor funcione correctamente, deberá descargar en su computadora la biblioteca GUI. Luego deberá reemplazar en ella el archivo TextBox.mqh por el archivo adjunto a este artículo.

Programas y archivos utilizados en el artículo

Nombre 
Tipo
Descripción de los parámetros
JAson.mqh
Archivo de encabezado
Serialización y deserialización de un objeto JSON en MQL
json.mqh
Archivo de encabezado
clase para parsear Json
TextBox.mqh
Archivo de encabezado
Clase modificada del campo de texto para mostrar el texto formateado en un gráfico
NewsFeedProgram.mqh
Archivo de encabezado
Clase principal para el asesor que muestra la barra de noticias
NewsFeedExpert.mq5
Archivo del experto
Implementación de la clase para mostrar la barra de noticias en el asesor
NewsAPI_test.mq5
Script
Script para probar las llamadas API
newstest_JAson.mq5
Script
Script de prueba para acceder a las posibilidades de la biblioteca JAson.mqh
newstest_json.mq5
Script
Script de prueba para acceder a las posibilidades de la biblioteca json.mqh



Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/4149

Archivos adjuntos |
NewsFeedExpert.mq5 (2.48 KB)
NewsAPI_test.mq5 (2.52 KB)
NewsFeedProgram.mqh (35.64 KB)
TextBox.mqh (282.87 KB)
newstest_JAson.mq5 (2.03 KB)
newstest_json.mq5 (2.18 KB)
Sincronización de varios gráficos del mismo símbolo en timeframes diferentes Sincronización de varios gráficos del mismo símbolo en timeframes diferentes
Para tomar decisiones sobre la realización de las transacciones, a menudo es necesario analizar simultáneamente los gráficos en el proceso del trading. Además, los gráficos disponen de los objetos del análisis gráfico. Es bastante incómodo colocar los mismos objetos en todos los gráficos. En este artículo, yo propongo automatizar la clonación de los objetos en los gráficos.
Desarrollando los Asesores Expertos multimódulo Desarrollando los Asesores Expertos multimódulo
El lenguaje de programación MQL permite implementar el concepto del diseño modular de las estrategias comerciales. En este artículo, se muestra el ejemplo del desarrollo del Asesor Experto multimódulo compuesto de los módulos de archivos compilados separadamente.
Trabajando con los resultados de la optimización mediante la interfaz gráfica Trabajando con los resultados de la optimización mediante la interfaz gráfica
Continuamos desarrollar el tema del procesamiento y el análisis de los resultados de la optimización. Ahora nuestra tarea consiste en seleccionar 100 mejores resultados de la optimización y mostrarlos en la tabla de la interfaz gráfica. Hagamos que el usuario obtenga el gráfico del balance de multisímbolos y de la reducción (drawdown) en gráficos separados seleccionando una fila de la tabla de los resultados de la optimización.
Gráfico del balance de multisímbolos en MetaTrader 5 Gráfico del balance de multisímbolos en MetaTrader 5
En este artículo, se muestra el ejemplo de la aplicación MQL con la interfaz gráfica en la que se muestran los gráficos del balance de multisímbolos y reducción del depósito según los resultados de la última prueba.