Nativer Twitter-Client: Teil 2

Soewono Effendi | 17 September, 2020

Einführung

Wie in meinem ersten Artikel "Native Twitter-Client für MT4 und MT5 ohne DLL" versprochen, wird der folgende Artikel versuchen, die Twitter-API zum Senden von Tweets mit Fotos zu erforschen. Um diesen Artikel leicht und einfach verständlich zu halten, werde ich mich nur auf das Hochladen von Bildern konzentrieren. Am Ende dieses Artikels sollten Sie über einen funktionierenden Twitter-Client ohne externe DLL verfügen, mit dem Sie Nachrichten mit bis zu vier Fotos twittern können. Das Limit von 4 Fotos wird von der Twitter-API festgelegt, wie im Parameter media_ids erklärt wird.


Hochladen von Fotos

Es gibt eine neue Methode mit dem Namen chunked upload, um Medien mit besseren Methoden zum Hochladen großer Dateien, z.B. Videos oder animierte GIFs, hochzuladen. Für unseren Zweck werde ich mich auf die einfache Methode konzentrieren, die auf das Hochladen von Bildern beschränkt ist.

Bitte stellen Sie sicher, dass Sie mit Twitters Medientypen und Größenbeschränkungen vertraut sind.

Das Hochladen von Fotos auf Twitter ist im Grunde genommen ein einfacher OAuth authentifizierter http multipart/form-data POST, den ich im nächsten Absatz erläutern werde. Jedes hochgeladene Foto wird eine media_id zurückgeben, die nur innerhalb einer bestimmten Zeitspanne gültig ist, damit es in einen Tweet aufgenommen und veröffentlicht werden kann.

Um bis zu vier Fotos zu veröffentlichen, werden alle zurückgegebenen media_ids einfach als komma-separierte Liste zusammengefügt.

Die Schritte zum Tweeten einer Nachricht mit Fotos sind wie folgt:

  1. Foto hochladen und deren zurückgegebene media_id sichern
  2. Wiederholen Sie das Hochladen weiterer Fotos, bis max. 4 Fotos. Sichern Sie immer die zurückgegebenen media_id.
  3. Bereiten Sie Ihre Tweet-Nachricht vor.
  4. Geben Sie die media_ids an, wenn Sie Ihren Tweet mit der durch Komma getrennten Liste aller einzufügenden media_id senden.
Hinweis:
Um den Code einfach und leicht verständlich zu halten, wird auf eine Fehlerbehandlung verzichtet.


HTTP multipart/form-data

Um Fotos auf Twitter hochzuladen, können die Fotos als binäre Rohdaten oder als Base64-kodierter String hochgeladen werden. Es wird empfohlen, Fotos als binäre Rohdaten hochzuladen, da der Base64-kodierte String etwa dreimal so groß ist.

Die Datenmethode für multipart/form-data ist in RFC-2388 gut definiert, aber es könnte leichter zu verstehen sein, wenn man dieses schöne Tutorial von curl liest. Im Grunde genommen ist es, wie aus dem erwähnten Artikel zitiert, "eine HTTP-POST-Anforderung, die mit dem Anforderungstext gesendet wird, der speziell als eine Reihe von 'Teilen' formatiert und durch MIME-Grenzen getrennt ist".

POST /submit.cgi HTTP/1.1
Host: example.com
User-Agent: curl/7.46.0
Accept: */*
Content-Length: 313
Expect: 100-continue
Content-Type: multipart/form-data; boundary=------------------------d74496d66958873e

--------------------------d74496d66958873e
Content-Disposition: form-data; name="person"

anonymous
--------------------------d74496d66958873e
Content-Disposition: form-data; name="secret"; filename="file.txt"
Content-Type: text/plain

contents of the file
--------------------------d74496d66958873e--


Die Implementierung in der Twitter-Klasse sieht wie folgt aus:

   void              appendPhoto(string filename, string hash, uchar &data[],
                                 bool common_flag=false)
     {
      int flags=FILE_READ|FILE_BIN|FILE_SHARE_WRITE|FILE_SHARE_READ;
      if(common_flag)
         flags|=FILE_COMMON;
      //---
      int handle=FileOpen(filename,flags);
      if(handle==INVALID_HANDLE)
         return;
      //---
      int size=(int)FileSize(handle);
      uchar img[];
      ArrayResize(img,size);
      FileReadArray(handle,img,0,size);
      FileClose(handle);
      int pos = ArraySize(data);
      int offset = pos + size;
      int hlen = StringLen(hash)+6;
      int newlen = offset + hlen;
      ArrayResize(data, newlen);
      ArrayCopy(data, img, pos);
      StringToCharArray("\r\n--"+hash+"\r\n", data, offset, hlen);
     }

Der obige Code fügt die rohen Binärdaten einer Bilddatei zu den "Teilen" des HTTP-Multipart/Formulardaten-Posts hinzu. Die "Hülle" des POST erfolgt im folgenden Code, wobei der Twitter Upload-API-Parameter "media" angegeben wird.

   string              uploadPhoto(string filename)
     {
      // POST multipart/form-data
      string url = "https://upload.twitter.com/1.1/media/upload.json";
      //string url = "https://httpbin.org/anything";
      string params[][2];
      string query = oauthRequest(params, url, "POST");
      string o = getOauth(params);
      string custom_headers = "Content-Type: multipart/form-data;"
                              " boundary=";
      string boundary = getNonce();
      StringAdd(custom_headers, boundary); // use nonce as boundary string
      StringAdd(custom_headers, "\r\n");
      string headers = getHeaders(o, custom_headers, "upload.twitter.com");

      //string query = getQuery(params, url);
      //Print(query);
      uchar data[];
      string part = "\r\n--";
      StringAdd(part, boundary);
      StringAdd(part, "\r\nContent-Disposition: form-data;"
                " name=\"media\"\r\n\r\n");
      StringToCharArray(part, data, 0, StringLen(part));
      appendPhoto(filename, boundary, data);
      string resp = SendRequest("POST", url, data, headers);;
      if(m_verbose)
        {
         SaveToFile(filename + "_post.txt", data);
         Print(resp);
        }
      return (getTokenValue(resp, "media_id"));
     }

Um die erstellten HTTP-Multipart/Formulardaten zu inspizieren und zu verifizieren, kann die HTTP-Anforderung zur weiteren Inspektion als Datei im Datenordner des MT-Terminals gespeichert werden.


Tweet mit Fotos

Für einfache Zwecke verwende ich eine einfache Funktion getTokenValue(), um die von der Twitter-Upload-API zurückgegebene media_id abzurufen. Vielleicht sollten Sie die Verwendung der ausgezeichneten JSON-Bibliothek in Betracht ziehen, die auf MQL5.com verfügbar ist. 

Der folgende Code zeigt einen sehr einfachen Weg, die Twitter-Klasse zu verwenden. Die Funktion Screenshots() macht einfach Screenshots von aktuell geöffneten Charts und erstellt eine einfache Tweet-Nachricht. Bis zu vier Charts werden ausgewählt.
Jeder Screenshot wird als Datei gespeichert, deren Name im Text-Array fnames zurückgegeben wird.

Die Screenshots werden nacheinander hochgeladen, wobei die zurückgegebene media_id gesichert und als kommagetrennte Liste zusammengestellt wird.
Durch die Angabe der Parameter der media_ids mit dieser durch Komma getrennten Liste wird die Tweet-Nachricht mit diesen Screenshots als Anhang an den Tweet gepostet.

So einfach ist das.

   CTwitter tw(consumer_key, consumer_secret,
               access_token, access_secret, verbose);

   // Gather information
   string fnames[4];
   string msg;
   Screenshots(fnames, msg);

   // Upload screenshots
   int n = ArraySize(fnames);
   int i = n - 1;
   // create comma separated media_ids
   string medias = tw.uploadPhoto(fnames[i]);
   for(i= n - 2; i>=0; i--)
   {
      StringAdd(medias, ",");
      StringAdd(medias, tw.uploadPhoto(fnames[i]));
   }
   
   // Send Tweet with photos' ids
   string resp = tw.tweet(msg, medias);
   Print(resp);


Twitter-Klasse

Die Twitter-Klasse, wie sie in der Twitter.mqh zu finden ist, wurde mit dem Ziel entwickelt, unabhängig von anderen Include-Dateien in sich geschlossen zu sein. Um einen Tweet mit Fotos zu versenden, genügt eine einzige Datei.

Zuerst instanziieren Sie ein Twitter-Objekt, indem Sie Ihr Nutzer- und Zugriffstoken angeben, mit einem optionalen Verbose-Flag, um bei der Fehlersuche während der Entwicklung zu helfen.

   CTwitter tw(consumer_key, consumer_secret,
               access_token, access_secret, verbose);

Dann können Sie versuchen, verfügbare öffentliche Funktionen aufzurufen:

Es gibt einige Hilfsfunktionen:

  • getTokenValue()
    gibt den Wert eines Token/Parameters aus einer Json-Zeichenkette zurück.
    NOTE: Dies ist eine sehr einfache Textanalyse, erwarten Sie daher keine volle Json-Kompatibilität.
  • unquote()
    entfernt die Anführungszeichen in einem Text.


Tweet Ihres Charts

Beigefügt ist ein funktionierendes MT5-Skript, das Screenshots von bis zu vier Charts macht und eine einfache Tweet-Nachricht mit dem Symbol des Charts und dem OHLC-Wert erstellt.

Es ist ein einfaches Beispiel für Sie, um mit der Entwicklung Ihrer eigenen Experten und/oder Skripte zu beginnen.

Hinweis:Sie müssen Ihre eigenen Nutzer- und Zugriff-Tokens und Geheimschlüssel definieren.

Nachfolgend finden Sie Beispiele für die vom Skript gesendeten Tweets.

Tweet mit vom MT5 gesendeten Bildschirmfotos

Abb. 1 Tweet mit vom MT5 gesendeten Bildschirmfotos


MT5-Chart in voller Größe auf Twitter

Abb. 2 MT5-Chart in voller Größe auf Twitter 


Und natürlich können Sie auch andere Fotos anhängen ;)



Ein Tweet glücklicher Katzen

Abb. 3 Ein Tweet glücklicher Katzen


Schlussfolgerung

Eine einfache und leicht zu benutzende Twitter-Klasse als eigenständige Include-Datei steht Ihnen zur Verfügung, mit der Sie Ihre Charts und Signale leicht veröffentlichen können. Die relevanten technischen Details werden in der Hoffnung dargestellt, dass sie leicht verständlich sind.

Diese Twitter-Klasse ist bei weitem nicht vollständig, es gibt viele andere Twitter-APIs, die zu dieser Klasse hinzugefügt werden können. Fühlen Sie sich frei, Ihre Verbesserungen im Kommentar zum Nutzen der MQL5-Gemeinschaft zu veröffentlichen.

Ich hoffe, dass Ihnen die Lektüre dieses Artikels gefällt, so wie mir das Schreiben Spaß gemacht hat.
Ich wünsche Ihnen, dass Sie den zur Verfügung gestellten Code auch aus Spaß und Profit nutzen können.

Genießt's.