diff --git a/bfxapi/examples/ws/subscribe_tickers.py b/bfxapi/examples/ws/subscribe_tickers.py new file mode 100644 index 0000000..cc8daf9 --- /dev/null +++ b/bfxapi/examples/ws/subscribe_tickers.py @@ -0,0 +1,23 @@ +import os +import sys +sys.path.append('../../../') + +from bfxapi import Client + +bfx = Client( + logLevel='DEBUG' +) + +@bfx.ws.on('error') +def log_error(err): + print ("Error: {}".format(err)) + +@bfx.ws.on('new_ticker') +def log_candle(ticker): + print ("New ticker: {}".format(ticker)) + +async def start(): + await bfx.ws.subscribe('ticker', 'tBTCUSD') + +bfx.ws.on('connected', start) +bfx.ws.run() diff --git a/bfxapi/models/__init__.py b/bfxapi/models/__init__.py index 4da024e..a575991 100644 --- a/bfxapi/models/__init__.py +++ b/bfxapi/models/__init__.py @@ -16,5 +16,7 @@ from .notification import Notification from .transfer import Transfer from .deposit_address import DepositAddress from .withdraw import Withdraw +from .ticker import Ticker +from .funding_ticker import FundingTicker NAME = 'models' diff --git a/bfxapi/models/funding_ticker.py b/bfxapi/models/funding_ticker.py new file mode 100644 index 0000000..bd7d1ec --- /dev/null +++ b/bfxapi/models/funding_ticker.py @@ -0,0 +1,89 @@ +""" +Module used to describe all of the different data types +""" + +class FundingTickerModel: + """ + Enum used to index the different values in a raw funding ticker array + """ + FRR = 0 + BID = 1 + BID_PERIOD = 2 + BID_SIZE = 3 + ASK = 4 + ASK_PERIOD = 5 + ASK_SIZE = 6 + DAILY_CHANGE = 7 + DAILY_CHANGE_PERC = 8 + LAST_PRICE = 9 + VOLUME = 10 + HIGH = 11 + LOW = 12 + # _PLACEHOLDER, + # _PLACEHOLDER, + FRR_AMOUNT_AVAILABLE = 15 + +class FundingTicker: + """ + FRR float Flash Return Rate - average of all fixed rate funding over the last hour (funding tickers only) + BID float Price of last highest bid + BID_PERIOD int Bid period covered in days (funding tickers only) + BID_SIZE float Sum of the 25 highest bid sizes + ASK float Price of last lowest ask + ASK_PERIOD int Ask period covered in days (funding tickers only) + ASK_SIZE float Sum of the 25 lowest ask sizes + DAILY_CHANGE float Amount that the last price has changed since yesterday + DAILY_CHANGE_RELATIVE float Relative price change since yesterday (*100 for percentage change) + LAST_PRICE float Price of the last trade + VOLUME float Daily volume + HIGH float Daily high + LOW float Daily low + FRR_AMOUNT_AVAILABLE float The amount of funding that is available at the Flash Return Rate (funding tickers only) + """ + + def __init__(self, pair, frr, bid, bid_period, bid_size, ask, ask_period, ask_size, + daily_change, daily_change_perc, last_price, volume, high, low, frr_amount_avail): + self.pair = pair + self.frr = frr + self.bid = bid + self.bid_period = bid_period + self.bid_size = bid_size + self.ask = ask + self.ask_period = ask_period + self.ask_size = ask_size + self.daily_change = daily_change + self.daily_change_perc = daily_change_perc + self.last_price = last_price + self.volume = volume + self.high = high + self.low = low + self.frr_amount_available = frr_amount_avail + + @staticmethod + def from_raw_ticker(raw_ticker, pair): + """ + Generate a Ticker object from a raw ticker array + """ + # [72128,[6914.5,28.123061460000002,6914.6,22.472037289999996,175.8,0.0261,6915.7,6167.26141685,6964.2,6710.8]] + + return FundingTicker( + pair, + raw_ticker[FundingTickerModel.FRR], + raw_ticker[FundingTickerModel.BID], + raw_ticker[FundingTickerModel.BID_PERIOD], + raw_ticker[FundingTickerModel.BID_SIZE], + raw_ticker[FundingTickerModel.ASK], + raw_ticker[FundingTickerModel.ASK_PERIOD], + raw_ticker[FundingTickerModel.ASK_SIZE], + raw_ticker[FundingTickerModel.DAILY_CHANGE], + raw_ticker[FundingTickerModel.DAILY_CHANGE_PERC], + raw_ticker[FundingTickerModel.LAST_PRICE], + raw_ticker[FundingTickerModel.VOLUME], + raw_ticker[FundingTickerModel.HIGH], + raw_ticker[FundingTickerModel.LOW], + raw_ticker[FundingTickerModel.FRR_AMOUNT_AVAILABLE] + ) + + def __str__(self): + return "FundingTicker '{}' ".format( + self.pair, self.last_price, self.volume) diff --git a/bfxapi/models/ticker.py b/bfxapi/models/ticker.py new file mode 100644 index 0000000..bcd749e --- /dev/null +++ b/bfxapi/models/ticker.py @@ -0,0 +1,71 @@ +""" +Module used to describe all of the different data types +""" + +class TickerModel: + """ + Enum used to index the different values in a raw ticker array + """ + BID = 0 + BID_SIZE = 1 + ASK = 2 + ASK_SIZE = 3 + DAILY_CHANGE = 4 + DAILY_CHANGE_RELATIVE = 5 + LAST_PRICE = 6 + VOLUME = 7 + HIGH = 8 + LOW = 9 + +class Ticker: + """ + BID float Price of last highest bid + BID_SIZE float Sum of the 25 highest bid sizes + ASK float Price of last lowest ask + ASK_SIZE float Sum of the 25 lowest ask sizes + DAILY_CHANGE float Amount that the last price has changed since yesterday + DAILY_CHANGE_RELATIVE float Relative price change since yesterday (*100 for percentage change) + LAST_PRICE float Price of the last trade + VOLUME float Daily volume + HIGH float Daily high + LOW float Daily low + """ + + def __init__(self, pair, bid, bid_size, ask, ask_size, daily_change, daily_change_rel, + last_price, volume, high, low): + self.pair = pair + self.bid = bid + self.bid_size = bid_size + self.ask = ask + self.ask_size = ask_size + self.daily_change = daily_change + self.daily_change_rel = daily_change_rel + self.last_price = last_price + self.volume = volume + self.high = high + self.low = low + + @staticmethod + def from_raw_ticker(raw_ticker, pair): + """ + Generate a Ticker object from a raw ticker array + """ + # [72128,[6914.5,28.123061460000002,6914.6,22.472037289999996,175.8,0.0261,6915.7,6167.26141685,6964.2,6710.8]] + + return Ticker( + pair, + raw_ticker[TickerModel.BID], + raw_ticker[TickerModel.BID_SIZE], + raw_ticker[TickerModel.ASK], + raw_ticker[TickerModel.ASK_SIZE], + raw_ticker[TickerModel.DAILY_CHANGE], + raw_ticker[TickerModel.DAILY_CHANGE_RELATIVE], + raw_ticker[TickerModel.LAST_PRICE], + raw_ticker[TickerModel.VOLUME], + raw_ticker[TickerModel.HIGH], + raw_ticker[TickerModel.LOW], + ) + + def __str__(self): + return "Ticker '{}' ".format( + self.pair, self.last_price, self.volume) diff --git a/bfxapi/websockets/bfx_websocket.py b/bfxapi/websockets/bfx_websocket.py index bce9a0c..8eb0f99 100644 --- a/bfxapi/websockets/bfx_websocket.py +++ b/bfxapi/websockets/bfx_websocket.py @@ -12,7 +12,7 @@ from .subscription_manager import SubscriptionManager from .wallet_manager import WalletManager from .order_manager import OrderManager from ..utils.auth import generate_auth_payload -from ..models import Order, Trade, OrderBook +from ..models import Order, Trade, OrderBook, Ticker, FundingTicker class Flags: @@ -218,6 +218,8 @@ class BfxWebsocket(GenericWebsocket): await self._trade_handler(data) if subscription.channel_name == 'status': await self._status_handler(data) + if subscription.channel_name == 'ticker': + await self._ticker_handler(data) else: self.logger.warn( "Unknown data event: '{}' {}".format(dataEvent, data)) @@ -356,6 +358,17 @@ class BfxWebsocket(GenericWebsocket): else: self.logger.warn('Unknown status data type: {}'.format(data)) + async def _ticker_handler(self, data): + symbol = self.subscriptionManager.get(data[0]).symbol + if type(data[1]) is list: + raw_ticker = data[1] + t = None + if len(raw_ticker) == 10: + t = Ticker.from_raw_ticker(raw_ticker, symbol) + else: + t = FundingTicker.from_raw_ticker(raw_ticker, symbol) + self._emit('new_ticker', t) + async def _trade_handler(self, data): symbol = self.subscriptionManager.get(data[0]).symbol if type(data[1]) is list: