Como escrever um cliente nativo Twitter para MetaTrader 4 e MetaTrader 5 sem usar DLL
Introdução
O Twitter é uma plataforma gratuita para troca pública de mensagens. O usuário pode escrever qualquer coisa, desde conselhos financeiros valiosos até opiniões pessoais de pessoas famosas e não tão famosas. Porém, neste artigo, não falaremos sobre o conteúdo, mas, sim, sobre a forma de trabalhar com tweets.
Em primeiro lugar, precisamos nos registrar para obter acesso ao conjunto de tokens necessários para trabalhar com a Tweeter API. No início, podemos nos confundir com esses tokens: há muitos e ainda por cima têm nomes semelhantes.
Em geral, precisamos dos seguintes tokens para usar a Twitter API:
- customer_token
- customer_token_secret
- access_token
- access_token_secret
Nota: será necessário saber como trabalhar com as chaves públicas e privadas usadas para assinatura digital.
Os primeiros dois tokens, customer_token e customer_token_secret, são apenas as chaves pública e privada para identificar nosso aplicativo Twitter. Em termos leigos, um aplicativo do Twitter é a identificação do nosso serviço e/ou acesso usando Twitter API.
Os tokens access_token e access_token_secret as chaves pública e privada para nos identificar como usuários do Twitter. Na linguagem do Twitter, isso é chamado de user auth ou user context. Com base nisso, a API access_token pode determinar quem a está acessando.
Há também outro token, bearer_token, com o qual podemos obter o chamado acesso anônimo usando a Twitter API. Este método de acesso é chamado app auth ou app context. Não é possível acessar algumas Twitter API sem o user context. Saiba mais sobre isso no guia online da Twitter API
Se sabe programar em outras linguagens, você pode usar as Bibliotecas do Twitter. Elas dão uma boa ideia sobre os detalhes de implementação que poderão não ser tão óbvios ao trabalhar apenas com a documentação da API.
Tweeter API e autorização
Usaremos os tokens mostrados acima:
- customer_token
- customer_token_secret
- access_token
- access_token_secret
No Youtube há muitas instruções e materiais de treinamento sobre como obter esses tokens.
OAuth é um padrão geralmente aceito e amplamente usado para autenticação e autorização de APIs da web, que também é usado pela Twitter API. Em termos simples, OAuth é uma assinatura digital, um método de assinatura de conteúdo digital que ao ser usado qualquer tentativa de manipular o conteúdo o invalida.
Para validar e assinar adequadamente o conteúdo, é necessário usar certos métodos e seguir o processo exato de criação desse conteúdo.
Todo o processo está bem documentado na documentação da Twitter API.
Twitter API exige um método de codificação específico de solicitações HTTP. Este método será descrito no próximo capítulo.
Codificação de URL e classificação de parâmetros
Para garantir que o conteúdo assinado digitalmente seja preciso, o próprio conteúdo deve ser claramente definido. Para isso, ao usar uma assinatura digital, a Twitter API (mais precisamente, o método OAuth) requer os parâmetros HTTP POST e/ou HTTP GET para concluir as etapas necessárias.
É imperativo codificar os parâmetros HTTP POST / HTTP GET assim:
- Todos os caracteres devem ser codificados em porcentagem (%XX), exceto os caracteres alfanuméricos (0-9, A-Z, a-z) e especiais ‘-‘, ‘.’, ‘_’, ‘~’.
- É necessário usar letras maiúsculas (0-9 ABCDEF) no valor hexadecimal de codificação percentual.
Para obter informações sobre como codificar corretamente os caracteres "%" e "+", leia o guia de referência e a documentação adicional.
Ademais, preste atenção à classificação de parâmetros especificados na documentação de referência:
- A especificação OAuth fala sobre classificação lexicográfica, que é a classificação alfabética padrão para muitas bibliotecas.
- Se duas chaves tiverem a mesma chave codificada, a especificação OAuth diz que será necessária uma classificação adicional com base no valor. No entanto, o Twitter não aceita chaves duplicadas em solicitações de API.
Implementação simples desse requisito:
string hex(int i) { static string h="0123456789ABCDEF"; string ret=""; int a = i % 16; int b = (i-a)/16; if(b>15) StringConcatenate(ret,ret,hex(b),StringSubstr(h,a,1)); else StringConcatenate(ret,ret,StringSubstr(h,b,1),StringSubstr(h,a,1)); return (ret); } string URLEncode(string toCode) { int max=StringLen(toCode); string RetStr=""; for(int i=0; i<max; i++) { string c = StringSubstr(toCode,i,1); ushort asc = StringGetCharacter(c, 0); if((asc >= '0' && asc <= '9') || (asc >= 'a' && asc <= 'z') || (asc >= 'A' && asc <= 'Z') || (asc == '-') || (asc == '.') || (asc == '_') || (asc == '~')) StringAdd(RetStr,c); else { StringConcatenate(RetStr,RetStr,"%",hex(asc)); } } return (RetStr); } string arrayEncode(string &array[][2]) { string ret=""; string key,val; int l=ArrayRange(array,0); for(int i=0; i<l; i++) { key = URLEncode(array[i,0]); val = URLEncode(array[i,1]); StringConcatenate(ret,ret,key,"=",val); if(i+1<l) StringConcatenate(ret,ret,"&"); } return (ret); } void sortParam(string&arr[][2]) { string k1, k2; string v1, v2; int n = ArrayRange(arr,0); // bubble sort int i, j; for(i = 0; i < n-1; i++) { // Last i elements are already in place for(j = 0; j < n-i-1; j++) { int x = j+1; k1 = arr[j][0]; k2 = arr[x][0]; if(k1 > k2) { // swap values v1 = arr[j][1]; v2 = arr[x][1]; arr[j][1] = v2; arr[x][1] = v1; // swap keys arr[j][0] = k2; arr[x][0] = k1; } } } } void addParam(string key,string val,string&array[][2]) { int x=ArrayRange(array,0); if(ArrayResize(array,x+1)>-1) { array[x][0]=key; array[x][1]=val; } }
Exemplo de uso das funções discutidas acima:
string params[][2]; addParam("oauth_callback", "oob", params); addParam("oauth_consumer_key", consumer_key, params); sortParam(params);
Atenção: para simplificar o código, a classificação aqui é incompleta, não leva em consideração os parâmetros de chaves idênticas. O código pode ser melhorado se você usar parâmetros com chaves idênticas. Por exemplo, é possível adicionar botões de opção ou caixas de seleção num formulário html.
Sobre o HMAC-SHA1 da maneira mais simples possível
Outro inconveniente ao criar uma assinatura OAuth é a falta de suporte integrado para HMAC-SHA1 em MQL. A função MQL CryptEncode() suporta apenas o algoritmo SHA1-HASH. A partir daqui obtemos o sinalizador: CRYPT_HASH_SHA1.
Bem, codifiquemos nosso HMAC-SHA1 com ajuda de CryptEncode()
string hmac_sha1(string smsg, string skey, uchar &dstbuf[]) { // Описание HMAC: // https://ru.wikipedia.org/wiki/HMAC // uint n; uint BLOCKSIZE=64; uchar key[]; uchar msg[]; uchar i_s[]; uchar o_s[]; uchar i_sha1[]; uchar keybuf[]; uchar i_key_pad[]; uchar o_key_pad[]; string s = ""; if((uint)StringLen(skey)>BLOCKSIZE) { uchar tmpkey[]; StringToCharArray(skey,tmpkey,0,StringLen(skey)); CryptEncode(CRYPT_HASH_SHA1, tmpkey, keybuf, key); n=(uint)ArraySize(key); } else n=(uint)StringToCharArray(skey,key,0,StringLen(skey)); if(n<BLOCKSIZE) { ArrayResize(key,BLOCKSIZE); ArrayFill(key,n,BLOCKSIZE-n,0); } ArrayCopy(i_key_pad,key); for(uint i=0; i<BLOCKSIZE; i++) i_key_pad[i]=key[i]^(uchar)0x36; ArrayCopy(o_key_pad,key); for(uint i=0; i<BLOCKSIZE; i++) o_key_pad[i]=key[i]^(uchar)0x5c; n=(uint)StringToCharArray(smsg,msg,0,StringLen(smsg)); ArrayResize(i_s,BLOCKSIZE+n); ArrayCopy(i_s,i_key_pad); ArrayCopy(i_s,msg,BLOCKSIZE); CryptEncode(CRYPT_HASH_SHA1, i_s, keybuf, i_sha1); ArrayResize(o_s,BLOCKSIZE+ArraySize(i_sha1)); ArrayCopy(o_s,o_key_pad); ArrayCopy(o_s,i_sha1,BLOCKSIZE); CryptEncode(CRYPT_HASH_SHA1, o_s, keybuf, dstbuf); for(int i=0; i < ArraySize(dstbuf); i++) StringConcatenate(s, s, StringFormat("%02x",(dstbuf[i]))); return s; }
Para verificar se o resultado é certo, comparemos com o hash gerado com base na documentação da Twitter API:
uchar hashbuf[]; string base_string = "POST&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fstatuses%2Fupdate.json&include_entities%3Dtrue%26oauth_consumer_key%3Dxvz1evFS4wEEPTGEFPHBog%26oauth_nonce%3DkYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1318622958%26oauth_token%3D370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb%26oauth_version%3D1.0%26status%3DHello%2520Ladies%2520%252B%2520Gentlemen%252C%2520a%2520signed%2520OAuth%2520request%2521"; string signing_key = "kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw&LswwdoUaIvS8ltyTt5jkRh4J50vUPVVHtR2YPi5kE"; string hash = hmac_sha1(base_string, signing_key, hashbuf); Print(hash); // 842b5299887e88760212a056ac4ec2ee1626b549 uchar not_use[]; uchar base64buf[]; CryptEncode(CRYPT_BASE64, hashbuf, not_use, base64buf); string base64 = CharArrayToString(base64buf); Print(base64); // hCtSmYh+iHYCEqBWrE7C7hYmtUk=
Solução via WebRequest
A função WebRequest() permite acessar qualquer interface REST API via Internet sem usar uma DLL externa. O código a seguir permite acessar a Twitter API com ajuda de WebRequest()
#define WEBREQUEST_TIMEOUT 5000 //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ string SendRequest(string method, string url, string headers="", string params="", int timeout=WEBREQUEST_TIMEOUT) { char data[]; char result[]; string resp_headers; ResetLastError(); StringToCharArray(params, data); ArrayResize(data, ArraySize(data)-1); int res = WebRequest(method, url, headers, timeout, data, result, resp_headers); if(res != -1) { string resp = CharArrayToString(result); if(verbose) { Print("***"); Print("Data:"); Print(CharArrayToString(data)); Print("Resp Headers:"); Print(resp_headers); Print("Resp:"); Print("***"); Print(resp); } return resp; } else { int err = GetLastError(); PrintFormat("* WebRequest error: %d (%d)", res, err); if(verbose) { Print("***"); Print("Data:"); Print(CharArrayToString(data)); } if (err == 4014) { string msg = "* PLEASE allow https://api.tweeter.com in WebRequest listed URL"; Print(msg); } } return ""; }
Certifique-se de verificar a documentação sobre WebRequest().
Para usar a função WebRequest(), é necessário adicionar os endereços dos servidores à lista de URL permitidos na guia "Experts" da janela "Configurações". A porta do servidor é selecionada automaticamente com base no protocolo especificado - 80 para "http://" e 443 para "https://".
Funções auxiliares para criar uma Twitter REST API
Essas funções auxiliares serão úteis ao criar uma assinatura da Twitter API.
string getNonce() { const string alnum = "abcdef0123456789"; char base[]; StringToCharArray(alnum, base); int x, len = StringLen(alnum); char res[32]; for(int i=0; i<32; i++) { x = MathRand() % len; res[i] = base[x]; } return CharArrayToString(res); } string getBase(string¶ms[][2], string url, string method="POST") { string s = method; StringAdd(s, "&"); StringAdd(s, URLEncode(url)); StringAdd(s, "&"); bool first = true; int x=ArrayRange(params,0); for(int i=0; i<x; i++) { if(first) first = false; else StringAdd(s, "%26"); // URLEncode("&") StringAdd(s, URLEncode(params[i][0])); StringAdd(s, "%3D"); // URLEncode("=") StringAdd(s, URLEncode(params[i][1])); } return s; } string getQuery(string¶ms[][2], string url = "") { string key; string s = url; string sep = ""; if(StringLen(s) > 0) { if(StringFind(s, "?") < 0) { sep = "?"; } } bool first = true; int x=ArrayRange(params,0); for(int i=0; i<x; i++) { key = params[i][0]; if(StringFind(key, "oauth_")==0) continue; if(first) { first = false; StringAdd(s, sep); } else StringAdd(s, "&"); StringAdd(s, params[i][0]); StringAdd(s, "="); StringAdd(s, params[i][1]); } return s; } string getOauth(string¶ms[][2]) { string key; string s = "OAuth "; bool first = true; int x=ArrayRange(params,0); for(int i=0; i<x; i++) { key = params[i][0]; if(StringFind(key, "oauth_")!=0) continue; if(first) first = false; else StringAdd(s, ", "); StringAdd(s, URLEncode(key)); StringAdd(s, "=\""); StringAdd(s, URLEncode(params[i][1])); StringAdd(s, "\""); } return s; }
Script de amostra
Agora é possível enviar a primeira solicitação Twitter API.
void verifyCredentials() { string _api_key = consumer_key; string _api_secret = consumer_secret; string _token = access_token; string _secret = access_secret; string url = "https://api.twitter.com/1.1/account/verify_credentials.json"; string params[][2]; addParam("oauth_consumer_key", _api_key, params); string oauth_nonce = getNonce(); addParam("oauth_nonce", oauth_nonce, params); addParam("oauth_signature_method", "HMAC-SHA1", params); string oauth_timestamp = IntegerToString(TimeGMT()); addParam("oauth_timestamp", oauth_timestamp, params); addParam("oauth_token", _token, params); addParam("oauth_version", "1.0", params); sortParam(params); string query = getQuery(params, url); string base = getBase(params, url, "GET"); uchar buf[]; string key = URLEncode(_api_secret); StringAdd(key, "&"); StringAdd(key, URLEncode(_secret)); uchar hashbuf[], base64buf[], nokey[]; string hash = hmac_sha1(base, key, hashbuf); CryptEncode(CRYPT_BASE64, hashbuf, nokey, base64buf); string base64 = CharArrayToString(base64buf); addParam("oauth_signature", base64, params); sortParam(params); string o = getOauth(params); 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"); string resp = SendRequest("GET", query, headers); Print(resp); // если все в порядке, мы получим JSON-ответ // {"id":122,"id_str":"122","name":"xxx","screen_name":"xxx123","location":"","description":"", ... }
Exemplo de cliente Twitter num gráfico do MetaTrader 5
A imagem abaixo mostra um cliente Twitter exibindo tweets a partir de um canal de notícias da Indonésia. No momento, estou preparando a publicação do seguinte artigo com una implementação adicional da Twitter API.
Figura 1. Exibindo tweets num gráfico
A seguinte imagem mostra a postagem de tweets a partir do terminal MetaTrader 5.
Fig. 2. Tweet postado a partir do terminal MetaTrader 5
Melhorias futuras
O método acima funciona bem, mas não cobre todas as funções da Twitter API. Esta é uma boa base para quem deseja aprender mais sobre a Tweeter API. No próximo artigo, veremos como postar no Twitter, incluindo capturas de tela de gráficos.
Será possível criar uma classe TwitterAPI ou até mesmo uma classe de cliente OAuth genérica.
Nota sobre autorização em três passos e baseada em PIN
Além disso, para trabalhar com o Twitter, podemos usar autorização em três passos e autorização de código PIN.
Fim do artigo
O Twitter é uma plataforma popular que permite a qualquer usuário postar quase de tudo. Espero que os artigos e o código que eles contêm sejam úteis para a comunidade MQL e ajudem você a entender o OAuth ao trabalhar com a Twitter API.
Aguardo seus comentários e sugestões. Você pode usar qualquer código deste artigo em seus projetos gratuitos e/ou pagos.
Quero agradecer ao usuário Grzegorz Korycki pela biblioteca (SHA256, SHA384 и SHA512 + HMAC - biblioteca para MetaTrader 4) que me inspirou a criar a função HMAC-SHA1.
Desejamos que os tweets tragam prazer e lucro!
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/8270
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso
Excelente Artigo! Muito bom! Vou poder implementar uma ideia com base nele.
Código simples e muito bem escrito, de fácil entendimento. Muito obrigado!