概述
就像我在第一篇文章“无需 DLL 的 MT4/MT5 的原生推特(Twitter)客户端”中所承诺的那样;本文将尝试探索 Twitter API,从而能发送带有照片的推文。 为了令本文更容易理解,我仅关注上传图像。 到本文结尾,您应能得到一个可运行的推特客户端,且无需用到任何外部 DLL,这令您可发布最多四张照片的消息。 4 张照片的限制是由 Twitter API 设置,如参数 media_ids 中所述。
上传照片
有一种新方法,称为分块上传,在上传媒体时可用更好的方法来上传较大的文件,譬如视频或 GIF 动画。 出于我们的目的,我将关注简单方法,该方法仅限于仅上传图片。
请确保您已熟知推特的媒体类型和大小限制。
将照片上传到推特只是一个简单的基本 OAuth 授权 HTTP multipart/form-data POST,我将在下个段落中对其进行解释。 已上传的每张照片都将返回一个 media_id,该 ID 仅在一定时间内有效,从而可在要发布的推文里包含它。
为了发布多达四张照片,所有返回的 media_id 都被简单地连接在一起,形成以逗号分隔的列表。
发布带照片推文的步骤如下:
- 上传照片并收集返回的 media_id
- 重复上传更多照片,直达上限。 4 张照片。 始终收集其返回的 media_id。
- 准备您的推文消息
- 发送推文时,请指定 media_id,并在列表里以逗号分隔所有要包含的 media_id。
注意:
为了令代码简单易懂,省略了错误处理。
HTTP multipart/form-data
为了将照片上传到推特,可将这些照片作为原始二进制数据或 Base64 编码的字符串上传。 建议将照片作为原始二进制数据上传,因为 Base64 编码的字符串的大小约暴涨三倍。
HTTP multipart/form-data 方法在 RFC-2388 中加以良好定义,但阅读本篇不错指南也许更容易理解。 基本上,从提到的文章中引用:“这是一个 HTTP POST 请求,其发送的请求主体已特别格式化为一个 "parts" 序列,并用 MIME 边界分隔。”
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--
Twitter 类的实现如下:
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);
}
上面的代码将图像文件的原始二进制数据添加到 HTTP multipart/form-data post 的 “parts” 里。 POST 的 “envelope” 的代码完成如下,并指定了 Twitter Upload-API 参数 “media”。
string uploadPhoto(string filename)
{
string url = "https://upload.twitter.com/1.1/media/upload.json";
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);
StringAdd(custom_headers, "\r\n");
string headers = getHeaders(o, custom_headers, "upload.twitter.com");
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"));
}
为了检查和验证构建的 HTTP multipart/form-data,把 HTTP 请求另外保存在 MT 终端的数据文件夹中,以便进行进一步检查。
带照片的推文
出于简洁起见,我用了一个简单的函数 getTokenValue() 来提取 Twitter Upload-API 返回的 media_id。 您可能会考虑使用出色的 MQL5.com 上提供的 JSON 库。
以下代码展示了一种非常简单使用 Twitter 类的方法。 函数 Screenshots() 简单地捕获当前打开图表的屏幕截图,并构建一条简单的推文消息。 最多能选择四个图表。
每个屏幕截图均保存到文件,其文件名在字符串数组 fnames 里返回。
屏幕截图被逐一上传,收集返回的 media_id,合并的列表则以逗号分隔。
依据上述逗号分隔列表中指定的 media_ids 参数,我们发布带有这些屏幕截图的推文消息,并将这些屏幕截图附加到推文里。
就是如此容易。
CTwitter tw(consumer_key, consumer_secret,
access_token, access_secret, verbose);
string fnames[4];
string msg;
Screenshots(fnames, msg);
int n = ArraySize(fnames);
int i = n - 1;
string medias = tw.uploadPhoto(fnames[i]);
for(i= n - 2; i>=0; i--)
{
StringAdd(medias, ",");
StringAdd(medias, tw.uploadPhoto(fnames[i]));
}
string resp = tw.tweet(msg, medias);
Print(resp);
Twitter 类
您可以在 Twitter.mqh 中找到 Twitter 类,其目标是独立于其他包含文件。 若要发送带有照片的推文,这一个文件就能满足您全部需求了。
首先,实例化一个 Twitter 对象,指定您的使用者和访问令牌,并带有一个可选的冗长标志,这有助于在开发过程中进行调试。
CTwitter tw(consumer_key, consumer_secret,
access_token, access_secret, verbose);
然后,您可以尝试调用可用的公开函数:
- verifyCredentials()
返回您的访问令牌 Twitter ID
- uploadPhoto()
上传照片,并返回其 media_id
- tweet()
发送带有可选 media_ids 的推文
还有一些辅助函数:
- getTokenValue()
从 json 字符串返回令牌/参数的值。
注意: 这是一个非常简单的字符串解析,不要期望能与 json 完全兼容。
在推特上发布您的图表
附件是一个有效的 MT5 脚本,该脚本可捕获多达四个图表的屏幕截图,并构建一条简单的推文消息,其中包含图表的品种和 OHLCV 值。
这是一个简单的示例,是您开始自行研发智能系统和/或脚本的起点。
注意:
您必须指定自己的使用者、访问令牌和密匙。
以下是脚本发送的推文示例。

图例 1. 自 MT5 发送的带照片推文

图例 2. 推特上的全尺寸 MT5 图表
当然,您也可以附加任何照片;)

图例 3. 幸运猫推文
结束语
此处为您提供了一个简单易用的 Twitter 类作为自包含文件,令您轻松发布图表和信号。 还示意了相关的技术细节,希望它们可以很容易就理解。
这个 Twitter 类还远未完工,还有许多其他 Twitter API 会添加到该类之中。 请随时在评论中发表您的改进意见,这都会令 MQL5 社区受益。
我希望您阅读本文时能感到愉悦,就像我写这篇文章时一样。
我也希望您可以用所提供的代码来得到乐趣和收益。
尽享快乐。