Erstellen eines eigenen Newsfeeds für MetaTrader 5

Francis Dube | 22 März, 2018


Einführung

MetaTrader 5 bietet viele nützliche Funktionen, die ein Händler unabhängig von seinem Handelsstil benötigen würde, einschließlich eines möglichen Zugriffs auf einen Live-Newsfeed. Es bietet Händlern einen unschätzbaren Kontext, der sich auf die Märkte auswirken kann. Die einzige Einschränkung ist der Umfang der angebotenen Nachrichten. Ich glaube, Händler könnten von einem flexibleren Newsfeed profitieren, der es einem ermöglicht, nicht nur die Art der Nachrichten, sondern auch deren Quelle zu wählen.


Eingebauter Newsfeed

Je nachdem, mit welchem Broker Sie handeln, kann der Live-Newsfeed sehr nützlich oder sogar völlig überflüssig sein. Sie müssen sich darauf verlassen können, wie sie vom Makler im Terminal implementiert wurde. Einige Broker bieten Zugang zu relevanten Newsfeeds von seriösen Nachrichtenagenturen. Andere jedoch nicht. Dabei bietet sich die Gelegenheit, die Möglichkeit zu erkunden, eine Anwendung zu entwickeln, die diesen Anforderungen gerecht wird.

Die Nachrichten-API

Da alle Nachrichten, die man benötigen könnte, im Internet frei verfügbar sind, benötigen wir nur einen bequemen Weg, um direkt auf die gewünschten Nachrichten zuzugreifen. Eine Möglichkeit, dies zu erreichen, ist der Einsatz von RSS-Hilfsmitteln. Ich habe einen Artikel darüber geschrieben, wie man einen RSS-Reader für MetaTrader 5 codiert. Der größte Nachteil ist, dass jede URL manuell eingegeben werden muss, was in Verbindung mit der zusätzlichen Einrichtung, die für die Aktivierung von Web-Anfragen im Terminal erforderlich ist, mühsam werden kann.

Ich glaube, die beste Lösung ist, eine Web-API zu verwenden. Nach einer umfangreichen Suche stolperte ich über eine kostenlose API, die den Zugriff auf mehrere Nachrichtenagenturen ermöglicht. Sie heißt einfach NewsAPI, wird über HTTP Get-Requests aufgerufen und gibt Json-Metadaten zurück. Sie ermöglicht es, Schlagzeilen der Nachrichten abzurufen, die von einer ausgewählten Nachrichtenagentur veröffentlicht wurden. Es gibt eine Vielzahl von Nachrichtenagenturen, aus denen man wählen kann und es wird behauptet, dass weitere hinzukommen werden. Die Benutzer werden auch ermutigt, neue Quellen vorzuschlagen. Der Dienst scheint nur mangelnde Sprachvielfalt zu haben und wird vor allem von in den USA und Europa ansässigen Nachrichtenagenturen dominiert. Ich denke, das ist trotzdem akzeptabel. Ein weiteres Plus ist die Tatsache, dass all dies von einer einzigen Webadresse aus zugänglich ist.

NewsAPI-Zugriff

Um mit der NewsAPI arbeiten zu können, müssen Sie berechtigt sein, auf den vollen Service zuzugreifen. Besuchen Sie dazu die offizielle Webseite und klicken Sie auf Get API Key. Registrieren Sie Ihre E-Mail-Adresse und Sie erhalten einen API-Schlüssel, den Sie für den Zugriff auf alle Funktionen benötigen.

NewsAPI-Website


Verwendung der API

Der Zugriff auf das gesamte API erfolgt über zwei URLs:

  1. https://newsapi.org/v1/sources? Eine Anfrage in dieser Form liefert eine Liste aller Nachrichtenquellen, die über die API verfügbar sind.
    Diese Liste enthält auch Informationen über Identität jeder Quelle, die bei der Abfrage der neuesten Nachrichtenüberschriften angegeben werden sollten.
  2. https://newsapi.org/v1/articles? die Artikel-URL liefert Schlagzeilen und Zitate aus einer bestimmten Quelle. Die URL sollte zwei obligatorische Parameter enthalten. Der erste ist ein Identifikator, der die gewünschte Quelle eindeutig identifiziert. Der zweite ist der API-Schlüssel für die Autorisierung.

Parameter
Beschreibung
Mögliche Parameterwerte
Quelle/Artikel
 Beispiel
Kategorie (optional)
Die Kategorie, die Sie gerne erhalten möchten Wirtschaft, Unterhaltung, Spiele, Allgemeines, Musik, Politik, Wissenschaft und Natur, Sport, Technik. Quellen
https://newsapi.org/v1/sources?category=business


Sprache (optional)
Sprache der Nachrichtenquellen.
en, de, fr Quellen
https://newsapi.org/v1/sources?language=en
Land (optional)
Land, in dem sich die Quelle befindet
au, de, gb, in, it, us Quellen
https://newsapi.org/v1/sources?country=us
Quelle (obligatorisch)
Identität der Nachrichtenquelle
Wählen Sie ein beliebiges aus der Liste, die von einer Anfrage unter Verwendung der Quell-URL zurückgegeben wird.
Artikel
https://newsapi.org/v1/articles?source=cnbc&apiKey=API_KEY
Schlüssel des Api (obligatorisch)
Zeichenfolge der Benutzerauthentifizierung

Artikel
siehe Beispiel von oben
 sortiert nach Art und Weise, in der die Schlagzeilen sortiert werden, d.h. Beliebtheit, nach der Reihenfolge, in der sie auf der Website erscheinen, und nach der chronologischen Reihenfolge.
 top, latest, popular  Artikel  https://newsapi.org/v1/articles?source=cnbc&sortBy=top&apiKey=API_KEY

Die Tabelle oben zeigt die wichtigsten Parameter, die zusammen mit den beiden URLs der API verwendet werden können. Eine vollständige Liste finden Sie unter Dokumentation auf der Website.

Ein Skript zum Testen der API

Nun, da wir eine allgemeine Vorstellung davon haben, wie man die API verwendet, ist es an der Zeit, sie anzuwenden. Das Skript, das wir erstellen werden, dient dazu, sich mit den Antworten vertraut zu machen, die durch API-Anfragen gegeben werden. Um dies zu erreichen, muss das Skript in der Lage sein, Web-Anfragen zu stellen und auch die Antworten in einer Textdatei zu speichern. Mit Hilfe des Skripts sollten wir in der Lage sein, jede API-Anfrage zu testen und die Antwort zu beobachten.

Hier ist der Code des Skripts 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,
   Artikel
  };

input string sFilename="sorce.txt";
input mode Mode=sources;
input string parameters="";
int timeout=5000;
//+------------------------------------------------------------------+
//| Script Programm Start Funktion                                   |
//+------------------------------------------------------------------+
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;
  }

Zunächst gibt es die Definitionsdirektiven, die die verschiedenen Komponenten einer URL repräsentieren, die eine API-Anforderung darstellen. Die erste der Benutzereingaben ist sFilename, wo man einen Dateinamen eingeben würde, der zum Zwischenspeichern der API-Antworten verwendet wird. Der Mode-Parameter ist eine Aufzählung, die das Umschalten zwischen den beiden Haupt-URLs der API ermöglicht.

Der Benutzereingabeparameter named parameters dient zur Eingabe zusätzlicher obligatorischer oder optionaler URL-Parameter, die in einen API-Request aufgenommen werden sollen. Unser Skript hat nur eine Funktion, die den URL-API-Aufruf abhängig von den gewählten Parametereinstellungen aufbaut. Wenn die Webrequest-Funktion erfolgreich ist, werden die Metadaten in einer Datei gespeichert.

Wir können nun einige Tests durchführen und die Antworten studieren, wobei der erste Test eine Ausführung des Skripts mit den Standardparametern sein wird. Wenn wir die Datei öffnen, kann die API-Antwort gelesen werden. Es ist wichtig, die Struktur des Json-Objekts zu beachten, da es nützlich sein wird, wenn wir spezifische Informationen aus den Daten extrahieren müssen.

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

Beim Öffnen der Datei können wir sehen, dass die Antwort ein Array von Json-Objekten enthält, die alle Nachrichtenquellen repräsentieren, von denen man Schlagzeilen anfordern kann.

Als nächstes wird ein Test eines API-Aufrufs durchgeführt, der Nachrichten von einer ausgewählten Quelle anfordert. Auch hier beobachten wir die Antwort, indem wir die Datei öffnen.

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

In diesem Fall enthält die API-Antwort ein Array von Json-Objekten, wobei jedes eine Nachrichtenüberschrift ist.

Schließlich wollen wir untersuchen, welche Antwort wir erhalten, wenn ein falscher API-Aufruf gemacht wird. Hier sind die Ergebnisse, wenn ein ungültiger API-Schlüssel verwendet wird.

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

Ein weiteres Beispiel für eine fehlerhafte Antwort, diesmal wurde eine Anfrage mit falscher Quell-ID gestellt.

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

Nachdem wir mit der API herumgespielt haben, können wir nun einen Blick darauf werfen, wie man mit einem Json-Parser schnell auf diese Daten zugreifen kann.

JSON-Metadaten analysieren

In der MQL5.com Codebasis stehen zwei Json-Bibliotheken zur Verfügung. Der erste Versuch ist json.mqh. Die Erstellung eines Testskripts unter Verwendung dieser Bibliothek ergab eine Reihe von Fehlern und Warnungen. Diese Fehler wurden in der Bibliotheksdatei selbst gefunden. Bei einem Besuch der Codebase-Webseite der Bibliothek legt der Autor fest, dass der Code aktiv auf github gepflegt wird. Der Autor hat die über die Codebasis verfügbare Code-Datei nicht aktualisiert.

Die Behebung der Kompilierungsfehler war einfach genug, alles, was nötig war, ist die Einbindung der Hash-Datei direkt in die json.mqh-Datei. Die Warnungen wurden alle durch implizites Type Casting verursacht. Die korrigierte json.mqh Datei ist unten aufgeführt.

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

/*
   See json_demo for examples.

 This requires the hash.mqh ( 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;
// Generische Klasse für alle JSON-Typen (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; }

   // Typ-Methoden
   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; }

   // Überschreiben der Kind-Klasse
   virtual string toString() 
     {
      return "";
     }

   // Einige praktische Abfragen zur Umwandlung von Subtypen.
   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();
     }

   // "Static" Abfragen von Arrays und Objekten, die untergeordnete Ergebnisse zurückgeben.
   // Sie erlauben dem Programm, den Wert zu erhalten, ohne die Operation des Programms zu unterbrechen 
   // (manchmal ist die Aussetzung des Programms wünschenswert - sei es besser, dass der Expert Advisor aufhört zu arbeiten, als mit falschen Daten weiter zu arbeiten)
   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;
     }
  };
// -----------------------------------------
....

Der Code des Testskripts newstest_json ist unten aufgeführt. Das Skript liest einfach eine Datei, die Json-Metadaten enthält, die von einem API-Aufruf aus früheren Tests gespeichert wurden. Wenn das Skript ausgeführt wird, werden alle in den Daten enthaltenen Nachrichten an das Terminal ausgegeben.

//+------------------------------------------------------------------+
//|                                                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 Programm Start Funktion                                   |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   Test();
  }
//+------------------------------------------------------------------+
//| Test                                                             |
//+------------------------------------------------------------------+
bool Test()
  {

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

   int hFile,iStringSize;

// Dateiinhalt lesen 
   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);
  }

Mit der korrigierten Datei funktioniert die Bibliothek ohne Probleme.

Testergebnisse der Bibliothek


Nun können wir uns die zweite Json-Bibliothek JAson.mqh ansehen. Ein Test mit dieser Bibliothek hat keine Fehler ergeben. Es hat gleich beim ersten Mal perfekt funktioniert. Zum Testen dieser Bibliothek wurde das Skript newstest_JAson verwendet.

//+------------------------------------------------------------------+
//|                                               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 Programm Start Funktion                                   |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   Test();
  }
//+------------------------------------------------------------------+
//| Test                                                             |
//+------------------------------------------------------------------+
bool Test()
  {

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

   int hFile,iStringSize;

// Dateiinhalt lesen 
   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);
  }

Und hier sind die Testergebnisse.

JAson.mqh Testergebnisse der Bibliothek

Vergleicht man diese Bibliothek mit der ersten, json.mqh, haben beide Unterstützung für alle json-Datentypen. Der Hauptunterschied besteht darin, dass json.mqh jeden Json-Datentyp als Klasse implementiert und mehrere Klassen definiert. Während in JAson.mqh die json-Datentypen durch eine öffentlich zugängliche Klasseneigenschaft definiert sind, daher definiert die Bibliothek eine einzige Klasse.

Nun können wir eine Anwendung für MetaTrader 5 programmieren, die die Nachrichten anzeigt. Die Anwendung verwendet die Bibliothek JAson.mqh. Die Anwendung wird als Expert Advisor implementiert, der eine Liste von Nachrichtenquellen anzeigt. Wenn ein Listenelement ausgewählt ist, zeigt das nächste Textfeld die neuesten Nachrichten aus der Quelle an.

Die Klasse CNewsFeed

In einem früheren Artikel habe ich die Standardbibliothek verwendet, um eine grafische Benutzeroberfläche zu erstellen. Dieses Mal möchte ich auf die Bibliothek von Anatoli Kazharski zurückgreifen. Da sich die Bibliothek scheinbar in ständiger Beta-Phase befindet und der Autor regelmäßige Updates und neue Funktionen bereitstellt, gibt es eine Reihe von Versionen der umfangreichen Bibliothek. Ich habe mich für die im Artikel Graphical Interfaces XI:Refactoring the library code enthaltene Version entschieden. Ich glaube, sie bietet alles, was wir brauchen und nichts, was wir nicht brauchen.

Unsere Anwendung wird ziemlich einfach sein, es werden keine Menüs oder Registerkarten benötigt. Beginnen wir mit der Include-Datei, die die Hauptklasse für die Erstellung der Anwendung enthält.

//+------------------------------------------------------------------+
//|                                              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"
//+------------------------------------------------------------------+
//| Klasse zum Erstellen einer Anwendung                             |
//+------------------------------------------------------------------+
class CNewsFeed : public CWndEvents
  

NewsFeedprogram.mqh wird sowohl die GUI-Bibliothek als auch die Json-Bibliothek enthalten. Wie im Skript speichern die Direktiven Komponenten einer URL.

//+------------------------------------------------------------------+
//|                                              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"
//+------------------------------------------------------------------+
//| Klasse zum Erstellen einer Anwendung                             |
//+------------------------------------------------------------------+
class CNewsFeed : public CWndEvents
  {
private:
   //--- Zeitzähler
   CTimeCounter      m_counter; // Aktualisieren der Elemente und der Statuszeile
   //--- Hauptfenster
   CWindow           m_window;
   //--- Statuszeile
   CStatusBar        m_status_bar;
   //--- Listenansicht
   CListView         m_listview;
   //--- Bearbeitet
   CTextBox          m_text_box;
   //--- Haupt-Json-Objekt 
   CJAVal            srce;
   CJAVal            js;
   //--- Json-Zeiger auf verschachtelte Elemente
   CJAVal           *articles;
   CJAVal           *articlesArrayElement;
   CJAVal           *sources;
   CJAVal           *sourcesArrayElement;

Die Hauptklasse CNewsFeed ist von CWndEvents abgeleitet. Deren private Eigenschaften sind Steuerungskomponenten, aus denen sich die Anwendung zusammensetzt, d.h. das Hauptfenster, an das die Listenansicht, die Textbox und die Statuszeile angehängt sind. Es gibt auch einen Zeitzähler zur Aktualisierung der Statuszeile. Die restlichen privaten Eigenschaften vom Typ CJAVal ermöglichen die Json-Parser-, srce- und js-Eigenschaften, die Json-Objekte enthalten, die von einem Aufruf für Nachrichtenquellen bzw. spezifische Nachrichten von einem bestimmten Nachrichtenanbieter zurückgegeben werden. Die übrigen Eigenschaften sind Zeiger, die sich auf verschachtelte Json-Objekte beziehen.

Der Rest der Klasse ist unten dargestellt.

//+------------------------------------------------------------------+
//|                                              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"
//+------------------------------------------------------------------+
//| Klasse zum Erstellen einer Anwendung                             |
//+------------------------------------------------------------------+
class CNewsFeed : public CWndEvents
  {
private:
   //--- Zeitzähler
   CTimeCounter      m_counter; // Aktualisieren der Elemente und der Statuszeile
   //--- Hauptfenster
   CWindow           m_window;
   //--- Statuszeile
   CStatusBar        m_status_bar;
   //--- Listenansicht
   CListView         m_listview;
   //--- Bearbeitet
   CTextBox          m_text_box;
   //--- Haupt-Json-Objekt 
   CJAVal            srce;
   CJAVal            js;
   //--- Json-Zeiger auf verschachtelte Elemente
   CJAVal           *articles;
   CJAVal           *articlesArrayElement;
   CJAVal           *sources;
   CJAVal           *sourcesArrayElement;
public:
                     CNewsFeed(void);
                    ~CNewsFeed(void);
   //--- Initialisierung/Deinitialisierung
   bool              OnInitEvent(void);
   void              OnDeinitEvent(const int reason);
   //--- Timer
   void              OnTimerEvent(void);
   //--- Chart Event Handler
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);

   //--- Erstellen des grafischen Interfaces des Programms
   bool              CreateGUI(void);
private:
   //--- Hauptfenster
   bool              CreateWindow(const string text);
   //--- Statuszeile
   bool              CreateStatusBar(const int x_gap,const int y_gap);
   //--- Listenansicht
   bool              CreateListView(const int x_gap,const int y_gap);
   //--- Bearbeitet
   bool              CreateTextBox(const int x_gap,const int y_gap);
   //--- Füllen der Quelle des Json-Objektes
   bool              PrepareSources(void);
   //--- Fill articles Json object based on selected element from sources Json object
   bool              PrepareArticles(int listview_index);
   //--- Laden der Daten
   string            DownLoad(string url,string file_name);
  };

Detaillierte Beschreibungen der Methoden zur grafischen Benutzeroberfläche finden Sie in Artikeln von Anatoli Kazharski.

Änderungen in der Klasse der CTextBox

Es gibt nur einen Teil der Bibliothek, den ich diskutieren möchte, da ich einige Änderungen vornehmen musste, um die Funktionalität zu aktivieren, die ich brauchte. Dies bezieht sich speziell auf das Steuerelement Textbox. Beim Testen stellte ich fest, dass die Methode update() von textbox nicht wie erwartet reagierte, wenn die Textbox mit neuem Inhalt aktualisiert wurde. Dieses Problem wurde behoben, indem einige private Methoden der gleichen Klasse zur Update-Methode hinzugefügt wurden, wie unten gezeigt.

Das Auffrischen des Inhalts in der Textbox brachte auch andere Probleme mit sich, die bei der Minimierung und Maximierung der Anwendung auftreten. Der Täter war wieder die Textbox. Diese Probleme beziehen sich meist auf das Autoresizing.

//+------------------------------------------------------------------+
//| Aktualisieren des Steuerelementes                                |
//+------------------------------------------------------------------+
void CTextBox::Update(const bool redraw=false)
  {
//--- Neuzeichnen der Tabelle, wenn angegeben
   if(redraw)
     {
      //--- Zeichnen
      //ChangeTextBoxSize();
      WordWrap();
      Draw();
      CalculateTextBoxSize();
      ChangeScrollsSize();
      //--- Anwenden
      m_canvas.Update();
      m_textbox.Update();
      return;
     }
//--- Anwenden
   m_canvas.Update();
   m_textbox.Update();
  }



Zuerst die Probleme mit den Bildlaufleisten. Horizontales und vertikales Scrollen scheint nach dem Auffrischen des Textfeldes teilweise zu funktionieren, ich sage teilweise, weil wenn ein bestimmter Punkt erreicht wurde, während das Scrollen des Inhalts plötzlich verschwinden würde. Ich bemerkte die Probleme, wenn neue Inhalte, die in das Textfeld geschrieben wurden, größere "size"-Parameter hatten (d.h. die maximale Zeilenbreite und die Anzahl der Zeilen, aus denen der Text besteht), relativ zum ursprünglichen Text, der während der Initialisierung angezeigt wurde. Um diese Probleme zu vermeiden, habe ich den Zeilenumbruchmodus aktiviert, so dass kein horizontaler Scrollbalken erforderlich ist und das Textfeld mit einer großen Anzahl von Leerzeilen initialisiert wurde. Die automatische Größenanpassung der Listenansicht und der Textbox in der vertikalen Ebene wurde deaktiviert.

Wenn Sie die Anwendung ausführen möchten und die Gui-Bibliothek heruntergeladen haben, ersetzen Sie einfach die Datei TextBox.mqh durch die am Ende des Artikels gezeigte.

Methoden zur Verarbeitung von Json-Objekten

//+------------------------------------------------------------------+
//| Methode für Web-Anfragen und Datensicherung                      |
//+------------------------------------------------------------------+     
string CNewsFeed::DownLoad(string url,string file_name="")
  {

// Falls das Terminal nicht verbunden ist, nimmt auch der EA an, keine Verbindung  
   if(!(bool)::TerminalInfoInteger(TERMINAL_CONNECTED))return(NULL);

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

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

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

// Laden des Datenstroms 
   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");
        }
      // Schreiben der geladenen Daten in eine Datei
      ::FileWriteString(hFile,pStream);
      ::FileClose(hFile);
     }
//Print("download success");
   return(pStream);
  }

Download() - Wird verwendet, um API-Aufrufe über die Webrequest-Funktion auszuführen und gibt die Antwort als Zeichenkette zurück. Wenn ein zweiter String-Parameter angegeben wird, wird die String-Antwort in einer Datei gespeichert. Wenn ein Fehler auftritt, wird der NULL zurückgegeben.

//+------------------------------------------------------------------+
//| Laden der Daten, um Quellen der Json-Object zu füllen            |
//+------------------------------------------------------------------+    
bool CNewsFeed::PrepareSources(void)
  {
   string sStream;
   int    iStringSize,hFile;

   string sources_filename="sources.txt";
// Laden der Daten
   sStream=DownLoad(BASE_URL+SRCE,sources_filename);

   if(sStream==NULL)
     {
      if(!::FileIsExist(sources_filename))
        {
         ::Print("error : required file does not exit");
         return(false);
        }
      // Dateiinhalt lesen 
      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);
     }
// Analysieren der Json-Daten  
   if(!srce.Deserialize(sStream))
     {
      ::Print("Json deserialize error");
      return(false);
     }
// Zuweisen eines Json-Objekts zur Quelle 
   if(srce["status"].ToStr()=="ok")
     {
      sources=srce["sources"];
      return(true);
     }
   else
     {
      Print("error json api access denied");
      return(false);
     }
  }

PrepareSources() wird während der EA-Initialisierung einmalig aufgerufen, um eine API-Anfrage für die verfügbaren Nachrichtenquellen zu stellen. Die Antwort wird in einer Datei gespeichert und mit der Methode Deserialize des Json-Parsers analysiert. Daher wird das Array der Quellen der json-Objekte einem Zeiger auf die Quellen zugewiesen. Wenn keine Verbindung besteht und die TXT-Quelldatei noch nicht erstellt wurde, wird der Expert Advisor nicht erfolgreich initialisiert.

//+------------------------------------------------------------------+
//| Laden der Daten, um Artikel der Json-Object zu füllen            |
//+------------------------------------------------------------------+     
bool CNewsFeed::PrepareArticles(int listview_index)
  {
   string sStream,id;
   int iStringSize,hFile;
// Prüfen der Quelle eines Json-Objektes 
   if(sources==NULL)
     {
      ::Print("Invalid pointer access");
      return(false);
     }

// Prüfen des Index 
   if(listview_index>=::ArraySize(sources.m_e))
     {
      Print("invalid array index reference");
      return(false);
     }
// Zuweisung von Json-Objekten zum Array sourcesArrayElement  
   sourcesArrayElement=sources[listview_index];
// Name der Nachrichtenquelle abfragen
   id=sourcesArrayElement["id"].ToStr();
// zurücksetzen von sourcesArrayElement
   sourcesArrayElement=NULL;

// Daten bestimmter Nachrichtenquellen herunterladen
   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);
        }

      // Json-Datei lesen 
      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);
     }

// Json-Datei analysieren
   if(!js.Deserialize(sStream))
     {
      ::Print("Json deserialize error");
      return(false);
     }
// json-Objekt dem Zeiger auf ein Artikel zuweisen
   if(js["status"].ToStr()=="ok")
     {
      articles=js["articles"];
      return(true);
     }
   else
     {
      Print("error json api access denied");
      return(false);
     }
  }


PrepareArticles() - diese Funktion wird in der Methode zur Ereignisbehandlung des Hauptcharts verwendet. So stellen Sie eine API-Anfrage für Nachrichten von einem bestimmten Nachrichtenausgang, bevor sie im Textfeld angezeigt werden können. Ein an die Funktion übergebener ganzzahliger Wert repräsentiert den Index eines ausgewählten Listenelements. Dieser Index wird verwendet, um den gewählten News Outlet zu identifizieren, so dass die richtige API-Request-URL erstellt werden kann. Die API-Antwort wird genauso behandelt, wie sie in der Methode PrepareSources verarbeitet wird.

Beachten Sie auch, dass beide der eben beschriebenen Methoden ohne Verbindung funktionieren können, wenn und nur wenn eine API-Anforderung mit einer bestehenden Datei übereinstimmt.

Aktualisieren des Textfeldes

Als nächstes werfen wir einen Blick auf die Methode OnchartEvent. Wenn ein Listenelement angeklickt wird, wird zuerst das Textfeld automatisch nach oben gescrollt. Dies ist notwendig, um zu verhindern, dass neue Inhalte falsch angezeigt werden. Die Methoden des Listenansichtsobjekts SelectedItemText() und SelectedItemIndex() werden verwendet, um den Namen und den Index des angeklickten Listenansichtselements zu erhalten, der in diesem Fall den Namen der ausgewählten Nachrichtenquelle und dessen Position im Quellenarray des json-Quellobjektes definiert. Aus diesen Informationen kann die richtige URL erstellt werden, um eine API-Anfrage für Nachrichtenschlagzeilen mit der PrepareArtilces() Methode zu stellen. Wenn erfolgreich, wird das Textfeld mit den neuesten Überschriften aktualisiert, andernfalls wird eine Fehlermeldung angezeigt.

//+------------------------------------------------------------------+
//| Ereignisbehandlung des Charts                                    |
//+------------------------------------------------------------------+
void CNewsFeed::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
// wenn eine der Nachrichtenquellen ausgewählt ist (angeklickt)
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LIST_ITEM)
     {
      string nameofobject="";        //name of selected news source
      int selected,asize,g;          //selected - index of selected list item , asize - array size of articles json object array , g -array index
      bool ar=false;                 // ar - Rückgabewert der Methode prepareArticles
                                     // Erstes automatisches Scrollen des Textfeldes an den Anfang, nur wenn das vertikale Scrollen erforderlich ist.
      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;
      //--- löscht den aktuellen Inhalt des Textfeldes
      m_text_box.ClearTextBox();
      //--- Überschrift für neuen Textfeldinhalt hinzufügen
      m_text_box.AddText(0,nameofobject+" Top HeadLines:");
      //--- Abhängig vom Erfolg der PrepareArticles-Methode werden die Inhalte der Textfelder gefüllt.
      if(asize>0 && ar)// Falls PrepareArticles erfolgreich ist
        {
         string descrip,des;
         for(g=0; g<asize;g++)
           {
            // Json-Objekt auf Array-Element von Artikeln setzen Array von Json-Objekten
            articlesArrayElement=articles[g];
            // Wert abfragen 
            des=articlesArrayElement["description"].ToStr();
            // zusätzlichen Text, der je nach Verfügbarkeit angezeigt werden soll, einstellen
            descrip=(des!="null" && des!="")? " -> "+des:".";
            // neuen Text zum Textfeld hinzufügen 
            m_text_box.AddLine(string(g+1)+". "+articlesArrayElement["title"].ToStr()+descrip);
           }
        }
      else // Falls PrepareArticles nicht erfolgreich ist
        {
         asize=1; // Setzen der Größe auf Eins
         for(g=0; g<asize;g++)
           {
            // Fehlermeldung im Textfeld anzeigen
            m_text_box.AddLine("Error retrieving data from feed.");
           }
        }
      //-- das Textfeld neu zeichnen      
      m_text_box.Update(true);
      //-- Wert des Objektes Artikel zurücksetzen
      articles=NULL;
      //Print("clicked listview item is "+nameofobject);
      return;
     }
  }

Damit ist die Definition der Klasse CNewsFeed abgeschlossen, so dass sie in einen Expert Advisor aufgenommen werden kann.

Der Expert Advisor NewsFeedProgram

Der Code wird unten zusammen mit einigen Screenshots gezeigt, wie die Anwendung beim Ausführen aussehen wird.

//+------------------------------------------------------------------+
//|                                               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;
//+------------------------------------------------------------------+
//| Initialisierungsfunktion des Experten                            |
//+------------------------------------------------------------------+
int OnInit()
  {

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

//--- Einrichten des Handelspanels
   if(!program.CreateGUI())
     {
      ::Print("Failed to create graphical interface!");
      return(INIT_FAILED);
     }
//--- Initialisierung war erfolgreich
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Deinitialisierungsfunktion des Experten                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Timer löschen
   program.OnDeinitEvent(reason);

  }
//+------------------------------------------------------------------+
//| Experten Funktion OnTick                                         |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+
//| Timer Funktion                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---
   program.OnTimerEvent();
  }
//+------------------------------------------------------------------+
//| Funktion der Chart-Events                                        |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   program.ChartEvent(id,lparam,dparam,sparam);
  }

Initial look of application

News display


Schlussfolgerung

In diesem Artikel haben wir die Möglichkeit das Erstellen eines benutzerdefinierten Newsfeeds mit Hilfe einer Nachrichten-Web-API untersucht. Der demonstrierte EA ist sehr einfach und kann wahrscheinlich durch die Aktivierung einer automatischen Update-Funktion erweitert werden, so dass die App die neuesten Nachrichten anzeigen kann, sobald sie verfügbar sind. Ich hoffe, es wird jemandem nützlich sein.

Bitte beachten Sie, dass Sie die GUI-Bibliothek herunterladen müssen, damit der EA korrekt funktioniert. Ersetzen Sie dann die Datei TextBox.mqh durch die an diesen Artikel angehängte Datei.

Im Artikel verwendete Programme und Dateien

Name 
Typ
Beschreibung
JAson.mqh
Header Datei
Json Serialisierung und Deserialisierung der Nativen MQL-Klasse
json.mqh
Header Datei
Klasse zur Analyse von Json
TextBox.mqh
Header Datei
Modifizierte Klasse des Textfeldes zur Darstellung von Text auf dem Chart
NewsFeedProgram.mqh
Header Datei
Hauptklasse des EAs für den Newsfeed
NewsFeedExpert.mq5
Expert Advisor Datei
Expert Advisor, der die Klasse der Newsfeed umsetzt
NewsAPI_test.mq5
Script Datei
Skript zum Testen der API-Aufrufe
newstest_JAson.mq5
Script Datei
Testskript für den Zugriff auf die Möglichkeiten der Bibliothek JAson.mqh library
newstest_json.mq5
Script Datei
Testskript für den Zugriff auf die Möglichkeiten der Bibliothek json.mqh