Skip to main content

A unified crypto exchange websocket

Project description

UXS - Unified eXchange Streaming

A unified crypto exchange websocket

This free to use python library is ccxt based. I use it for personal trading and data feeds. Pull requests are welcome, although I'll yet have to make some sort of guide on how to implement new exchanges.

DISCLAIMER: Use it at your own risk! I take no responsibility for any losses occurred!

Installation (python 3.5.3+ required):

pip install --upgrade uxs

Latest development version:

pip install git+https://github.com/binares/uxs.git

Supported exchanges:

ticker all_tickers orderbook l3 ohlcv trades balance order fill position
binance + + + + + + + p
binancefu + + + + + + + p +
bitmex p + + p p + o o +
bittrex + + + + + + + +
bw + + + + + p p
coinbene + + + + + p p
coindcx p p + p + + p +
gateiofu + p
hitbtc + p + p p p + +
kraken + p + + + + +
krakenfu + p + p + + + + +
kucoin + + + p + + o o
luno p p w + p w p o o
poloniex p + + p p + + +
southxchange p p + p + p p

Note that there aren't separate subscription channels for balance, order, fill (your trade) and position - they all belong under account: xs.subscribe_to_account(). However some exchanges like bitmex require you to subscribe to each market directly for order and fill updates: xs.subscribe_to_own_market(symbol) (but you'll still want to also subscribe to account, as it contains balance and position updates).

+ - direct streaming
p - emulated via polling (fetch_balance, fetch_tickers etc)
w - emulated via streaming (l3 -> orderbook, l3 -> trades)
o - must be subscribed to own_market

Test environments are currently offered for: binancefu, bitmex, krakenfu and kucoin (kraken also offers some sort of non-sandboxed test env). For using them add {'test': True} to the config, and make sure you have created a sandbox account.

Simple usage:

import uxs
import asyncio

xs = uxs.binance({'apiKey': '', 'secret': ''})
xs.subscribe_to_orderbook('BTC/USDT')
# Subscribes to balance, order, fill and position updates
xs.subscribe_to_account()
xs.start()

asyncio.get_event_loop().run_forever()

ExchangeSocket

All exchange streamer classes inherit from uxs.ExchangeSocket. Note that uxs.ExchangeSocket itself isn't a subclass of ccxt.Exchange, i.e. uxs.binance !=~ ccxt.async_support.binance. Its corresponding (asynchronous) ccxt Exchange instance is accessible under .api: uxs.binance.api =~ ccxt.async_support.binance. The .api object's class is a wrapped one through, with some extra attributes added for caching data, rounding up/down, calculating payout and altering the markets data (e.g. for personalized fees).

ExchangeSocket does borrow some ccxt.async_support.Exchange methods: create_order, edit_order, cancel_order will normally evoke the same method of ccxt class, unless the exchange supports websocket trading (hitbtc). And fetch_ticker, fetch_tickers, fetch_order_book, fetch_ohlcv, fetch_trades, fetch_balance, fetch_order, fetch_orders, fetch_open_orders, fetch_closed_orders, which may in some cases be evoked through websocket.

The included examples show how to wait for updates, use callbacks, trade, cache fetch results and store tokens in a file / password encrypted file.

Subscriptions

# Subscribe

xs.subscribe_to_ticker(symbol)

xs.subscribe_to_all_tickers()

xs.subscribe_to_orderbook(symbol)

xs.subscribe_to_l3(symbol)

xs.subscribe_to_ohlcv(symbol, timeframe)

xs.subscribe_to_trades(symbol)

xs.subscribe_to_account()

xs.subscribe_to_own_market(symbol)

# Unsubscribe

xs.unsubscibe_to_{channel}(**params)

# Shortened

xs.sub_to_{channel}(**params)

xs.unsub_to_{channel}(**params)

# Dynamically

xs.subscribe_to({'_': channel, **params})

xs.unsubscribe_to({'_': channel, **params})

# Subscription object

s = xs.get_subscription({'_': channel, **params}) # for example {'_': 'orderbook', 'symbol': 'BTC/USDT'}
# or
s = xs.get_subscription((channel, *params)) # for example ('orderbook', 'BTC/USDT')

s.state # 0=inactive, 1=active

await s.wait_till_active() # wait till the subscription becomes active
# or
await xs.wait_till_subscription_active({'_': channel, **params})

Data structures

These are attributes of ExchangeSocket instance (xs). The objects in these dicts are equivalent to those of ccxt.Exchange (except for position, which isn't yet implemented by ccxt).

xs.tickers[symbol]

xs.orderbooks[symbol]

xs.l3_books[symbol]

xs.ohlcv[symbol][timeframe]

xs.trades[symbol]

xs.balances[currency]

xs.orders[order_id]

xs.open_orders[order_id]

xs.fills[order_id]

xs.positions[symbol]

An order also contains 'payout' keyword, which is the current received amount in target currency.

The structures are updated on spot. Bids/asks are inserted directly into the existing list, dict values are updated but the dict objects' id never changes. That includes all sub-level dicts (orders, fills, ...), and even the 'info' dicts (but not the other dicts like 'fee': {'cost': .. , 'currency': ..}). So for any time spanning operation (await create_order()), or if you're accessing the data from another thread, there is a real possibility that the dict has been updated in the meanwhile. To ensure that you'll still have access to the old values, make a (deep)copy of the structure before. Also avoid looping over a structure while for example creating an order (in the loop), as the dict/list size might change, and python throws an error (in dict case).

# Do NOT do this:
for o in xs.open_orders.values():
    await xs.cancel_order(o['id'], o['symbol'])

# Instead:
for o in list(xs.open_orders.values()):
    await xs.cancel_order(o['id'], o['symbol'])

Note that once a subscription feed is lost/unsubbed, the associated real-time data is automatically deleted. This it to prevent the user using outdated data, and by default includes these channels: all_tickers, ticker, orderbook. E.g. once ('orderbook', 'ETH/BTC') is lost, xs.orderbooks['ETH/BTC'] is deleted. Account relevant data is not deleted, as you might want to cancel the orders / close the positions.

To change it initiate an exchange like this:

# specific channel
uxs.binance({'channels': {'orderbook': {'delete_data_on_unsub': False}}})

Wait on stream event

# See example c / docstring for description
await xs.wait_on(stream, id=-1)

Add stream event callback

# See example d for description
xs.add_callback(cb, stream, id=None)

xs.create_order

xs.create_order automatically rounds the price down for buy orders, and up for sell orders. The amount is also rounded, always down.

Logging

Initialize with verbose value

  • 0.5 - create/edit/cancel order
  • 1 - connection, subscription, send, fetch/polling events + above
  • 2 - ping + some inner mechanisms + above
  • 3 - recv events + above

depending on how detailed log you want. Unexpected errors (not connectivity related) are logged in any case.

uxs.binance({'verbose': 1})

If you just want to see recv output without including 0.5, 1 and 2, init with

uxs.binance({'connection_defaults': {'handle': print}})

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

uxs-0.6.1.tar.gz (191.8 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page