Native Twitter Client: Part 2

19 August 2020, 11:41
Soewono Effendi
0
12 418

Introduction

As promised in my first article "Native Twitter Client for MT4 and MT5 without DLL" following article will try to explore the Twitter API to send tweets with photos. To keep this article easy and simple to be understood I will focus on uploading image only. By the end of this article, you should have a working Twitter client without using any external DLL, which allow you to tweet messages with up to four photos. The limit of 4 photos is set by Twitter API as explained in the parameter media_ids.


Uploading photos

There is a new method, called chunked upload, to upload media with better methods to upload large files, e.g. videos or animated GIFs. For our purpose I will focus on the simple method which is limited to upload image only.

Please make sure you're familiar with Twitter's media types and sizes restrictions.

Uploading photo to Twitter is basically a simple OAuth authorized HTTP multipart/form-data POST which I will explain in the next paragraph. Each photo uploaded will return a media_id which is valid only within a certain amount of time to allow it to be included in a tweet to be publish.

To publish up to four photos, all returned media_ids are simple joined together as a comma-separated list.

The steps to tweet a message with photos are as following:

  1. Upload photo and collect its returned media_id
  2. Repeat uploading further photos, up to max. 4 photos. Always collect its returned media_id.
  3. Prepare your tweet message
  4. Specify media_ids when sending your tweet with the comma-separated list of all media_id to be included.
NOTE:
To keep the code simple and easier to follow, error handling is omitted.


HTTP multipart/form-data

To upload photos to Twitter, the photos can be uploaded as raw binary data or as Base64 encoded string. It is recommended to upload photos as raw binary data, since Base64 encoded string is about three times larger in size.

The HTTP multipart/form-data method is well-defined in RFC-2388 but it might be easier to understand when reading this nice tutorial of curl. Basically, quoted from the mentioned article, "it is an HTTP POST request sent with the request body specially formatted as a series of "parts", separated with MIME boundaries."

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--


The implementation in the Twitter class, is as follows:

   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);
     }

The above code adds the raw binary data of an image file to the "parts" of the HTTP multipart/form-data post. The "envelope" of the POST is done in the following code, with the Twitter Upload-API parameter "media" specified.

   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"));
     }

To inspect and to verify the build HTTP multipart/form-data, the HTTP request can be saved as file in MT terminal's data folder for further inspection.


Tweet with photos

For simple purpose, I use a simple function getTokenValue() to retrieve media_id  returned by the Twitter Upload-API. You might want to consider using the excellent JSON library available on MQL5.com

Following code shows a very simple way to use the Twitter class. The function Screenshots() simply takes screenshots of currently opened charts and builds a simple tweet message. Up to four charts are selected.
Each screenshot is saved as a file, its filename is returned in the string array fnames.

The screenshots are uploaded one-by-one, with its returned media_id collected and gathered together as a comma-separated list.
By specifying media_ids parameter with this above comma-separated list, we post the tweet message with these screenshots attached to the tweet.

As simple as that.

   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 class

The Twitter class as you can find in the Twitter.mqh is developed with the goal to be self-contained, independent of other include files. To send a tweet with photos that single file is all you need.

First you instantiate a Twitter object, specifying your consumer and access token, with an optionally verbose flag to help in debugging during development.

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

Then you can try to call avalilable publc functions:

  • verifyCredentials() 
    returns the Twitter ID for your access token
  • uploadPhoto()
    upload a photo and returns its media_id
  • tweet()
    send a tweet with optional media_ids

There are some helper functions:

  • getTokenValue()
    return the value of a token/parameter from a json string.
    NOTE: This is a very simple string parsing, do not expect full json compatibility.
  • unquote()
    remove quotes from a string.


Tweet your charts

Attached is a working MT5 script that takes screenshot of up to four charts and build a simple tweet message of chart's symbol and OHLCV value.
It is a simple example for you to get started to develop your own experts and/or scripts.


NOTE:You must specify your own consumer and access tokens and secrets.

Following are examples of the tweets sent by the script.

Tweet with photos sent from MT5

Figure 1. Tweet with photos sent from MT5


Full size MT5 chart on Twitter

Figure 2. Full size MT5 chart on Twitter 


And of course you can also attach any photos ;)



Tweet with lucky cats

Figure 3. Tweet with lucky cats


Conclusion

A simple and easy to use Twitter class as a self-contained include file is provided for you to publish your charts and signals easily. The relevant technical details are presented in the hope that they can be easily understood.

This Twitter class is far from complete, there are many other Twitter APIs that can be added to this class. Feel free to post your improvements in the comment for the benefit of MQL5 community.

I hope you enjoy reading this article, as I have enjoyed writing it.
I wish you can use the code provided for fun and profit too.

Enjoy.


Attached files |
Twitter.mqh (19.77 KB)
TwitterDemo.mq5 (4.87 KB)
Timeseries in DoEasy library (part 42): Abstract indicator buffer object class Timeseries in DoEasy library (part 42): Abstract indicator buffer object class

In this article, we start the development of the indicator buffer classes for the DoEasy library. We will create the base class of the abstract buffer which is to be used as a foundation for the development of different class types of indicator buffers.

Native Twitter Client for MT4 and MT5 without DLL Native Twitter Client for MT4 and MT5 without DLL

Ever wanted to access tweets and/or post your trade signals on Twitter ? Search no more, these on-going article series will show you how to do it without using any DLL. Enjoy the journey of implementing Tweeter API using MQL. In this first part, we will follow the glory path of authentication and authorization in accessing Twitter API.

Multicurrency monitoring of trading signals (Part 5): Composite signals Multicurrency monitoring of trading signals (Part 5): Composite signals

In the fifth article related to the creation of a trading signal monitor, we will consider composite signals and will implement the necessary functionality. In earlier versions, we used simple signals, such as RSI, WPR and CCI, and we also introduced the possibility to use custom indicators.

Timeseries in DoEasy library (part 43): Classes of indicator buffer objects Timeseries in DoEasy library (part 43): Classes of indicator buffer objects

The article considers the development of indicator buffer object classes as descendants of the abstract buffer object simplifying declaration and working with indicator buffers, while creating custom indicator programs based on DoEasy library.