mirror of
https://github.com/aljazceru/bitfinex-api-py.git
synced 2025-12-20 15:24:21 +01:00
orderbook: use string values to generate checksum
This commit is contained in:
committed by
Jacob Plaster
parent
105c2f22df
commit
6ea571d468
@@ -3,6 +3,7 @@ Module used to describe all of the different data types
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import zlib
|
import zlib
|
||||||
|
import json
|
||||||
|
|
||||||
class OrderBook:
|
class OrderBook:
|
||||||
"""
|
"""
|
||||||
@@ -31,26 +32,37 @@ class OrderBook:
|
|||||||
"""
|
"""
|
||||||
return self.asks
|
return self.asks
|
||||||
|
|
||||||
def update_from_snapshot(self, data):
|
def update_from_snapshot(self, data, orig_raw_msg):
|
||||||
"""
|
"""
|
||||||
Update the orderbook with a raw orderbook snapshot
|
Update the orderbook with a raw orderbook snapshot
|
||||||
"""
|
"""
|
||||||
for order in data:
|
# we need to keep the original string values that are sent to use
|
||||||
if len(order) == 4:
|
# this avoids any problems with floats
|
||||||
if order[3] < 0:
|
orig_raw = json.loads(orig_raw_msg, parse_float=str, parse_int=str)[1]
|
||||||
|
zip_data = []
|
||||||
|
# zip both the float values and string values together
|
||||||
|
for index, order in enumerate(data):
|
||||||
|
zip_data += [(order, orig_raw[index])]
|
||||||
|
## build our bids and asks
|
||||||
|
for order in zip_data:
|
||||||
|
if len(order[0]) == 4:
|
||||||
|
if order[0][3] < 0:
|
||||||
self.bids += [order]
|
self.bids += [order]
|
||||||
else:
|
else:
|
||||||
self.asks += [order]
|
self.asks += [order]
|
||||||
else:
|
else:
|
||||||
if order[2] < 0:
|
if order[0][2] < 0:
|
||||||
self.asks += [order]
|
self.asks += [order]
|
||||||
else:
|
else:
|
||||||
self.bids += [order]
|
self.bids += [order]
|
||||||
|
|
||||||
def update_with(self, order):
|
def update_with(self, order, orig_raw_msg):
|
||||||
"""
|
"""
|
||||||
Update the orderbook with a single update
|
Update the orderbook with a single update
|
||||||
"""
|
"""
|
||||||
|
# keep orginal string vlues to avoid checksum float errors
|
||||||
|
orig_raw = json.loads(orig_raw_msg, parse_float=str, parse_int=str)[1]
|
||||||
|
zip_order = (order, orig_raw)
|
||||||
if len(order) == 4:
|
if len(order) == 4:
|
||||||
amount = order[3]
|
amount = order[3]
|
||||||
count = order[2]
|
count = order[2]
|
||||||
@@ -63,12 +75,12 @@ class OrderBook:
|
|||||||
|
|
||||||
# if first item in ordebook
|
# if first item in ordebook
|
||||||
if len(side) == 0:
|
if len(side) == 0:
|
||||||
side += [order]
|
side += [zip_order]
|
||||||
return
|
return
|
||||||
|
|
||||||
# match price level
|
# match price level but use the float parsed object
|
||||||
for index, s_order in enumerate(side):
|
for index, s_order in enumerate(side):
|
||||||
s_price = s_order[0]
|
s_price = s_order[0][0]
|
||||||
if s_price == price:
|
if s_price == price:
|
||||||
if count == 0:
|
if count == 0:
|
||||||
del side[index]
|
del side[index]
|
||||||
@@ -81,8 +93,8 @@ class OrderBook:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# add to book and sort lowest to highest
|
# add to book and sort lowest to highest
|
||||||
side += [order]
|
side += [zip_order]
|
||||||
side.sort(key=lambda x: x[0], reverse=not amount < 0)
|
side.sort(key=lambda x: x[0][0], reverse=not amount < 0)
|
||||||
return
|
return
|
||||||
|
|
||||||
def checksum(self):
|
def checksum(self):
|
||||||
@@ -93,17 +105,19 @@ class OrderBook:
|
|||||||
# take set of top 25 bids/asks
|
# take set of top 25 bids/asks
|
||||||
for index in range(0, 25):
|
for index in range(0, 25):
|
||||||
if index < len(self.bids):
|
if index < len(self.bids):
|
||||||
bid = self.bids[index]
|
# use the string parsed array
|
||||||
|
bid = self.bids[index][1]
|
||||||
price = bid[0]
|
price = bid[0]
|
||||||
amount = bid[3] if len(bid) == 4 else bid[2]
|
amount = bid[3] if len(bid) == 4 else bid[2]
|
||||||
data += [str(price)]
|
data += [price]
|
||||||
data += [str(amount)]
|
data += [amount]
|
||||||
if index < len(self.asks):
|
if index < len(self.asks):
|
||||||
ask = self.asks[index]
|
# use the string parsed array
|
||||||
|
ask = self.asks[index][1]
|
||||||
price = ask[0]
|
price = ask[0]
|
||||||
amount = ask[3] if len(ask) == 4 else ask[2]
|
amount = ask[3] if len(ask) == 4 else ask[2]
|
||||||
data += [str(price)]
|
data += [price]
|
||||||
data += [str(amount)]
|
data += [amount]
|
||||||
checksum_str = ':'.join(data)
|
checksum_str = ':'.join(data)
|
||||||
# calculate checksum and force signed integer
|
# calculate checksum and force signed integer
|
||||||
checksum = zlib.crc32(checksum_str.encode('utf8')) & 0xffffffff
|
checksum = zlib.crc32(checksum_str.encode('utf8')) & 0xffffffff
|
||||||
|
|||||||
@@ -98,13 +98,17 @@ class BfxWebsocket(GenericWebsocket):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, API_KEY=None, API_SECRET=None, host='wss://api.bitfinex.com/ws/2',
|
def __init__(self, API_KEY=None, API_SECRET=None, host='wss://api.bitfinex.com/ws/2',
|
||||||
manageOrderBooks=False, dead_man_switch=False, logLevel='INFO', *args, **kwargs):
|
manageOrderBooks=False, dead_man_switch=False, logLevel='INFO', parse_float=float,
|
||||||
|
*args, **kwargs):
|
||||||
self.API_KEY = API_KEY
|
self.API_KEY = API_KEY
|
||||||
self.API_SECRET = API_SECRET
|
self.API_SECRET = API_SECRET
|
||||||
self.manageOrderBooks = manageOrderBooks
|
self.manageOrderBooks = manageOrderBooks
|
||||||
self.dead_man_switch = dead_man_switch
|
self.dead_man_switch = dead_man_switch
|
||||||
self.pendingOrders = {}
|
self.pendingOrders = {}
|
||||||
self.orderBooks = {}
|
self.orderBooks = {}
|
||||||
|
# How should we store float values? could also be bfxapi.Decimal
|
||||||
|
# which is slower but has higher precision.
|
||||||
|
self.parse_float = parse_float
|
||||||
|
|
||||||
super(BfxWebsocket, self).__init__(
|
super(BfxWebsocket, self).__init__(
|
||||||
host, logLevel=logLevel, *args, **kwargs)
|
host, logLevel=logLevel, *args, **kwargs)
|
||||||
@@ -149,7 +153,7 @@ class BfxWebsocket(GenericWebsocket):
|
|||||||
self.logger.warn(
|
self.logger.warn(
|
||||||
"Unknown websocket event: '{}' {}".format(eType, msg))
|
"Unknown websocket event: '{}' {}".format(eType, msg))
|
||||||
|
|
||||||
async def _ws_data_handler(self, data):
|
async def _ws_data_handler(self, data, raw_message_str):
|
||||||
dataEvent = data[1]
|
dataEvent = data[1]
|
||||||
chan_id = data[0]
|
chan_id = data[0]
|
||||||
|
|
||||||
@@ -161,7 +165,7 @@ class BfxWebsocket(GenericWebsocket):
|
|||||||
if subscription.channel_name == 'candles':
|
if subscription.channel_name == 'candles':
|
||||||
await self._candle_handler(data)
|
await self._candle_handler(data)
|
||||||
if subscription.channel_name == 'book':
|
if subscription.channel_name == 'book':
|
||||||
await self._order_book_handler(data)
|
await self._order_book_handler(data, raw_message_str)
|
||||||
if subscription.channel_name == 'trades':
|
if subscription.channel_name == 'trades':
|
||||||
await self._trade_handler(data)
|
await self._trade_handler(data)
|
||||||
else:
|
else:
|
||||||
@@ -320,7 +324,7 @@ class BfxWebsocket(GenericWebsocket):
|
|||||||
data[1], subscription.symbol, subscription.timeframe)
|
data[1], subscription.symbol, subscription.timeframe)
|
||||||
self._emit('new_candle', candle)
|
self._emit('new_candle', candle)
|
||||||
|
|
||||||
async def _order_book_handler(self, data):
|
async def _order_book_handler(self, data, orig_raw_message):
|
||||||
obInfo = data[1]
|
obInfo = data[1]
|
||||||
chan_id = data[0]
|
chan_id = data[0]
|
||||||
subscription = self.subscriptionManager.get(data[0])
|
subscription = self.subscriptionManager.get(data[0])
|
||||||
@@ -345,24 +349,24 @@ class BfxWebsocket(GenericWebsocket):
|
|||||||
isSnapshot = type(obInfo[0]) is list
|
isSnapshot = type(obInfo[0]) is list
|
||||||
if isSnapshot:
|
if isSnapshot:
|
||||||
self.orderBooks[symbol] = OrderBook()
|
self.orderBooks[symbol] = OrderBook()
|
||||||
self.orderBooks[symbol].update_from_snapshot(obInfo)
|
self.orderBooks[symbol].update_from_snapshot(obInfo, orig_raw_message)
|
||||||
self._emit('order_book_snapshot', {
|
self._emit('order_book_snapshot', {
|
||||||
'symbol': symbol, 'data': obInfo})
|
'symbol': symbol, 'data': obInfo})
|
||||||
else:
|
else:
|
||||||
self.orderBooks[symbol].update_with(obInfo)
|
self.orderBooks[symbol].update_with(obInfo, orig_raw_message)
|
||||||
self._emit('order_book_update', {'symbol': symbol, 'data': obInfo})
|
self._emit('order_book_update', {'symbol': symbol, 'data': obInfo})
|
||||||
|
|
||||||
async def on_message(self, message):
|
async def on_message(self, message):
|
||||||
self.logger.debug(message)
|
self.logger.debug(message)
|
||||||
# convert float values to decimal
|
# convert float values to decimal
|
||||||
msg = json.loads(message, parse_float=Decimal)
|
msg = json.loads(message, parse_float=self.parse_float)
|
||||||
self._emit('all', msg)
|
self._emit('all', msg)
|
||||||
if type(msg) is dict:
|
if type(msg) is dict:
|
||||||
# System messages are received as json
|
# System messages are received as json
|
||||||
await self._ws_system_handler(msg)
|
await self._ws_system_handler(msg)
|
||||||
elif type(msg) is list:
|
elif type(msg) is list:
|
||||||
# All data messages are received as a list
|
# All data messages are received as a list
|
||||||
await self._ws_data_handler(msg)
|
await self._ws_data_handler(msg, message)
|
||||||
else:
|
else:
|
||||||
self.logger.warn('Unknown websocket response: {}'.format(msg))
|
self.logger.warn('Unknown websocket response: {}'.format(msg))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user