# -*- 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, IndexType, Int, OrderBook, Trade from ccxt.async_support.base.ws.client import Client from typing import List class luno(ccxt.async_support.luno): def describe(self) -> Any: return self.deep_extend(super(luno, self).describe(), { 'has': { 'ws': True, 'watchTicker': False, 'watchTickers': False, 'watchTrades': True, 'watchTradesForSymbols': False, 'watchMyTrades': False, 'watchOrders': None, # is in beta 'watchOrderBook': True, 'watchOHLCV': False, }, 'urls': { 'api': { 'ws': 'wss://ws.luno.com/api/1', }, }, 'options': { 'sequenceNumbers': {}, }, '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 https://www.luno.com/en/developers/api#tag/Streaming-API :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 ` """ self.check_required_credentials() await self.load_markets() market = self.market(symbol) symbol = market['symbol'] subscriptionHash = '/stream/' + market['id'] subscription: dict = {'symbol': symbol} url = self.urls['api']['ws'] + subscriptionHash messageHash = 'trades:' + symbol subscribe: dict = { 'api_key_id': self.apiKey, 'api_key_secret': self.secret, } request = self.deep_extend(subscribe, params) trades = await self.watch(url, messageHash, request, subscriptionHash, subscription) if self.newUpdates: limit = trades.getLimit(symbol, limit) return self.filter_by_since_limit(trades, since, limit, 'timestamp', True) def handle_trades(self, client: Client, message, subscription): # # { # "sequence": "110980825", # "trade_updates": [], # "create_update": { # "order_id": "BXHSYXAUMH8C2RW", # "type": "ASK", # "price": "24081.09000000", # "volume": "0.07780000" # }, # "delete_update": null, # "status_update": null, # "timestamp": 1660598775360 # } # rawTrades = self.safe_value(message, 'trade_updates', []) length = len(rawTrades) if length == 0: return symbol = subscription['symbol'] market = self.market(symbol) 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 for i in range(0, len(rawTrades)): rawTrade = rawTrades[i] trade = self.parse_trade(rawTrade, market) stored.append(trade) self.trades[symbol] = stored client.resolve(self.trades[symbol], messageHash) def parse_trade(self, trade, market=None) -> Trade: # # watchTrades(public) # # { # "base": "69.00000000", # "counter": "113.6499000000000000", # "maker_order_id": "BXEEU4S2BWF5WRB", # "taker_order_id": "BXKNCSF7JDHXY3H", # "order_id": "BXEEU4S2BWF5WRB" # } # return self.safe_trade({ 'info': trade, 'id': None, 'timestamp': None, 'datetime': None, 'symbol': market['symbol'], 'order': None, 'type': None, 'side': None, # takerOrMaker has no meaning for public trades 'takerOrMaker': None, 'price': None, 'amount': self.safe_string(trade, 'base'), 'cost': self.safe_string(trade, 'counter'), 'fee': None, }, 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 dictConstructor [params]: extra parameters specific to the exchange API endpoint :param str [params.type]: accepts l2 or l3 for level 2 or level 3 order book :returns dict: A dictionary of `order book structures ` indexed by market symbols """ self.check_required_credentials() await self.load_markets() market = self.market(symbol) symbol = market['symbol'] subscriptionHash = '/stream/' + market['id'] subscription: dict = {'symbol': symbol} url = self.urls['api']['ws'] + subscriptionHash messageHash = 'orderbook:' + symbol subscribe: dict = { 'api_key_id': self.apiKey, 'api_key_secret': self.secret, } request = self.deep_extend(subscribe, params) orderbook = await self.watch(url, messageHash, request, subscriptionHash, subscription) return orderbook.limit() def handle_order_book(self, client: Client, message, subscription): # # { # "sequence": "24352", # "asks": [{ # "id": "BXMC2CJ7HNB88U4", # "price": "1234.00", # "volume": "0.93" # }], # "bids": [{ # "id": "BXMC2CJ7HNB88U5", # "price": "1201.00", # "volume": "1.22" # }], # "status": "ACTIVE", # "timestamp": 1528884331021 # } # # update # { # "sequence": "110980825", # "trade_updates": [], # "create_update": { # "order_id": "BXHSYXAUMH8C2RW", # "type": "ASK", # "price": "24081.09000000", # "volume": "0.07780000" # }, # "delete_update": null, # "status_update": null, # "timestamp": 1660598775360 # } # symbol = subscription['symbol'] messageHash = 'orderbook:' + symbol timestamp = self.safe_integer(message, 'timestamp') if not (symbol in self.orderbooks): self.orderbooks[symbol] = self.indexed_order_book({}) asks = self.safe_value(message, 'asks') if asks is not None: snapshot = self.custom_parse_order_book(message, symbol, timestamp, 'bids', 'asks', 'price', 'volume', 'id') self.orderbooks[symbol] = self.indexed_order_book(snapshot) else: ob = self.orderbooks[symbol] self.handle_delta(ob, message) ob['timestamp'] = timestamp ob['datetime'] = self.iso8601(timestamp) orderbook = self.orderbooks[symbol] nonce = self.safe_integer(message, 'sequence') orderbook['nonce'] = nonce client.resolve(orderbook, messageHash) def custom_parse_order_book(self, orderbook, symbol, timestamp=None, bidsKey='bids', asksKey: IndexType = 'asks', priceKey: IndexType = 'price', amountKey: IndexType = 'volume', countOrIdKey: IndexType = 2): bids = self.parse_bids_asks(self.safe_value(orderbook, bidsKey, []), priceKey, amountKey, countOrIdKey) asks = self.parse_bids_asks(self.safe_value(orderbook, asksKey, []), priceKey, amountKey, countOrIdKey) return { 'symbol': symbol, 'bids': self.sort_by(bids, 0, True), 'asks': self.sort_by(asks, 0), 'timestamp': timestamp, 'datetime': self.iso8601(timestamp), 'nonce': None, } def parse_bids_asks(self, bidasks, priceKey: IndexType = 'price', amountKey: IndexType = 'volume', thirdKey: IndexType = 2): bidasks = self.to_array(bidasks) result = [] for i in range(0, len(bidasks)): result.append(self.custom_parse_bid_ask(bidasks[i], priceKey, amountKey, thirdKey)) return result def custom_parse_bid_ask(self, bidask, priceKey: IndexType = 'price', amountKey: IndexType = 'volume', thirdKey: IndexType = 2): price = self.safe_number(bidask, priceKey) amount = self.safe_number(bidask, amountKey) result = [price, amount] if thirdKey is not None: thirdValue = self.safe_string(bidask, thirdKey) result.append(thirdValue) return result def handle_delta(self, orderbook, message): # # create # { # "sequence": "110980825", # "trade_updates": [], # "create_update": { # "order_id": "BXHSYXAUMH8C2RW", # "type": "ASK", # "price": "24081.09000000", # "volume": "0.07780000" # }, # "delete_update": null, # "status_update": null, # "timestamp": 1660598775360 # } # del # { # "sequence": "110980825", # "trade_updates": [], # "create_update": null, # "delete_update": { # "order_id": "BXMC2CJ7HNB88U4" # }, # "status_update": null, # "timestamp": 1660598775360 # } # trade # { # "sequence": "110980825", # "trade_updates": [ # { # "base": "0.1", # "counter": "5232.00", # "maker_order_id": "BXMC2CJ7HNB88U4", # "taker_order_id": "BXMC2CJ7HNB88U5" # } # ], # "create_update": null, # "delete_update": null, # "status_update": null, # "timestamp": 1660598775360 # } # createUpdate = self.safe_value(message, 'create_update') asksOrderSide = orderbook['asks'] bidsOrderSide = orderbook['bids'] if createUpdate is not None: bidAskArray = self.custom_parse_bid_ask(createUpdate, 'price', 'volume', 'order_id') type = self.safe_string(createUpdate, 'type') if type == 'ASK': asksOrderSide.storeArray(bidAskArray) elif type == 'BID': bidsOrderSide.storeArray(bidAskArray) deleteUpdate = self.safe_value(message, 'delete_update') if deleteUpdate is not None: orderId = self.safe_string(deleteUpdate, 'order_id') asksOrderSide.storeArray([0, 0, orderId]) bidsOrderSide.storeArray([0, 0, orderId]) def handle_message(self, client: Client, message): if message == '': return subscriptions = list(client.subscriptions.values()) handlers = [self.handle_order_book, self.handle_trades] for j in range(0, len(handlers)): handler = handlers[j] handler(client, message, subscriptions[0])