Конференция "Сети" » работа с API биржи bittrex.com
 
  • tippa (30.08.14 22:00) [0]
    Добрый день.
    подскажите как в делфи купить что-то на бирже bittrex.com через апи?
    создал ключ API Keys, он состоит из 2 частей: Key и Secret.

    в документации [https://bittrex.com/Home/Api] указано, что купить можно с помощью запроса
    https://bittrex.com/api/v1.1/market/buymarket?apikey=API_KEY&market=BTC-LTC&quantity=1.2  
    собственно что нужно писать вместо API_KEY в этом запросе?
    использую Delphi7 и библиотеку Synapse.
  • junglecat (31.08.14 00:31) [1]
    судя по всему, apisecret нужен для подписи http-заголовка в запросе, apisign
  • tippa (31.08.14 08:07) [2]
    junglecat, да, я немного поразбирался, на странице апи есть пример использования ключа, насколько я понимаю - это PHP
    $apikey='xxx';
    $apisecret='xxx';
    $nonce=time();
    $uri='https://bittrex.com/api/v1.1/market/getopenorders?apikey='.$apikey.'&nonce='.$nonce;
    $sign=hash_hmac('sha512',$uri,$apisecret);
    $ch = curl_init($uri);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('apisign:'.$sign));
    $execResult = curl_exec($ch);
    $obj = json_decode($execResult);


    и главная загвозка в функции
    $sign=hash_hmac('sha512',$uri,$apisecret)


    где можно найти аналогичную функцию для делфи, или научите пользоваться гуглом, так как ничего путного найти не смог
  • brother © (31.08.14 08:34) [3]
  • tippa (31.08.14 21:56) [4]
    нашел в сети модуль для различных хэш функций, cHash.pas
    https://code.google.com/p/fundamentals/source/browse/trunk/Source/Utils/cHash.pas?r=30

    хэш находится верно, проверял на сторонних онлайн сервисах.
    Но биржа упорно возвращает ошибку, вроде все сделал по образцу из PHP-примера.

    var key, secret:string;
       url,sign:string;
       HTTP:THttpSend;
       Data:TStringStream;
       list:TStringList;
    begin
    key:='xxx';
    secret:='xxx';

    url:='https://bittrex.com/api/v1.1/account/getbalances?apikey='+key+'&nonce='+inttostr(DateTimeToUnix(now));
    sign:=SHA512DigestToHex(CalcHMAC_SHA512(secret, url));

    HTTP:=THttpSend.Create;
    Data := TStringStream.Create('');
    Data.WriteString('apisign:'+sign);
    Data.Position:=0;
    HTTP.Document.LoadFromStream(Data);
    Data.free;
    HTTP.HTTPMethod('GET','https://bittrex.com/api/v1.1/account/getbalances?apikey='+key);
    list:=TStringList.Create;
    list.LoadFromStream(HTTP.Document);
    showmessage(inttostr(HTTP.ResultCode)+#13#10+list.Text);
    list.Free;
    HTTP.Free;

    end;



    выдает
    200
    {"success":false,"message":"NONCE_NOT_PROVIDED","result":null}



    по ссылке выше через TIdHMACSHA512 тоже пробовал, но что-то на моей 7 делфи не хватает, например не работает функция StringOf для перевода TidBytes в строку. Пробовал колхозить через Chr() - какие-то кракозябры получаются. Но первый вариант же должен работать, что может быть не так?
  • junglecat (31.08.14 22:18) [5]
    а не так надо?
    HTTP.HTTPMethod('GET','https://bittrex.com/api/v1.1/account/getbalances?apikey='+key+'&nonce='+inttostr(DateTimeToUnix(now)));
  • tippa (01.09.14 08:17) [6]
    junglecat, да, вы правы. Исправил, но опять не хочет работать. Ниже поправленный код.
    var key, secret:string;
       url,sign:string;
       HTTP:THttpSend;
       Data:TStringStream;
       list:TStringList;
       nonce:string;
    begin
    key:='c446699bf07f438b9d95e6240f2ac504';
    secret:='d09f4a1ee901498f8c7d4fbc7af2fd2f';
    nonce:=inttostr(DateTimeToUnix(now));

    url:='https://bittrex.com/api/v1.1/account/getbalances?apikey='+key+'&nonce='+nonce;
    sign:=SHA512DigestToHex(CalcHMAC_SHA512(secret, url));

    HTTP:=THttpSend.Create;
    Data := TStringStream.Create('');
    Data.WriteString('apisign:'+sign);
    Data.Position:=0;
    HTTP.Document.LoadFromStream(Data);
    Data.free;
    HTTP.HTTPMethod('GET',url);
    list:=TStringList.Create;
    list.LoadFromStream(HTTP.Document);
    memo1.Lines.Add(inttostr(HTTP.ResultCode)+#13#10+list.Text);
    list.Free;
    HTTP.Free;

    end;


    ключи в примере реальные, для получения баланса их достаточно.
    теперь возвращает ответ в виде:
    200
    {"success":false,"message":"APISIGN_NOT_PROVIDED","result":null}



    не знаю куда еще копнуть, грешу на
    sign:=SHA512DigestToHex(CalcHMAC_SHA512(secret, url));


    хотя проверял её работу на сайте
    http://www.freeformatter.com/hmac-generator.html

    , результат сходится.
  • junglecat (01.09.14 09:23) [7]
    > [6] tippa   (01.09.14 08:17)

    видимо, apisign должен быть в заголовке http-запроса, а не в самом запросе
  • tippa (01.09.14 09:45) [8]

    > junglecat   (01.09.14 09:23) [7]

    о да, наконец-то, спасибо
    вот рабочий вариант если кому интересно
    var key, secret:string;
       url,sign:string;
       HTTP:THttpSend;
       list:TStringList;
       nonce:string;
    begin
    key:='xxx';
    secret:='xxx';
    nonce:=inttostr(DateTimeToUnix(now));

    url:='https://bittrex.com/api/v1.1/account/getbalances?apikey='+key+'&nonce='+nonce;
    sign:=SHA512DigestToHex(CalcHMAC_SHA512(secret, url));

    HTTP:=THttpSend.Create;
    HTTP.Headers.Add('apisign:'+sign);
    HTTP.HTTPMethod('GET',url);
    list:=TStringList.Create;
    list.LoadFromStream(HTTP.Document);
    memo1.Lines.Add(inttostr(HTTP.ResultCode)+#13#10+list.Text);
    list.Free;
    HTTP.Free;

    end;

  • rebelperm © (01.02.18 22:50) [9]
    Отличный код. Мне понравился.
    Сейчас как раз пишу программу и решил начать с запроса баланса.
    А ни кто не задавался написать подобные запросы к API на Delphi к другим биржам
    Cucoin или Cruptopia?
    Нашел проект на C# и на PHP, но толку переделать запрос баланса не хватает. :-(
  • rebelperm © (03.02.18 23:01) [10]
    const metod = 'GetBalance';
         //rq ='';
         rq ='CurrencyId:2';
    var key, secret:string;
      url,sign:string;
      HTTP:TidHTTP;
      list:TStringList;
      nonce:string;
      post_data : string;
      m : string;
      requestContentBase64String : string;
      signature : string;
      hmacsignature : string;
      header_value : string;
      headers : string;

     data: TIdMultiPartFormDataStream;

     begin
     key:='xxx';
     secret:='xxx';
     nonce:=inttostr(DateTimeToUnix(now));
    url:='https://www.cryptopia.co.nz/Api/'+metod;
    // url:='https://www.cryptopia.co.nz/Api/SubmitTrade';
    post_data:=rq;
    m:=md5(post_data);
    requestContentBase64String:=EncodeBase64(m);
    signature:=key + 'POST' + AnsiLowerCase(url) + nonce + requestContentBase64String;
    hmacsignature:= EncodeBase64(SHA256DigestToHexa(chash.CalcHMAC_SHA256(DecodeBase64(secret),signa ture)));
    header_value:= 'amx ' + key + ':' + hmacsignature + ':' + nonce;
    HTTP:=TidHTTP.Create;
    HTTP.IOHandler:=form1.IdSSLIOHandlerSocketOpenSSL1;
    HTTP.Request.CustomHeaders.Add('Authorization:'+ header_value);
    HTTP.Request.CustomHeaders.Add('Content-Type: application/json; charset=utf-8');
    HTTP.Request.URL:=url;
    data := TIdMultiPartFormDataStream.Create;
    data.AddFormField('CurrencyId', '2');
    form1.memo1.Text:=HTTP.post(url,data);   {}
    data.Free;
    HTTP.Free;
  • rebelperm © (03.02.18 23:01) [11]
    const metod = 'GetBalance';
         //rq ='';
         rq ='CurrencyId:2';
    var key, secret:string;
      url,sign:string;
      HTTP:TidHTTP;
      list:TStringList;
      nonce:string;
      post_data : string;
      m : string;
      requestContentBase64String : string;
      signature : string;
      hmacsignature : string;
      header_value : string;
      headers : string;

     data: TIdMultiPartFormDataStream;

     begin
     key:='xxx';
     secret:='xxx';
     nonce:=inttostr(DateTimeToUnix(now));
    url:='https://www.cryptopia.co.nz/Api/'+metod;
    // url:='https://www.cryptopia.co.nz/Api/SubmitTrade';
    post_data:=rq;
    m:=md5(post_data);
    requestContentBase64String:=EncodeBase64(m);
    signature:=key + 'POST' + AnsiLowerCase(url) + nonce + requestContentBase64String;
    hmacsignature:= EncodeBase64(SHA256DigestToHexa(chash.CalcHMAC_SHA256(DecodeBase64(secret),signa ture)));
    header_value:= 'amx ' + key + ':' + hmacsignature + ':' + nonce;
    HTTP:=TidHTTP.Create;
    HTTP.IOHandler:=form1.IdSSLIOHandlerSocketOpenSSL1;
    HTTP.Request.CustomHeaders.Add('Authorization:'+ header_value);
    HTTP.Request.CustomHeaders.Add('Content-Type: application/json; charset=utf-8');
    HTTP.Request.URL:=url;
    data := TIdMultiPartFormDataStream.Create;
    data.AddFormField('CurrencyId', '2');
    form1.memo1.Text:=HTTP.post(url,data);   {}
    data.Free;
    HTTP.Free;
  • Fernando Rizzato (14.02.18 20:31) [12]
    const
     apiKey: String = 'your apiKey';
     apiSecret: String = 'your apiSecret';
     requestURL: String = 'https://www.cryptopia.co.nz/Api/GetBalance';

    var
     FHTTPClient: THTTPClient;
     LPOSTRequest: IHTTPRequest;
     LResponse: IHTTPResponse;
     LHeaders: TNetHeaders;

     Data: TJSONObject;
     nonce: String;
     signature: String;
     hmacsignature: String;
     header_value: String;
     requestB64: String;
    begin
     Data := TJSONObject.Create;
     FHTTPClient := THTTPClient.Create;
     try
       // get the POST request
       LPOSTRequest := FHTTPClient.GetRequest('POST', requestURL);

       // Create the body request
       Data.AddPair(TJSONPair.Create('Currency', 'DOT'));
       LPOSTRequest.SourceStream := TStringStream.Create(Data.ToJSON);

       // Authentication
       requestB64 := TNetEncoding.Base64.EncodeBytesToString
         (THashMD5.GetHashBytes(Data.ToJSON));

       // Create random nonce for each request
       nonce := IntToStr(DateTimeToUnix(Now));

       // Creating the raw signature string
       signature := apiKey + 'POST' + LowerCase(TNetEncoding.URL.Encode(requestURL)
         ) + nonce + requestB64;

       hmacsignature := TNetEncoding.Base64.EncodeBytesToString
         (THashSHA2.GetHMACAsBytes(signature,
         TNetEncoding.Base64.DecodeStringToBytes(apiSecret)));

       header_value := 'amx ' + apiKey + ':' + hmacsignature + ':' + nonce;

       LHeaders := [
         TNetHeader.Create('Content-Type', 'application/json; charset=utf-8'),
         TNetHeader.Create('Authorization', header_value)];
       LResponse := FHTTPClient.Execute(LPOSTRequest, nil, LHeaders);

       memResult.Text := LResponse.ContentAsString;
     finally
       FHTTPClient.Free;
     end;​
  • albe © (24.04.18 01:27) [13]
    Существуют десятки языков программирования, которыми можно создать Бота – программу для получения доступа по API к своему счету на криптобирже и все они сводятся к одной идее. В некий «черный ящик» вводим несколько входных параметров:
    1. КЛЮЧ (получаем на сайте биржи); [a8a7ac9c2746496febfea43fd0906625]
    2. СЕКРЕТ (получаем на сайте биржи); [/pK9WVQxQc/ITOTJI67LWuXC2WH7/rkByu0ZaVdO0gJ=]
    3. WWW – адрес отправки запроса (получаем на сайте биржи); [https://www.cryptopia.co.nz/api/]
    4. МЕТОД (Запрос баланса, запрос истории, установка/удаление ордеров и т.п.); [GetBalance]
    5. ПАРАМЕТРЫ запроса (некие дополнения к методу). [Currency: BTC]
    Этот «черный ящик» обрабатывает наши запросы, шифрует, хеширует, кодирует, в общем, создает  правильные (понятные серверу биржи) абракадабровские строки. Затем отправляет их на сервер и возвращает нам, более менее понятный ответ на наш запрос. Так вот в этом черном ящике все так запутано и непонятно, а нигде толком не найти разъяснения. Самостоятельно поразбирался в этом с биржей CRIPTOPIA выяснил кое-что. Нужны методы хеширования MD5, Кодирования/Раскодирования методом Base64, шифрования методом HMAC-SHA256. Вот, как я понял, такая последовательность операций в «ченом ящике»:
    1. Хешируем ПАРАМЕТРЫ запроса методом MD5 - (S1). [e69aeb3fdec45a367dddc510e924fc02]
    2. Кодируем захешированные параметры (S1) методом Base64 - (S2). [ZTY5YWViM2ZkZWM0NWEzNjdkZGRjNTEwZTkyNGZjMDI=]
    3. Нумеруем свой запрос (S3), NONCE = количество секунд, от какой то там древней даты (тут все ясно). [1989294]
    4. Конструируем некую строку (S4) таким образом:
    S4=КЛЮЧ + "POST" + WWW+МЕТОД + S3 + S2; [a8a7ac9c2746496febfea43fd0906625POSThttps://www.cryptopia.co.nz/api/getbalance1989294ZTY5YWViM2ZkZWM0NWEzNjdkZGRjNTEwZTkyNGZjMDI=]
    5. Декодирую СЕКРЕТ методом Base64 (S5); [þ’½YT1AÏÈLäÉ#®ËZåÂÙa 1;þ¹ Êí iWNÒ ]
    6. Шифрую методом HMAC-SHA256 сконструированную строчку (S4) с помощью декодированного СЕКРЕТА (S5), получаю еще более непонятную строку (S6); [9353f8320d6f295a19051c7f75132bfb66b2ae64e9b08a6e803c1266ee39d182]
    7. Кодирую эту (S6) строку методом Base64, получаю (S7); [OTM1M2Y4MzIwZDZmMjk1YTE5MDUxYzdmNzUxMzJiZmI2NmIyYWU2NGU5YjA4YTZlODAzYzEyNjZlZTM 5ZDE4Mg==]
    8. Конструируем еще одну некую строку (S8) таким образом:
    S8= "amx" + КЛЮЧ + ":" + S7 + ":" + S3; [amxa8a7ac9c2746496febfea43fd0906625:OTM1M2Y4MzIwZDZmMjk1YTE5MDUxYzdmNzUxMzJiZmI 2NmIyYWU2NGU5YjA4YTZlODAzYzEyNjZlZTM5ZDE4Mg==:1989294]
    9. В компоненте POST-запроса (у меня в Delphi это TIdHTTP) в заголовок пишем 'authorization' и строку S7.
    IdHTTP1.Request.CustomHeaders.AddValue('authorization',S8);
    Все эти сложности, начиная с первого пункта, делались лишь для того, чтобы в заголовок нашей компоненты вписать эту сложнейшую строчку, которая позволит авторизоваться и получить доступ в нашему счету на бирже.
    10. Делаем запрос серверу биржи:
    Lin.Text:=IdHTTP1.Post(WWW,Par);
    Ответ сервера записан в переменную Lin и ответ этот, к моему глубокому сожалению,  все еще: {"Success":false,"Error":"Invalid authorization header."}.
    Подскажите, пожалуйста, где я неправ, что я упустил.
    СПАСИБО.
  • albe © (24.04.18 01:37) [14]
    УПС, Конечно же так правильно : Lin.Text:=IdHTTP1.Post(WWW+МЕТОД,ПАРАМЕТРЫ);
 
Конференция "Сети" » работа с API биржи bittrex.com
Есть новые Нет новых   [118478   +40][b:0][p:0.002]