# -*- coding: utf-8 -*- # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN: # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code import ccxt.async_support from ccxt.async_support.base.ws.cache import ArrayCache from ccxt.base.types import Any, Int, OrderBook, Trade from ccxt.async_support.base.ws.client import Client from typing import List from ccxt.base.errors import NotSupported from ccxt.base.errors import ChecksumError class independentreserve(ccxt.async_support.independentreserve): def describe(self) -> Any: return self.deep_extend(super(independentreserve, self).describe(), { 'has': { 'ws': True, 'watchBalance': False, 'watchTicker': False, 'watchTickers': False, 'watchTrades': True, 'watchTradesForSymbols': False, 'watchMyTrades': False, 'watchOrders': False, 'watchOrderBook': True, 'watchOHLCV': False, }, 'urls': { 'api': { 'ws': 'wss://websockets.independentreserve.com', }, }, 'options': { 'watchOrderBook': { 'checksum': True, # TODO: currently only working for snapshot }, }, 'streaming': { }, 'exceptions': { }, }) async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]: """ get the list of most recent trades for a particular symbol :param str symbol: unified symbol of the market to fetch trades for :param int [since]: timestamp in ms of the earliest trade to fetch :param int [limit]: the maximum amount of trades to fetch :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict[]: a list of `trade structures ` """ await self.load_markets() market = self.market(symbol) symbol = market['symbol'] url = self.urls['api']['ws'] + '?subscribe=ticker-' + market['base'] + '-' + market['quote'] messageHash = 'trades:' + symbol trades = await self.watch(url, messageHash, None, messageHash) return self.filter_by_since_limit(trades, since, limit, 'timestamp', True) def handle_trades(self, client: Client, message): # # { # "Channel": "ticker-btc-usd", # "Nonce": 130, # "Data": { # "TradeGuid": "7a669f2a-d564-472b-8493-6ef982eb1e96", # "Pair": "btc-aud", # "TradeDate": "2023-02-12T10:04:13.0804889+11:00", # "Price": 31640, # "Volume": 0.00079029, # "BidGuid": "ba8a78b5-be69-4d33-92bb-9df0daa6314e", # "OfferGuid": "27d20270-f21f-4c25-9905-152e70b2f6ec", # "Side": "Buy" # }, # "Time": 1676156653111, # "Event": "Trade" # } # data = self.safe_value(message, 'Data', {}) marketId = self.safe_string(data, 'Pair') symbol = self.safe_symbol(marketId, None, '-') messageHash = 'trades:' + symbol stored = self.safe_value(self.trades, symbol) if stored is None: limit = self.safe_integer(self.options, 'tradesLimit', 1000) stored = ArrayCache(limit) self.trades[symbol] = stored trade = self.parse_ws_trade(data) stored.append(trade) self.trades[symbol] = stored client.resolve(self.trades[symbol], messageHash) def parse_ws_trade(self, trade, market=None): # # { # "TradeGuid": "2f316718-0d0b-4e33-a30c-c2c06f3cfb34", # "Pair": "xbt-aud", # "TradeDate": "2023-02-12T09:22:35.4207494+11:00", # "Price": 31573.8, # "Volume": 0.05, # "BidGuid": "adb63d74-4c02-47f9-9cc3-f287e3b48ab6", # "OfferGuid": "b94d9bc4-addd-4633-a18f-69cf7e1b6f47", # "Side": "Buy" # } # datetime = self.safe_string(trade, 'TradeDate') marketId = self.safe_string(market, 'Pair') return self.safe_trade({ 'info': trade, 'id': self.safe_string(trade, 'TradeGuid'), 'order': self.safe_string(trade, 'orderNo'), 'symbol': self.safe_symbol(marketId, market, '-'), 'side': self.safe_string_lower(trade, 'Side'), 'type': None, 'takerOrMaker': None, 'price': self.safe_string(trade, 'Price'), 'amount': self.safe_string(trade, 'Volume'), 'cost': None, 'fee': None, 'timestamp': self.parse8601(datetime), 'datetime': datetime, }, market) async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook: """ watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data :param str symbol: unified symbol of the market to fetch the order book for :param int [limit]: the maximum amount of order book entries to return :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: A dictionary of `order book structures ` indexed by market symbols """ await self.load_markets() market = self.market(symbol) symbol = market['symbol'] if limit is None: limit = 100 limitString = self.number_to_string(limit) url = self.urls['api']['ws'] + '/orderbook/' + limitString + '?subscribe=' + market['base'] + '-' + market['quote'] messageHash = 'orderbook:' + symbol + ':' + limitString subscription: dict = { 'receivedSnapshot': False, } orderbook = await self.watch(url, messageHash, None, messageHash, subscription) return orderbook.limit() def handle_order_book(self, client: Client, message): # # { # "Channel": "orderbook/1/eth/aud", # "Data": { # "Bids": [ # { # "Price": 2198.09, # "Volume": 0.16143952, # }, # ], # "Offers": [ # { # "Price": 2201.25, # "Volume": 15, # }, # ], # "Crc32": 1519697650, # }, # "Time": 1676150558254, # "Event": "OrderBookSnapshot", # } # event = self.safe_string(message, 'Event') channel = self.safe_string(message, 'Channel') parts = channel.split('/') depth = self.safe_string(parts, 1) baseId = self.safe_string(parts, 2) quoteId = self.safe_string(parts, 3) base = self.safe_currency_code(baseId) quote = self.safe_currency_code(quoteId) symbol = base + '/' + quote orderBook = self.safe_dict(message, 'Data', {}) messageHash = 'orderbook:' + symbol + ':' + depth subscription = self.safe_value(client.subscriptions, messageHash, {}) receivedSnapshot = self.safe_bool(subscription, 'receivedSnapshot', False) timestamp = self.safe_integer(message, 'Time') # orderbook = self.safe_value(self.orderbooks, symbol) if not (symbol in self.orderbooks): self.orderbooks[symbol] = self.order_book({}) orderbook = self.orderbooks[symbol] if event == 'OrderBookSnapshot': snapshot = self.parse_order_book(orderBook, symbol, timestamp, 'Bids', 'Offers', 'Price', 'Volume') orderbook.reset(snapshot) subscription['receivedSnapshot'] = True else: asks = self.safe_list(orderBook, 'Offers', []) bids = self.safe_list(orderBook, 'Bids', []) self.handle_deltas(orderbook['asks'], asks) self.handle_deltas(orderbook['bids'], bids) orderbook['timestamp'] = timestamp orderbook['datetime'] = self.iso8601(timestamp) checksum = self.handle_option('watchOrderBook', 'checksum', True) if checksum and receivedSnapshot: storedAsks = orderbook['asks'] storedBids = orderbook['bids'] asksLength = len(storedAsks) bidsLength = len(storedBids) payload = '' for i in range(0, 10): if i < bidsLength: payload = payload + self.value_to_checksum(storedBids[i][0]) + self.value_to_checksum(storedBids[i][1]) for i in range(0, 10): if i < asksLength: payload = payload + self.value_to_checksum(storedAsks[i][0]) + self.value_to_checksum(storedAsks[i][1]) calculatedChecksum = self.crc32(payload, True) responseChecksum = self.safe_integer(orderBook, 'Crc32') if calculatedChecksum != responseChecksum: error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol)) del client.subscriptions[messageHash] del self.orderbooks[symbol] client.reject(error, messageHash) return if receivedSnapshot: client.resolve(orderbook, messageHash) def value_to_checksum(self, value): result = format(value, '.8f') result = result.replace('.', '') # remove leading zeros result = self.parse_number(result) result = self.number_to_string(result) return result def handle_delta(self, bookside, delta): bidAsk = self.parse_bid_ask(delta, 'Price', 'Volume') bookside.storeArray(bidAsk) def handle_deltas(self, bookside, deltas): for i in range(0, len(deltas)): self.handle_delta(bookside, deltas[i]) def handle_heartbeat(self, client: Client, message): # # { # "Time": 1676156208182, # "Event": "Heartbeat" # } # return message def handle_subscriptions(self, client: Client, message): # # { # "Data": ["ticker-btc-sgd"], # "Time": 1676157556223, # "Event": "Subscriptions" # } # return message def handle_message(self, client: Client, message): event = self.safe_string(message, 'Event') handlers: dict = { 'Subscriptions': self.handle_subscriptions, 'Heartbeat': self.handle_heartbeat, 'Trade': self.handle_trades, 'OrderBookSnapshot': self.handle_order_book, 'OrderBookChange': self.handle_order_book, } handler = self.safe_value(handlers, event) if handler is not None: handler(client, message) return raise NotSupported(self.id + ' received an unsupported message: ' + self.json(message))