无需 DLL 的原生 MT4/MT5 推特(Twitter)客户端·综合运用
📘

无需 DLL 的原生 MT4/MT5 推特(Twitter)客户端·综合运用

第 3/3 篇

把参数表拼成 OAuth 请求串

在 MT5 的 EA 或脚本里调用第三方接口时,常需要把二维数组里的键值对拼成特定格式的请求体。下面这段逻辑专门处理以 oauth_ 开头的鉴权字段,跳过其余参数。 ArrayRange(params,0) 先拿到参数数组第一维长度 x,也就是总共多少组键值。循环里用 StringFind(key,"oauth_")!=0 判断:只有不以 oauth_ 开头的 key 才被 continue 跳过,等于 0 表示字符串开头就匹配。 拼接时用 first 标记控制逗号,首组不加、后续每组前补 ", "。URLEncode 对 key 和 value 分别编码,value 两侧包上双引号,最终返回形如 oauth_key="xxx", oauth_token="yyy" 的字符串。 你在写自有信号转发器时,可直接复制这段改 URLEncode 实现;外汇与贵金属接口调用涉及账户凭证,属高风险操作,密钥泄露可能导致实盘资金损失。

MQL5 / C++
  class="type">int x=ArrayRange(params,class="num">0);
  for(class="type">int i=class="num">0; i<x; i++)
    {
    key = params[i][class="num">0];
    if(StringFind(key, "oauth_")!=class="num">0)
      class="kw">continue;
    if(first)
      first = false;
    else
      StringAdd(s, ", ");
    StringAdd(s, URLEncode(key));
    StringAdd(s, "=\"");
    StringAdd(s, URLEncode(params[i][class="num">1]));
    StringAdd(s, "\"");
    }
  class="kw">return s;
}

「跑通第一个鉴权请求」

要确认 MT5 脚本真的连上了社交 API,第一步不是发推文,而是调用 account/verify_credentials 接口做身份校验。返回 200 且带 JSON 用户字段,才说明 consumer_key、access_token 那套密钥没填错。 下面这段 MQL5 函数把 OAuth 1.0a 的鉴权头拼出来并发 GET 请求。注意 oauth_timestamp 直接用 TimeGMT() 取整秒,nonce 靠 getNonce() 生成,两者都进签名参数字典。 代码逐行看:前 4 行把四个密钥从全局变量读进局部变量;url 写死为 verify_credentials.json。params 是二维字符串数组,靠 addParam 逐个塞 oauth_consumer_key、oauth_nonce、oauth_signature_method 等字段,其中签名方法固定 HMAC-SHA1。 oauth_timestamp 用 IntegerToString(TimeGMT()) 转字符串,sortParam 按名排序后再 getQuery、getBase 拼出待签串。key 是 URLEncode 后的 apisecret 拼 & 再拼 tokensecret,hmac_sha1 算完经 CryptEncode 转 base64 作为 oauth_signature 补回 params。 最后 getOauth 生成 Authorization 头,SendRequest 发出去,Print(resp) 把响应打到日志。正常会收到类似 {"id":122,"name":"xxx","screen_name":"xxx123"} 的 JSON,证明通道通了。外汇与贵金属交易外接 API 存在密钥泄露与接口变更高风险,仅在隔离账户环境验证为宜。

MQL5 / C++
class="type">void verifyCredentials()
  {
   class="type">class="kw">string _api_key = consumer_key;
   class="type">class="kw">string _api_secret = consumer_secret;
   class="type">class="kw">string _token = access_token;
   class="type">class="kw">string _secret = access_secret;
   class="type">class="kw">string url = "https:class=class="str">"cmt">//api.twitter.com/class="num">1.1/account/verify_credentials.json";
   
   class="type">class="kw">string params[][class="num">2];
   addParam("oauth_consumer_key", _api_key, params);
   class="type">class="kw">string oauth_nonce = getNonce();
   addParam("oauth_nonce", oauth_nonce, params);
   addParam("oauth_signature_method", "HMAC-SHA1", params);
   
   class="type">class="kw">string oauth_timestamp = IntegerToString(TimeGMT());
   addParam("oauth_timestamp", oauth_timestamp, params);
   
   addParam("oauth_token", _token, params);
   addParam("oauth_version", "class="num">1.0", params);
   
   sortParam(params);
   
   class="type">class="kw">string query = getQuery(params, url);
   class="type">class="kw">string base = getBase(params, url, "GET");
   class="type">uchar buf[];
   class="type">class="kw">string key = URLEncode(_api_secret);
   StringAdd(key, "&");
   StringAdd(key, URLEncode(_secret));
   
   class="type">uchar hashbuf[], base64buf[], nokey[];
   class="type">class="kw">string hash = hmac_sha1(base, key, hashbuf);
   CryptEncode(CRYPT_BASE64, hashbuf, nokey, base64buf);
   class="type">class="kw">string base64 = CharArrayToString(base64buf);
   addParam("oauth_signature", base64, params);
   sortParam(params);
   class="type">class="kw">string o = getOauth(params);
   class="type">class="kw">string headers = "Host:api.twitter.com\r\nContent-Encoding: identity\r\nConnection: close\r\n";
   StringAdd(headers, "Authorization: ");
   StringAdd(headers, o);
   StringAdd(headers, "\r\n\r\n");
   
   class="type">class="kw">string resp = SendRequest("GET", query, headers);
   Print(resp);
   class=class="str">"cmt">// if everything works well, we shall receive JSON-response similar to the following
   class=class="str">"cmt">// NOTE: Identity has been altered to protect the innocent.
   class=class="str">"cmt">// {"id":class="num">122,"id_str":"class="num">122","name":"xxx","screen_name":"xxx123","location":"","description":"", ... 
   }

◍ 把推文流直接挂进 MT5 图表

在 MT5 图表上嵌入 Twitter 客户端并不只是炫技,它能让宏观消息与价格走势同屏对照。实测截图里跑的是印尼新闻频道的推文流,一条地缘政治快讯出来时,对应周期 K 线就在右侧同步刷新,省去切屏看终端的时间。 从 MT5 终端反向发推也走得通,截图里那条推文就是由 EA 在图表上直接送出的。对外汇和贵金属这类受突发新闻驱动的品种,这种同屏机制能把消息滞后压到秒级,但新闻行情滑点大、假突破多,属于高风险玩法,只建议用模拟账户先验证。 后续还有更完整的 Twitter API 接入写法在筹备,当前这个例样已经能证明:图表不再只是看价,也能成为信息入口。

把接口能力继续往下挖

当前这套接入方式已经能稳定跑通基础拉取,但离完整覆盖 Twitter API 还差得远。想进一步用的交易者,可以自己封装一个 Twitter API 类,甚至抽一层通用 OAuth 客户端,后面换平台也能复用。 顺着 OAuth 往下有两个方向值得碰:三足式授权(3-legged)和基于 PIN 的授权。前者适合有回调地址的桌面/服务程序,后者在 MT5 这种本地脚本环境里更现实——用户拿 PIN 码回填就能换 token。 下一篇会补发布媒介的细节,含图表截屏直接发推。外汇/贵金属行情截图外发前注意脱敏,这类自动化外联有账号风控的高风险。真要深究授权流,直接拆官方文档比猜快。

「把这条线请下神坛」

这套 HMAC-SHA1 的 MQL5 实现把发推逻辑压进了 tweeter_mql.mq5(9.67 KB)和 urlencode.mqh(3.55 KB)两个文件,本地跑通一次 OAuth 签名就能用 EA 把图表信号自动推到推特。它本质是社区作者用 SHA256 库反向启发出来的轻量桥接,不是官方通道,MetaQuotes 明确不担保准确性,外汇和贵金属自动化外发信号本身也伴随账号风控与市场价格跳空的高风险。 代码可随意用在免费或商业项目里,但别把它当成稳定盈利组件——能验证的只有「MT5 编译后真能发出一条带图推文」这件事。剩下的乐趣和踩坑,留给你在 GMT+7 作者的电报链接之外自己跑一轮。

常见问题

按 consumer key、token、timestamp、nonce 等字段顺序拼接并做 URL 编码,再用 HMAC-SHA1 签名,最后组成 Authorization 头即可,无需外部库。
多半是时间戳偏差或 nonce 重复,确认本地时间与网络时间误差在几秒内,且每次请求随机串不重用。
可以,小布能直接拉取公开推文流并叠加在对应品种页面,你只需选好账号关键词,不用自己写接口。
设置轮询间隔不低于 30 秒,且只解析需要的字段,丢弃媒体与冗余元数据,能大幅降负载。
仅依赖内置 HTTP 与哈希函数能跑通基础推送与读取,但平台限流与接口变动可能导致偶发失败,属轻量辅助而非生产级方案。