Ismerkedés a Bittrex API-val [Python]

Bár kétségtelenül epic jó a kraken api-ja, ellenben a kraken konzervativitása a támogatott coin párok kapcsán már koránts sem tekinthető elégségesnek. Ennek okán elkezdtem kalandozásom a Bittrex API-jával. Api dokumentációt itt találjátok: -link-. Az általam használt python library-t pedig itt: -link-

Ez a cikk a korábban már elkezdett “CryptoCulture: A programozási mint alap nyelvtudás” cikksorozat folytatása. Ezúttal a post végén már egy automata limitáras vásárló robot szerűséget is bemutatok.

Nezzünk egyből az elején egy nagyon egyszerű példát:

#!/usr/bin/python3
import json
from bittrex.bittrex import Bittrex

sf = open("secrets.json")
secrets = json.load(sf)
sf.close()
bt = Bittrex(secrets['key'], secrets['secret'])

actual = bt.get_balance('BTC')
print(actual)

A kód futtatásához létre kell hozni egy secrets.json file-t, amibe be kell rakni az API és secret key-t. Ezt követően a program máris visszaadja az elvárt outputot: “{‘message’: ”, ‘success’: True, ‘result’: {‘CryptoAddress’: None, ‘Currency’: ‘BTC’, ‘Balance’: X.X, ‘Available’: X.X, ‘Pending’: 0.0}}

A get_balance(‘XXX’) helyett a get_balances api call ugyanezen struktúrában visszaadja az összes valaha bírtokolt coin egyenlegét, tehát itt az eredményben fogod látni a nullás egyenlegű tételeket is, amikből valaha rendelkeztél akár egy minimális mennyiséggel.

Nézzünk egy egyenleget és hozzá a 24 órás árfolyam változást:

#!/usr/bin/python3
import json
from bittrex.bittrex import Bittrex

sf = open("secrets.json")
secrets = json.load(sf)
sf.close()
bt = Bittrex(secrets['key'], secrets['secret'])

balances = bt.get_balances()
marketsum = bt.get_market_summaries();
for i in balances['result']:
   if i['Balance'] >0:
      _market = [];
      for j in marketsum['result']:
        if "BTC-"+i['Currency'] == j['MarketName']: _market = j;
      if ('Last' in _market):
        print(i['Currency']," balance: %.6f" % (i['Balance']), " 24h chg: %.02f%%"% (((_market['Last']/_market['PrevDay'])-1)*100));

Nem tudom, ki hogy van vele, de számomra képtelenség követni bittrexen azt, hogy a korábbi ordereim éppen milyen hozamban állnak, tehát, hogy ténylegesen mennyi a profitom az adott fundamentumban. Erre egy egyszerű megoldás:

#!/usr/bin/python3

import json
from bittrex.bittrex import Bittrex


sf = open("secrets.json")
secrets = json.load(sf)
sf.close()
bt = Bittrex(secrets['key'], secrets['secret'])

balances = bt.get_balances()
marketsum = bt.get_market_summaries();
orderhistory = bt.get_order_history();
for i in balances['result']:
   if i['Balance'] >0:
      _market = [];
      _btc_price = 0;
      _eth_price = 0;
      for j in marketsum['result']:
        if "BTC-"+i['Currency'] == j['MarketName']:
          _market = j;
          _btc_price = j['Last'];
        if "ETH-"+i['Currency'] == j['MarketName']:
          _eth_price = j['Last'];

      if ('Last' in _market):
        print(i['Currency']," balance: %.6f " % (i['Balance']), " 24h chg: %.02f%% (btc: %.08f, eth: %.06f)"% ((((_market['Last']/_market['PrevDay'])-1)*100),_btc_price, _eth_price));
        _sum_profit_btc = 0.0
        _sum_profit_eth = 0.0
        _chg = 0.0
        _s = 0;
        for j in orderhistory['result']:
              _match = 0
              if "BTC-"+i['Currency'] in j["Exchange"] and _s == 0:
                _sum_profit_btc = _sum_profit_btc + ((_btc_price- j['PricePerUnit'])*j['Quantity'])
                _chg = ((_btc_price/j['PricePerUnit']-1)*100)
                _match = 1
              if "ETH-"+i['Currency'] in j["Exchange"] and _s==0:
                _sum_profit_eth = _sum_profit_eth + ((_eth_price- j['PricePerUnit'])*j['Quantity'])
                _chg = ((_eth_price/j['PricePerUnit']-1)*100)
                _match = 1
              if _match==1:
                if (j['OrderType'] == "LIMIT_SELL"):
                  _s = 1
                else:
                  print (" - %s %s %s %.06f %.06f (chg: %.06f%%)" %(j['TimeStamp'], j["Exchange"], j['OrderType'], j['Quantity'], j['PricePerUnit'], _chg))
        print(">>>Profit: btc: %.08f, eth: %.04f" % (_sum_profit_btc, _sum_profit_eth))

Maga a kód egy picit suta, mert simán csak a legutolsó SELL-ig nézi vissza a historikus ordereket, ezen kis munkával lehetne javítani egy siman gördülő balance számítással, de ezt most nem raktam bele, így is hosszú lett a kód, aminek egyébként az eredménye valahogy így néz ki:

MCO  balance: XXXX.726567   24h chg: 35.53% (btc: 0.00487899, eth: 0.061500)
 - 2017-08-27T12:09:58.037 ETH-MCO LIMIT_BUY XXX.X26567 0.046407 (chg: 32.523609%)
>>>Profit: btc: 0.00000000, eth: XX.X430
OMG  balance: XXXX.482398   24h chg: 1.12% (btc: 0.00192001, eth: 0.024022)
 - 2017-08-27T20:09:22.41 BTC-OMG LIMIT_BUY XXX.000000 0.001897 (chg: 1.220438%)
 - 2017-08-25T11:19:49.37 ETH-OMG LIMIT_BUY XXX.106759 0.024685 (chg: -2.687224%)
 - 2017-08-25T11:22:03.783 BTC-OMG LIMIT_BUY XXX.375639 0.001887 (chg: 1.733703%)
 - 2017-08-14T09:31:56.617 ETH-OMG LIMIT_BUY XXX.000000 0.021980 (chg: 9.288490%)
>>>Profit: btc: X.XXX24379, eth: XX.X203

A ‘példa’ szerint OMG-ben csak bénázok, de MCO-ban szépen elkaptam a felugrót 🙂

Az eddigi példák lekéréseket végeztem. Nézzünk egy ordert, legyen mondjuk egy BTC-LBC páron történő vásárlás. Mivel a bittrex sem a felületen, sem API-n keresztül nem támogatja június közepe óta az marketprice vásárlást, ezért ennek a kódja egy kicsit összetettebb:

#!/usr/bin/python3
import json
import time
import sys
from bittrex.bittrex import Bittrex

sf = open("secrets.json")
secrets = json.load(sf)
sf.close()
bt = Bittrex(secrets['key'], secrets['secret'])

_ticker = ""
_amount = 0.0
_limit = 0

if (len(sys.argv) <4 ):
   print ("Use the correct parameter: %s --ticker BTC-LBC --amount 999 [--limit 0.00999]" % (sys.argv[0]))

for i in range(0,len(sys.argv)):
   if sys.argv[i] == "--ticker": _ticker = sys.argv[i+1]
   if sys.argv[i] == "--amount": _amount = float(sys.argv[i+1])
   if sys.argv[i] == "--limit": _limit = float(sys.argv[i+1])

if (_ticker == "" and _amount == 0):
   print("Missing amount or ticker parameter")
   sys.exit(0)


_order = [];
_round = 0;
_l_notif = True;
while True:
     last=[];
     last = bt.get_ticker(_ticker)
     if( 'success' not in last or last['success'] != True):
        print("Invalid JSON response from bittrex (Get_ticker):"+ ",".join(last['message']));
        continue
     if (last['result']['Last'] < _limit):
        if _l_notif == True:
           print("Price is under the preset limit, standby");
           _l_notif = False
        time.sleep(2);
        print('.',end='', flush=True);
        continue
     else:
        _l_notif=True;
     if(_order == []):
        _order=bt.buy_limit(_ticker, _amount, (last['result']['Bid']+(1.0/10**8)))
        if (_order['success'] != True):
           print(_order);
        else:
           print(_ticker, " order has been placed. market: %.08f %.08f %.08f" % (last['result']['Bid'],last['result']['Ask'],last['result']['Last']))
           print(" - Order details: ", _order['result'])
     else:
        _op_ords=bt.get_open_orders(_ticker);
        if len(_op_ords['result']) == 0:
           print("done...")
           #Order finished...
           break;
        else:
           _found=0;
           for i in _op_ords['result']:
                if (i['OrderUuid'] == _order['result']['uuid']):
                   _found=1;
                   _amount = i['QuantityRemaining']
                   if (float(last['result']['Bid']) > float(i['Limit'])):
                     print("Overbid! Cancel and replace order [new best: %.08f, old: %.08f]" % (last['result']['Bid'], i['Limit']))
                     _cancel = bt.cancel(_order['result']['uuid'])
                     if _cancel['success'] == True: _order=[];
           if (_found == 0):
               print("done...");
               break;
     time.sleep(1)

Nem mondom, hogy szép a kód, de kb mindent tud amivel a lehető legolcsóbban tudunk megvenni akármilyen coint:

  • Folyamatosan overbideli a legjobb ajánlatot az orderbookban.
  • Tartalmaz egy “–limit” paramétert, amivel meg tudsz adni egy árszintet ami felett kezdjen el csak venni, így pl beállítható, hogy az adott assetből csak akkor vegyen, ha annak az árfolyama felfelé áttör egy bizonyos szintet.
  • Figyeli a részleges vételeket és következő ordert már a csökkentett (remaining) mennyiséggel adja fel.

A kód addig fut amíg meg nem vesz az adott coinból annyit, amennyit megadsz neki paraméterben, vagy le nem lövöd a scriptet, ha kézzel (Ctrl+C) állítod le, akkor figyelj oda, mert bent maradhat az utolsó order amit berakot, ezt ilyenkor kézzel kell cancelezni.

commercial break...

Bookmark the permalink.

11 Comments

  1. Bittrexen a megbízás után akkor is levonja a jutalékot, ha visszavonom. Ez elég mocsok dolog. Sehol máshol nem találkoztam még ezzel.
    Erről jutott eszembe: “Folyamatosan overbideli a legjobb ajánlatot az orderbookban.”
    Ezt miként oldják meg a “nagyok”? Hiszen ad egy megbízást, visszavonja és rálicitál a másikra. Ez sok-sok apró kis százalék kiadás.

    • Ez egy széles körben elterjedt tévhit a bittrex kapcsán, nagyon sok helyen találkoztam már ezzel. A bittrex ezt írja a trading commisionről:
      “Trades – All trades are charged .25% of the profits of the trade. This is calculated by taking the (amount * purchase price * .0025). Any portion of an order that has not execute, will be refunded fully upon the cancellation of the order.” (forrás)

      Szóval valóban levonja a fee-t az ordernél is, azonban ha cancelezed azt akár egészben akár részben, akkor visszakapod a nem teljesült tételekre jutó fee-t.

      Szóval nyugodt szívvel mehet az overbid cancel/replace order.

  2. CRYPTOPRESENCE: A bittrex biztosan nem vonja le a canceled order után a jutalékot! Ezt magad is ellenőrizheted pár kattintással.

    Variance: egyébként vicces, de én is pár napja kezdtem el játszani a dologgal, nodejs alapon. Nem tudom hogy az include-olt bittrex python lib mit használ, de ha a dokumentált hivatalos Bittrex API-t hívogatja, akkor azzal nem árt vigyázni, mert rate limit van rajta, könnyen repülhet a ban. Sajnos nincs róla egzakt infó, hogy ez mikor következik be, másodkézből lehet olvasni olyanokat hogy a support szerint 1/perc nem gond, de hogy mennyitől “gond”, arról nincs infó.

    Én úgy csinálom, hogy a market adatokat websocketen kérdezem le (ezt használja a bittrex webgui is a böngészőben). Tök jó, mert amolyan broadcast szerű a dolog, már-már realtime. Ha pedig esemény van (buy/sell order elhelyezés) akkor hívom csak a http get alapú api-t.

    • Ezek merint csak elavult információk, márhogy a rate limit kapcsán. Még 2014-ben bevezetett a bittrex egy eléggé zord bot/rate-limit rendszert, ami valóban úgy működött, ahogy fenetebb írod, azonban idén év közepe óta már a következő szabályok érvényesek csak:
      “We are currently restricting orders to 500 open orders and 200,000 orders a day.”

      Tehát maximum 500 nyitott ordered lehet egy időben és naponta maximum 200000 ordert kezdeményezhetsz. Ha az utóbbit átléped, akkor valóban banolnak, de csak az adott napra. Egyébként az 200000 order meglátásom szerint bőven elegendő akár egy bot számára is.

      A websocketes ötlet nagyon jó, implementálni fogom azt is a saját tooljaimban! köszi.

      • Ezt láttam én is, csak egy kicsit túlbonyolítottam szerintem. Mert arra gondoltam, hogy az egyéb API hívások kapcsán (balance/order/market státusz és history lekérdezés) talán nem szeretik ha rájuk zúdítok percenként 10-15-öt. Viszont igazad lehet, ha 200.000 ordert engednek nyitni (ami lényegében 1db ugyanilyen api hívás) akkor valószínűleg ez a probléma tárgytalan.

  3. variance > kösz a bch tippet, dobtam.. durva hogy 810-en tudtam eladni pár napja..
    XRP hogy megindult.. ki gondolta volna.. 😀

    0 tudásunak tudtok segiteni? vagy link is jó a szükséges infokkal, amikből össze tudom rakni a problémára a megoldást
    felraktam win-re pythont, 3.5.4,a libek(?) hiánya miatt balhézik. pl import json

    • Van egy nagyon jól összerakott Python IDE mind windowsra, mind mac-ra, csak ajánlani tudom azoknak akik játszani akarnak ezzel: Anaconda Python a continuum.io-tól. Minden library benne van amire szerintem szükségetek lehet és könnyedén lehet hozzárakni extra libraryket is. Amiket ide a blogra felrakok plédákat azokat én simán AWS linuxon kódolom és futtatom, de szerintem a legtöbb kód minden gond nélkül futtatható anaconda-val is.

  4. én nagyon kezdő vagyok ezen a téren, de az a gondom, hogy amire azt írtad, hogy “egy nagyon egyszerű példa” és azt lefuttatom pyton-ban, rögtön egy olyan hibaüzenettel kiakad, hogy: ‘ModuleNotFoundError: No module named ‘bittrex’

    mi az, amit már a legelején elrontok?

  5. Megkérdezhetem, hogy volt kimondott tutorial amit használtál segítségül, vagy a hivatalos bittrex api alapján kezdtél bele?

Szólj hozzá: