-
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; -
Отличный код. Мне понравился.
Сейчас как раз пишу программу и решил начать с запроса баланса.
А ни кто не задавался написать подобные запросы к API на Delphi к другим биржам
Cucoin или Cruptopia?
Нашел проект на C# и на PHP, но толку переделать запрос баланса не хватает. :-( -
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; -
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; -
Существуют десятки языков программирования, которыми можно создать Бота – программу для получения доступа по 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."}.
Подскажите, пожалуйста, где я неправ, что я упустил.
СПАСИБО. -
УПС, Конечно же так правильно : Lin.Text:=IdHTTP1.Post(WWW+МЕТОД,ПАРАМЕТРЫ);