Obsługa prywatnego API BTC-e w Google Script

Jakiś czas temu pisałem, jak można podłączyć się przy pomocy publicznego API do różnych serwisów i pobrać dane do arkusza w Google Apps, oraz jak zrobić sobie na tej podstawie system powiadomień. Tym razem pokażę, jak zrobić coś bardziej zaawansowanego i połączyć się przy pomocy prywatnego api do konta w BTC-e. [Dodam, że bardzo podobnie sprawa wygląda w przypadku innych serwisów udostępniających prywatne API, np. pln.bitcurex.com, z tym że w przypadku bitcurexa w chwili obecnej API jest wyłączone.] Dzięki tej funkcjonalności można pobrać sobie swój stan konta, historię transakcji a także składać i modyfikować zlecenia a więc nawet zrobić sobie własnego bota transakcyjnego. Zacznijmy jednak od czegoś prostego.

Generowanie kluczy API

2013-12-10_1343Aby móc korzystać z prywatnego API, a więc takiego które ma dostęp do naszego konta, należy najpierw zacząć o wygenerowania kluczy. Jak ważne jest odpowiednie zabezpieczenie tych kluczy, chyba nie muszę pisać, ich utrata równoważna jest przekazaniem komuś kluczy do naszego konta.

Do generowania kluczy do prywatnego API służy odpowiednie menu znajdujące się na dole panelu zarządzania naszego konta. Wystarczy podać nazwę klucza (dowolna nazwa, która ułatwi nam identyfikację konkretnego klucza, nie ma ona znaczenia programistycznego) oraz kliknąć w guzik „create”.

Po wygenerowaniu kluczy powinie się on pojawić w postaci pokazanej na poniższym rysunku. Z lewej strony w kolumnie „Desc” mamy nazwę klucza, wartości z pól Key i Secret będą nam niezbędne do podłączenia się do API. W kolumnie „Perms” (zaznaczone na zielono) są wylistowane uprawnienia dla danego klucza (dostęp do informacji o koncie oraz wykonywanie transakcji, w tym przypadku zaznaczono tylko dostęp do informacji). Na samym końcu mamy kolumnę „Actions” pozwalającą na zapisanie zmian (domyślnie klucz nie ma żadnych uprawnień, więc trzeba zaznaczyć przynajmniej „info” i kliknąć „Save”) oraz skasowanie klucza.

2013-12-10_1352

Korzystanie z API

Uzbrojeni w klucz i secret możemy przystąpić do kodowania, wcześniej jednak wypadałoby się zapoznać z samym API udostępnianym przez BTC-e. Opis API znajduje się między innymi pod adresem: https://hdbtce.kayako.com/Knowledgebase/Article/View/26/4/trade-api-en. Są tam opisane wszystkie dostępne funkcje, jakie można wywołać. Analogiczny opis znajduje się na stronie: https://btc-e.com/api/documentation.  W tym momencie wypada wspomnieć, że w implementacji api transakcyjnego wzorowałem się na API znajdującym się na stronie: https://github.com/kidig/btc-e-google-script.

Jedną z prostszych rzeczy, jakie możemy zrobić przy pomocy API jest pobranie historii transakcji. Służy do tego funkcja TransHistory (nie mylić z TradeHistory!). Funkcja ta przyjmuje aż 7 opcjonalnych argumentów pozwalających określić od i do kiedy oraz od i do której transakcji chcemy pobrać dane, jednak w naszym przykładzie nie będą one potrzebne.

Zacznijmy więc od utworzenia nowego arkusza kalkulacyjnego i utworzenia skryptu (poprzednio opisywałem, jak to zrobić). W treści skryptu wpisujemy poniższy kod, oczywiście pamiętajmy o wprowadzeniu danych naszego własnego API w miejsca wypełnione XXX.

function bytes2hex(in_array) {
  var out_str = '';

  for (var i=0; i < in_array.length; i++) {
    var byte = in_array[i];
    if (byte < 0) byte += 256;

    var bytestr = byte.toString(16);
    if (bytestr.length == 1) bytestr = '0' + bytestr;

    out_str += bytestr;
  }

  return out_str;
}

function trade_api(method, params) {
  var url = 'https://btc-e.com/tapi';
  var api_key='92XXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX';
  var api_secret='91bXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';

  if (typeof(params) == 'undefined') params = {};

  var nonce = Math.round((new Date()).getTime() / 1000).toFixed(0);
  var query = [];

  query.push('nonce=' + nonce);
  query.push('method=' + method);

  for(var p in params) {
    query.push(p + "=" + params[p]);
  }

  var query_string = query.join("&");
  var sign = bytes2hex(Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_512, query_string, api_secret));

  var headers = {
    'Key': api_key,
    'Sign': sign
  };

  var options = {
    'headers': headers,
    'method': 'post',
    'payload': query_string
  };

  var res = UrlFetchApp.fetch(url, options);
  var raw_data = JSON.parse(res.getContentText());

  if (raw_data.success!=1) throw "trade_api "+method+" exception!";

  return raw_data;
}

function tradesToArray(objects) {
  var outputArray = [];
  for (var i in objects) {
    outputArray.push([Utilities.formatDate(new Date(objects[i].timestamp*1000), "GMT+1", "yyyy-MM-dd HH:mm:ss"), objects[i].amount, objects[i].desc, objects[i].status, objects[i].type, objects[i].currency]);
  }
  return outputArray;
}

function getTransHistory() {
  // Open spreadsheet
  var ss = SpreadsheetApp.getActiveSpreadsheet();

  var transHistory=trade_api("TransHistory");
  var transactions=tradesToArray(transHistory['return']);

  var range=ss.getSheets()[0].getRange(2,1,transactions.length,transactions[0].length);
  range.setValues(transactions);
}

Przygotujmy też odpowiednio nagłówek w naszym arkuszu aby nie zastanawiać się jakie dane są w której kolumnie.

2013-12-10_1555

Teraz już możemy uruchomić funkcję getTransHistory(), która powinna zapisać w pierwszym skoroszycie historię naszych transakcji. Jeśli jednak na górze pojawi się poniższy komunikat:2013-12-10_1557
to znaczy to najprawdopodobniej, że podaliśmy nieprawidłowy klucz, secret bądź nasz klucz nie ma wystarczających uprawnień.

Jeśli wszystko przebiegnie poprawnie, w pierwszym skoroszycie w naszym arkuszu pojawi się historia operacji. Jedna drobna uwaga: jeśli z jakiegoś powodu liczby w kolumnie z ilością nie są reprezentowane poprawnie (kropka zamiast przecinka, lub przecinek zamiast kropki – błąd ten pojawia się w zależności od ustawień regionalnych) można spróbować zamienić linię w funkcji tradesToArray() na jedną z poniższych:


outputArray.push([Utilities.formatDate(new Date(objects[i].timestamp*1000), "GMT+1", "yyyy-MM-dd HH:mm:ss"), (objects[i].amount.toString().replace(/\./,','))+0, objects[i].desc, objects[i].status, objects[i].type, objects[i].currency]);

lub


outputArray.push([Utilities.formatDate(new Date(objects[i].timestamp*1000), "GMT+1", "yyyy-MM-dd HH:mm:ss"), (objects[i].amount.toString().replace(/\,/,'.'))+0, objects[i].desc, objects[i].status, objects[i].type, objects[i].currency]);

Na koniec mała ściągawka dla typów transakcji:

1 – zasilenie konta
2 – wypłata z konta
3 – ???
4 – uznanie (wycofanie zlecenia oczekującego)
5 – obciążenie (zabezpieczenie za zlecenie oczekujące)

Poniżej przykładowe zlecenie oczekujące kupna LCT po 21.2 złożone 1 grudnia i wykonane 7-go. Najpierw rachunek USD jest obciążany kwotą 213.42, następnie mamy uznanie 10 na rachunku LTC (kupno 10.02 jednostek minus 0.2% prowizji).

2013-12-10_1627

Leave a Reply