Creando un feed de noticias personalizado en MetaTrader 5
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.
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.
Usando la API
El acceso a todas las características de la API está disponible mediante solicitud, usando dos URL básicos:
- 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á.
- 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.
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:
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); }
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
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso