# -*- 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, ArrayCacheBySymbolById, ArrayCacheByTimestamp import hashlib from ccxt.base.types import Any, Balances, Int, Market, Order, OrderBook, Position, Str, Strings, Ticker, Tickers, Trade from ccxt.async_support.base.ws.client import Client from typing import List from ccxt.base.errors import ExchangeError from ccxt.base.errors import BadRequest from ccxt.base.errors import NotSupported class weex(ccxt.async_support.weex): def describe(self) -> Any: return self.deep_extend(super(weex, self).describe(), { 'has': { 'watchBalance': True, 'watchBidsAsks': True, 'watchMyTrades': True, 'watchOHLCV': True, 'watchOHLCVForSymbols': True, 'watchOrderBook': False, 'watchOrderBookForSymbols': False, 'watchOrders': True, 'watchPositions': True, 'watchTicker': True, 'watchTickers': True, 'watchTrades': True, 'watchTradesForSymbols': True, 'unWatchBidsAsks': True, 'unWatchMyTrades': True, 'unWatchOHLCV': True, 'unWatchOHLCVForSymbols': True, 'unWatchOrderBook': False, 'unWatchOrderBookForSymbols': False, 'unWatchOrders': True, 'unWatchPositions': True, 'unWatchTicker': True, 'unWatchTickers': True, 'unWatchTrades': True, 'unWatchTradesForSymbols': True, }, 'urls': { 'api': { 'ws': { 'spot': 'wss://ws-spot.weex.com/v3/ws', 'contract': 'wss://ws-contract.weex.com/v3/ws', }, }, }, 'options': { 'ws': { 'options': { 'headers': { 'User-Agent': 'ccxt', # the exchange requires headers }, }, }, 'watchOHLCV': { 'priceType': 'LAST_PRICE', # or 'MARK_PRICE' for swap markets }, 'watchOHLCVForSymbols': { 'priceType': 'LAST_PRICE', # or 'MARK_PRICE' for swap markets }, 'watchOrderBook': { 'depth': '200', # or '15' }, 'watchOrderBookForSymbols': { 'depth': '200', # or '15' }, 'watchBalance': { 'fetchBalanceSnapshot': True, 'awaitBalanceSnapshot': True, }, 'watchPositions': { 'fetchPositionsSnapshot': True, 'awaitPositionsSnapshot': True, }, }, 'streaming': {}, }) def request_id(self): self.lock_id() requestId = self.sum(self.safe_integer(self.options, 'requestId', 0), 1) self.options['requestId'] = requestId self.unlock_id() return self.number_to_string(requestId) async def subscribe_public(self, messageHashes, channels, isContract=False, params={}, subscription={}): id = self.request_id() method = 'SUBSCRIBE' unsubscribe = self.safe_bool(subscription, 'unsubscribe', False) if unsubscribe: method = 'UNSUBSCRIBE' message: dict = { 'id': id, 'method': method, 'params': channels, } subscription = self.extend(subscription, {'id': id}) type = 'contract' if isContract else 'spot' url = self.urls['api']['ws'][type] + '/public' return await self.watch_multiple(url, messageHashes, self.deep_extend(message, params), messageHashes, subscription) async def subscribe_private(self, messageHash, subscribeHash, channel, isContract=False, params={}, subscription={}): type = 'contract' if isContract else 'spot' url = self.urls['api']['ws'][type] + '/private' self.authenticate(url) method = 'SUBSCRIBE' unsubscribe = self.safe_bool(subscription, 'unsubscribe', False) if unsubscribe: method = 'UNSUBSCRIBE' id = self.request_id() message: dict = { 'id': id, 'method': method, 'params': [channel], } subscription = self.extend(subscription, {'id': id}) return await self.watch(url, messageHash, self.deep_extend(message, params), subscribeHash, subscription) def authenticate(self, url): self.check_required_credentials() if (self.clients is not None) and (url in self.clients): return timestamp = self.nonce() payload = str(timestamp) + '/v3/ws/private' signature = self.hmac(self.encode(payload), self.encode(self.secret), hashlib.sha256, 'base64') originalHeaders = self.options['ws']['options']['headers'] userAgent = self.safe_string(originalHeaders, 'User-Agent', 'ccxt') extendedOptions: dict = { 'ws': { 'options': { 'headers': { 'User-Agent': userAgent, 'ACCESS-KEY': self.apiKey, 'ACCESS-SIGN': signature, 'ACCESS-PASSPHRASE': self.password, 'ACCESS-TIMESTAMP': self.number_to_string(timestamp), }, }, }, } self.extend_exchange_options(extendedOptions) # instantiate client self.client(url) # return headers to original state defaultOptions: dict = { 'ws': { 'options': { 'headers': { 'User-Agent': userAgent, }, }, }, } self.extend_exchange_options(defaultOptions) async def watch_ticker(self, symbol: str, params={}) -> Ticker: """ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market https://www.weex.com/api-doc/spot/Websocket/public/Tickers-Channel https://www.weex.com/api-doc/contract/Websocket/public/Tickers-Channel :param str symbol: unified symbol of the market to fetch the ticker for :param dict [params]: extra parameters specific to the exchange API endpoint :param str [params.name]: stream to use can be ticker or miniTicker :returns dict: a `ticker structure ` """ await self.load_markets() symbol = self.symbol(symbol) tickers = await self.watch_tickers([symbol], params) return tickers[symbol] async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers: """ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list https://www.weex.com/api-doc/spot/Websocket/public/Tickers-Channel https://www.weex.com/api-doc/contract/Websocket/public/Tickers-Channel :param str[] symbols: unified symbol of the market to fetch the ticker for :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: a `ticker structure ` """ await self.load_markets() symbols = self.market_symbols(symbols, None, False, True) firstMarket = self.get_market_from_symbols(symbols) isContract = firstMarket['contract'] topic = 'ticker' messageHashes = [] channels = [] for i in range(0, len(symbols)): symbol = symbols[i] market = self.market(symbol) channelName = market['id'] + '@' + topic messageHash = topic + '::' + symbol messageHashes.append(messageHash) channels.append(channelName) newTicker = await self.subscribe_public(messageHashes, channels, isContract, params) if self.newUpdates: result: dict = {} result[newTicker['symbol']] = newTicker return result return self.filter_by_array(self.tickers, 'symbol', symbols) async def un_watch_ticker(self, symbol: str, params={}) -> Any: """ unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list https://www.weex.com/api-doc/spot/Websocket/public/Tickers-Channel https://www.weex.com/api-doc/contract/Websocket/public/Tickers-Channel :param str symbol: unified symbol of the market to fetch the ticker for :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: a `ticker structure ` """ return await self.un_watch_tickers([symbol], params) async def un_watch_tickers(self, symbols: Strings = None, params={}) -> Any: """ unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list https://www.weex.com/api-doc/spot/Websocket/public/Tickers-Channel https://www.weex.com/api-doc/contract/Websocket/public/Tickers-Channel :param str[] symbols: unified symbol of the market to fetch the ticker for :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: a `ticker structure ` """ await self.load_markets() symbols = self.market_symbols(symbols, None, False, True) firstMarket = self.get_market_from_symbols(symbols) isContract = firstMarket['contract'] topic = 'ticker' subHashes = [] channels = [] unSubHashes = [] for i in range(0, len(symbols)): symbol = symbols[i] market = self.market(symbol) channelName = market['id'] + '@' + topic messageHash = topic + '::' + symbol unSubMessageHash = 'unsubscribe::' + messageHash subHashes.append(messageHash) channels.append(channelName) unSubHashes.append(unSubMessageHash) subscription = { 'unsubscribe': True, 'symbols': symbols, 'messageHashes': unSubHashes, 'subMessageHashes': subHashes, 'topic': topic, } return await self.subscribe_public(unSubHashes, channels, isContract, params, subscription) def handle_ticker(self, client: Client, message): # # { # "e": "ticker", # "E": 1776081628845, # "s": "ETHUSDT", # "d": [ # { # "p": "-18.93", # "P": "-0.008592", # "w": "2192.40298388", # "c": "2184.20", # "o": "2203.13", # "h": "2217.34", # "l": "2173.32", # "v": "359395.800", # "q": "787940424.31399", # "O": 1775995200000, # "C": 1776081600000, # "n": 485169, # "m": "2184.28", # "i": "2185.2025" # } # ] # } # market = self.get_market_from_client_and_message(client, message) tickers = self.safe_list(message, 'd', []) data = self.safe_dict(tickers, 0, {}) ticker = self.parse_ws_ticker(data, market) symbol = market['symbol'] messageHash = 'ticker::' + symbol self.tickers[symbol] = ticker client.resolve(self.tickers[symbol], messageHash) def parse_ws_ticker(self, ticker: dict, market: Market = None) -> Ticker: # # { # "p": "-18.93", # "P": "-0.008592", # "w": "2192.40298388", # "c": "2184.20", # "o": "2203.13", # "h": "2217.34", # "l": "2173.32", # "v": "359395.800", # "q": "787940424.31399", # "O": 1775995200000, # "C": 1776081600000, # "n": 485169, # "m": "2184.28", # "i": "2185.2025" # } # timestamp = self.safe_integer(ticker, 'C') close = self.safe_string(ticker, 'c') return self.safe_ticker({ 'symbol': market['symbol'], 'timestamp': timestamp, 'datetime': self.iso8601(timestamp), 'high': self.safe_string(ticker, 'h'), 'low': self.safe_string(ticker, 'l'), 'bid': self.safe_string(ticker, 'b'), 'bidVolume': self.safe_string(ticker, 'B'), 'ask': self.safe_string(ticker, 'a'), 'askVolume': self.safe_string(ticker, 'A'), 'vwap': self.safe_string(ticker, 'w'), 'open': self.safe_string(ticker, 'o'), 'close': close, 'last': close, 'previousClose': self.safe_string(ticker, 'x'), 'change': self.safe_string(ticker, 'p'), 'percentage': self.safe_string(ticker, 'P'), 'average': self.safe_string(ticker, 'w'), 'baseVolume': self.safe_string(ticker, 'v'), 'quoteVolume': self.safe_string(ticker, 'q'), 'markPrice': self.safe_string(ticker, 'm'), 'indexPrice': self.safe_string(ticker, 'i'), 'info': ticker, }, market) 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.weex.com/api-doc/spot/Websocket/public/Trades-Channel https://www.weex.com/api-doc/contract/Websocket/public/Trades-Channel :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 ` """ return await self.watch_trades_for_symbols([symbol], since, limit, params) async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]: """ get the list of most recent trades for a list of symbols https://www.weex.com/api-doc/spot/Websocket/public/Trades-Channel https://www.weex.com/api-doc/contract/Websocket/public/Trades-Channel :param str[] symbols: 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() symbols = self.market_symbols(symbols, None, False, True) firstMarket = self.get_market_from_symbols(symbols) isContract = firstMarket['contract'] topic = 'trade' messageHashes = [] channels = [] for i in range(0, len(symbols)): symbol = symbols[i] market = self.market(symbol) channelName = market['id'] + '@' + topic messageHash = topic + '::' + symbol messageHashes.append(messageHash) channels.append(channelName) trades = await self.subscribe_public(messageHashes, channels, isContract, params) if self.newUpdates: first = self.safe_value(trades, 0) tradeSymbol = self.safe_string(first, 'symbol') limit = trades.getLimit(tradeSymbol, limit) return self.filter_by_since_limit(trades, since, limit, 'timestamp', True) async def un_watch_trades(self, symbol: str, params={}) -> Any: """ unsubscribes from the trades channel https://www.weex.com/api-doc/spot/Websocket/public/Trades-Channel https://www.weex.com/api-doc/contract/Websocket/public/Trades-Channel :param str symbol: unified symbol of the market to fetch trades for :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict[]: a list of `trade structures ` """ await self.load_markets() return await self.un_watch_trades_for_symbols([symbol], params) async def un_watch_trades_for_symbols(self, symbols: List[str], params={}) -> Any: """ unsubscribes from the trades channel https://www.weex.com/api-doc/spot/Websocket/public/Trades-Channel https://www.weex.com/api-doc/contract/Websocket/public/Trades-Channel :param str[] symbols: unified symbol of the market to fetch trades for :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict[]: a list of `trade structures ` """ await self.load_markets() symbols = self.market_symbols(symbols, None, False, True) firstMarket = self.get_market_from_symbols(symbols) isContract = firstMarket['contract'] topic = 'trade' subHashes = [] channels = [] unSubHashes = [] for i in range(0, len(symbols)): symbol = symbols[i] market = self.market(symbol) channelName = market['id'] + '@' + topic messageHash = topic + '::' + symbol unSubMessageHash = 'unsubscribe::' + messageHash subHashes.append(messageHash) channels.append(channelName) unSubHashes.append(unSubMessageHash) subscription = { 'unsubscribe': True, 'symbols': symbols, 'messageHashes': unSubHashes, 'subMessageHashes': subHashes, 'topic': 'trades', } return await self.subscribe_public(unSubHashes, channels, isContract, params, subscription) def handle_trade(self, client: Client, message): # # { # "e": "trade", # "E": 1776104608321, # "s": "ETHUSDT", # "d": [ # { # "T": 1776104608298, # "t": "41099265-7985-4f4c-af93-2cc3bc1cf13b", # "p": "2225.15", # "q": "0.02525", # "v": "56.1850375", # "m": False # } # ] # } # market = self.get_market_from_client_and_message(client, message) symbol = market['symbol'] messageHash = 'trade::' + symbol if not (symbol in self.trades): limit = self.safe_integer(self.options, 'tradesLimit', 1000) self.trades[symbol] = ArrayCache(limit) tradesArray = self.trades[symbol] data = self.safe_list(message, 'd', []) newTrades = [] for i in range(0, len(data)): rawTrade = self.safe_dict(data, i, {}) trade = self.parse_ws_trade(rawTrade, market) newTrades.append(trade) sorted = self.sort_by(newTrades, 'timestamp') for j in range(0, len(sorted)): sortedTrade = sorted[j] tradesArray.append(sortedTrade) self.trades[symbol] = tradesArray client.resolve(tradesArray, messageHash) def parse_ws_trade(self, trade, market=None): # # { # "T": 1776089287762, # "t": "df4d1af1-71e8-400d-9571-f2cee2e6bea8", # "p": "2203.73", # "q": "7.214", # "v": "15897.70822", # "m": False # } # timestamp = self.safe_integer(trade, 'T') return self.safe_trade({ 'info': trade, 'id': self.safe_string(trade, 't'), 'timestamp': timestamp, 'datetime': self.iso8601(timestamp), 'symbol': market['symbol'], 'order': None, 'type': None, 'side': None, 'takerOrMaker': None, 'price': self.safe_string(trade, 'p'), 'amount': self.safe_string(trade, 'q'), 'cost': self.safe_string(trade, 'v'), 'fee': None, }, market) async def watch_ohlcv(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}) -> List[list]: """ watches historical candlestick data containing the open, high, low, and close price, and the volume of a market https://www.weex.com/api-doc/spot/Websocket/public/Candlesticks-Channel https://www.weex.com/api-doc/contract/Websocket/public/Candlesticks-Channel :param str symbol: unified symbol of the market to fetch OHLCV data for :param str timeframe: the length of time each candle represents :param int [since]: timestamp in ms of the earliest candle to fetch :param int [limit]: the maximum amount of candles to fetch :param dict [params]: extra parameters specific to the exchange API endpoint :returns int[][]: A list of candles ordered, open, high, low, close, volume """ extendedParams = self.extend(params, { 'callerMethodName': 'watchOHLCV', }) result = await self.watch_ohlcv_for_symbols([[symbol, timeframe]], since, limit, extendedParams) return result[symbol][timeframe] async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}): """ watches historical candlestick data containing the open, high, low, and close price, and the volume of a market https://www.weex.com/api-doc/spot/Websocket/public/Candlesticks-Channel https://www.weex.com/api-doc/contract/Websocket/public/Candlesticks-Channel :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']] :param int [since]: timestamp in ms of the earliest candle to fetch :param int [limit]: the maximum amount of candles to fetch :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: A list of candles ordered, open, high, low, close, volume """ await self.load_markets() callerMethodName = self.safe_string(params, 'callerMethodName', 'watchOHLCVForSymbols') params = self.omit(params, 'callerMethodName') channels = [] messageHashes = [] firstEntry = self.safe_list(symbolsAndTimeframes, 0, []) firstSymbol = self.safe_string(firstEntry, 0) firstMarket = self.market(firstSymbol) isContract = firstMarket['contract'] priceType = 'LAST_PRICE' if isContract: priceType, params = self.handle_option_and_params_2(params, callerMethodName, 'price', 'priceType', priceType) for i in range(0, len(symbolsAndTimeframes)): data = self.safe_list(symbolsAndTimeframes, i) symbolString = self.safe_string(data, 0) market = self.market(symbolString) if market['type'] != firstMarket['type']: raise BadRequest(self.id + ' ' + callerMethodName + ' market symbols must be of the same type') symbolString = market['symbol'] unifiedTimeframe = self.safe_string(data, 1, '1') interval = self.safe_string(self.timeframes, unifiedTimeframe, unifiedTimeframe) channel = market['id'] + '@kline_' + interval + '_' + priceType messageHash = 'ohlcv::' + symbolString + '::' + unifiedTimeframe channels.append(channel) messageHashes.append(messageHash) symbol, timeframe, stored = await self.subscribe_public(messageHashes, channels, isContract, params) if self.newUpdates: limit = stored.getLimit(symbol, limit) filtered = self.filter_by_since_limit(stored, since, limit, 0, True) return self.create_ohlcv_object(symbol, timeframe, filtered) async def un_watch_ohlcv(self, symbol: str, timeframe='1m', params={}) -> Any: """ unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market https://www.weex.com/api-doc/spot/Websocket/public/Candlesticks-Channel https://www.weex.com/api-doc/contract/Websocket/public/Candlesticks-Channel :param str symbol: unified symbol of the market to fetch OHLCV data for :param str timeframe: the length of time each candle represents :param dict [params]: extra parameters specific to the exchange API endpoint :returns int[][]: A list of candles ordered, open, high, low, close, volume """ params['callerMethodName'] = 'unWatchOHLCV' return await self.un_watch_ohlcv_for_symbols([[symbol, timeframe]], params) async def un_watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], params={}) -> Any: """ unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market https://www.weex.com/api-doc/spot/Websocket/public/Candlesticks-Channel https://www.weex.com/api-doc/contract/Websocket/public/Candlesticks-Channel :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']] :param dict [params]: extra parameters specific to the exchange API endpoint :returns int[][]: A list of candles ordered, open, high, low, close, volume """ await self.load_markets() callerMethodName = self.safe_string(params, 'callerMethodName', 'unWatchOHLCVForSymbols') params = self.omit(params, 'callerMethodName') channels = [] subHashes = [] unSubHashes = [] firstEntry = self.safe_list(symbolsAndTimeframes, 0, []) firstSymbol = self.safe_string(firstEntry, 0) firstMarket = self.market(firstSymbol) isContract = firstMarket['contract'] priceType = 'LAST_PRICE' if isContract: priceType, params = self.handle_option_and_params_2(params, callerMethodName, 'price', 'priceType', priceType) for i in range(0, len(symbolsAndTimeframes)): data = self.safe_list(symbolsAndTimeframes, i) symbolString = self.safe_string(data, 0) market = self.market(symbolString) if market['type'] != firstMarket['type']: raise BadRequest(self.id + ' ' + callerMethodName + ' market symbols must be of the same type') symbolString = market['symbol'] unifiedTimeframe = self.safe_string(data, 1, '1') interval = self.safe_string(self.timeframes, unifiedTimeframe, unifiedTimeframe) channel = market['id'] + '@kline_' + interval + '_' + priceType messageHash = 'ohlcv::' + symbolString + '::' + unifiedTimeframe unSubMessageHash = 'unsubscribe::' + messageHash channels.append(channel) subHashes.append(messageHash) unSubHashes.append(unSubMessageHash) subscription = { 'unsubscribe': True, 'symbolsAndTimeframes': symbolsAndTimeframes, 'messageHashes': unSubHashes, 'subMessageHashes': subHashes, 'topic': 'ohlcv', } return await self.subscribe_public(unSubHashes, channels, isContract, params, subscription) def handle_ohlcv(self, client: Client, message): # # { # e: 'kline', # E: 1776095535012, # s: 'ETHUSDT', # p: 'LAST_PRICE', # d: [ # { # t: 1776092400000, # T: 1776096000000, # s: 'ETHUSDT', # i: '1h', # o: '2234.18', # c: '2205.15', # h: '2236.43', # l: '2199.53', # v: '12505.60574', # n: 3381, # q: '27682528.6655305', # V: '6420.47929', # Q: '14213680.1906424' # } # ] # } # market = self.get_market_from_client_and_message(client, message) symbol = market['symbol'] if not (symbol in self.ohlcvs): self.ohlcvs[symbol] = {} data = self.safe_list(message, 'd', []) firstEntry = self.safe_dict(data, 0, {}) interval = self.safe_string(firstEntry, 'i') timeframe = self.find_timeframe(interval) if not (timeframe in self.ohlcvs[symbol]): limit = self.safe_integer(self.options, 'OHLCVLimit', 1000) self.ohlcvs[symbol][timeframe] = ArrayCacheByTimestamp(limit) stored = self.ohlcvs[symbol][timeframe] for i in range(0, len(data)): entry = self.safe_dict(data, i, {}) parsed = self.parse_ws_ohlcv(entry) stored.append(parsed) messageHash = 'ohlcv::' + symbol + '::' + timeframe resolveData = [symbol, timeframe, stored] client.resolve(resolveData, messageHash) def parse_ws_ohlcv(self, ohlcv, market=None) -> list: # # { # t: 1776092400000, # T: 1776096000000, # s: 'ETHUSDT', # i: '1h', # o: '2234.18', # c: '2205.15', # h: '2236.43', # l: '2199.53', # v: '12505.60574', # n: 3381, # q: '27682528.6655305', # V: '6420.47929', # Q: '14213680.1906424' # } # return [ self.safe_integer(ohlcv, 't'), self.safe_number(ohlcv, 'o'), self.safe_number(ohlcv, 'h'), self.safe_number(ohlcv, 'l'), self.safe_number(ohlcv, 'c'), self.safe_number(ohlcv, 'v'), ] 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 https://www.weex.com/api-doc/spot/Websocket/public/Depth-Channel https://www.weex.com/api-doc/contract/Websocket/public/Depth-Channel :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 """ params = self.extend(params, { 'callerMethodName': 'watchOrderBook', }) return await self.watch_order_book_for_symbols([symbol], limit, params) async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook: """ watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data https://www.weex.com/api-doc/spot/Websocket/public/Depth-Channel https://www.weex.com/api-doc/contract/Websocket/public/Depth-Channel :param str[] symbols: unified array of symbols :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() symbols = self.market_symbols(symbols, None, False, True) firstMarket = self.get_market_from_symbols(symbols) isContract = firstMarket['contract'] callerMethodName = self.safe_string(params, 'callerMethodName', 'watchOrderBookForSymbols') params = self.omit(params, 'callerMethodName') depth = '200' depth, params = self.handle_option_and_params(params, callerMethodName, 'depth', depth) messageHashes = [] channels = [] for i in range(0, len(symbols)): symbol = symbols[i] market = self.market(symbol) messageHash = 'orderbook::' + symbol channel = market['id'] + '@depth' + depth messageHashes.append(messageHash) channels.append(channel) subscription: dict = { 'limit': limit, } orderbook = await self.subscribe_public(messageHashes, channels, isContract, params, subscription) return orderbook.limit() async def un_watch_order_book(self, symbol: str, params={}) -> Any: """ unWatches information on open orders with bid(buy) and ask(sell) prices, volumes and other data https://www.weex.com/api-doc/spot/Websocket/public/Depth-Channel https://www.weex.com/api-doc/contract/Websocket/public/Depth-Channel :param str symbol: unified array of symbols :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: A dictionary of `order book structures ` indexed by market symbols """ params = self.extend(params, { 'callerMethodName': 'unWatchOrderBook', }) return await self.un_watch_order_book_for_symbols([symbol], params) async def un_watch_order_book_for_symbols(self, symbols: List[str], params={}) -> Any: """ unWatches information on open orders with bid(buy) and ask(sell) prices, volumes and other data https://www.weex.com/api-doc/spot/Websocket/public/Depth-Channel https://www.weex.com/api-doc/contract/Websocket/public/Depth-Channel :param str[] symbols: unified array of symbols :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() symbols = self.market_symbols(symbols, None, False, True) firstMarket = self.get_market_from_symbols(symbols) isContract = firstMarket['contract'] callerMethodName = self.safe_string(params, 'callerMethodName', 'unWatchOrderBookForSymbols') params = self.omit(params, 'callerMethodName') depth = '200' depth, params = self.handle_option_and_params(params, callerMethodName, 'depth', depth) subHashes = [] channels = [] unSubHashes = [] for i in range(0, len(symbols)): symbol = symbols[i] market = self.market(symbol) messageHash = 'orderbook::' + symbol channel = market['id'] + '@depth' + depth unSubMessageHash = 'unsubscribe::' + messageHash subHashes.append(messageHash) channels.append(channel) unSubHashes.append(unSubMessageHash) subscription = { 'unsubscribe': True, 'symbols': symbols, 'messageHashes': unSubHashes, 'subMessageHashes': subHashes, 'topic': 'orderbook', } return await self.subscribe_public(unSubHashes, channels, isContract, params, subscription) def handle_order_book(self, client: Client, message): # # { # "e": "depth", # "E": 1776098967972, # "s": "ETHUSDT", # "U": 14181847790, # "u": 14181847802, # "l": 200, # "d": "CHANGED", # "b": [["2227.21", "0"], ["2227.20", "46.519"]], # "a": [["2227.21", "44.092"], ["2227.26", "0"]] # } # market = self.get_market_from_client_and_message(client, message) symbol = market['symbol'] messageHash = 'orderbook::' + symbol if not (symbol in self.orderbooks): subscription = self.safe_dict(client.subscriptions, messageHash, {}) limit = self.safe_integer(subscription, 'limit') if limit is not None: self.orderbooks[symbol] = self.order_book({}, limit) else: self.orderbooks[symbol] = self.order_book({}) orderbook = self.orderbooks[symbol] timestamp = self.safe_integer(message, 'E') event = self.safe_string(message, 'e') nonce = self.safe_integer(message, 'u') if event == 'depthSnapshot': parsed = self.parse_order_book(message, symbol, timestamp, 'b', 'a') parsed['nonce'] = nonce orderbook.reset(parsed) else: asks = self.safe_list(message, 'a', []) bids = self.safe_list(message, 'b', []) self.handle_deltas(orderbook['asks'], asks) self.handle_deltas(orderbook['bids'], bids) orderbook['timestamp'] = timestamp orderbook['datetime'] = self.iso8601(timestamp) orderbook['nonce'] = nonce client.resolve(orderbook, messageHash) def handle_delta(self, bookside, delta): bidAsk = self.parse_bid_ask(delta) bookside.storeArray(bidAsk) async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers: """ watches best bid & ask for spot symbols https://www.weex.com/api-doc/spot/Websocket/public/BookTicker-Channel :param str[] symbols: unified symbol of the market to fetch the ticker for :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: a `ticker structure ` """ await self.load_markets() symbols = self.market_symbols(symbols, None, False, True) firstMarket = self.get_market_from_symbols(symbols) if firstMarket['contract']: raise NotSupported(self.id + ' watchBidsAsks is supported for spot markets only') messageHashes = [] channels = [] for i in range(0, len(symbols)): symbol = symbols[i] market = self.market(symbol) channelName = market['id'] + '@' + 'bookTicker' messageHash = 'bidask::' + symbol messageHashes.append(messageHash) channels.append(channelName) newTicker = await self.subscribe_public(messageHashes, channels, False, params) if self.newUpdates: result = {} result[newTicker['symbol']] = newTicker return result return self.filter_by_array(self.bidsasks, 'symbol', symbols) async def un_watch_bids_asks(self, symbols: Strings = None, params={}) -> Any: """ unWatches best bid & ask for spot symbols https://www.weex.com/api-doc/spot/Websocket/public/BookTicker-Channel :param str[] symbols: unified symbol of the market to fetch the ticker for :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: a `ticker structure ` """ await self.load_markets() symbols = self.market_symbols(symbols, None, False, True) firstMarket = self.get_market_from_symbols(symbols) if firstMarket['contract']: raise NotSupported(self.id + ' unWatchBidsAsks is supported for spot markets only') subHashes = [] channels = [] unSubHashes = [] for i in range(0, len(symbols)): symbol = symbols[i] market = self.market(symbol) channelName = market['id'] + '@' + 'bookTicker' messageHash = 'bidask::' + symbol unSubMessageHash = 'unsubscribe::' + messageHash subHashes.append(messageHash) channels.append(channelName) unSubHashes.append(unSubMessageHash) subscription = { 'unsubscribe': True, 'symbols': symbols, 'messageHashes': unSubHashes, 'subMessageHashes': subHashes, 'topic': 'bidsasks', } return await self.subscribe_public(unSubHashes, channels, False, params, subscription) def handle_bid_ask(self, client: Client, message): # # { # "e": "bookTicker", # "E": 1776103547551, # "s": "ETHUSDT", # "u": 1776103547547, # "b": "2227.39", # "B": "1.05512", # "a": "2227.40", # "A": "6.30889" # } # market = self.get_market_from_client_and_message(client, message) ticker = self.parse_ws_bid_ask(message, market) symbol = ticker['symbol'] self.bidsasks[symbol] = ticker messageHash = 'bidask::' + symbol client.resolve(ticker, messageHash) def parse_ws_bid_ask(self, message, market=None): timestamp = self.safe_integer(message, 'E') return self.safe_ticker({ 'symbol': market['symbol'], 'timestamp': timestamp, 'datetime': self.iso8601(timestamp), 'ask': self.safe_string(message, 'a'), 'askVolume': self.safe_string(message, 'A'), 'bid': self.safe_string(message, 'b'), 'bidVolume': self.safe_string(message, 'B'), 'info': message, }, market) async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]: """ watches information on multiple trades made by the user https://www.weex.com/api-doc/spot/Websocket/private/Fill-Channel https://www.weex.com/api-doc/contract/Websocket/private/Fill-Channel :param str symbol: unified market symbol of the market trades were made in :param int [since]: the earliest time in ms to fetch trades for :param int [limit]: the maximum number of trade structures to retrieve :param dict [params]: extra parameters specific to the exchange API endpoint :param str [params.type]: spot or swap, default is spot if symbol is not provided :returns dict[]: a list of `trade structures ` """ await self.load_markets() marketType = None market = None if symbol is not None: market = self.market(symbol) symbol = market['symbol'] marketType, params = self.handle_market_type_and_params('watchMyTrades', market, params) isContract = (marketType != 'spot') messageHash = 'myContractTrades' if isContract else 'myTrades' subscriptionHash = messageHash if symbol is not None: messageHash += '::' + symbol channel = 'fill' trades = await self.subscribe_private(messageHash, subscriptionHash, channel, isContract, params) if self.newUpdates: limit = trades.getLimit(symbol, limit) return self.filter_by_symbol_since_limit(trades, symbol, since, limit, True) async def un_watch_my_trades(self, symbol: Str = None, params={}) -> Any: """ unWatches information on multiple trades made by the user https://www.weex.com/api-doc/spot/Websocket/private/Fill-Channel https://www.weex.com/api-doc/contract/Websocket/private/Fill-Channel :param str [symbol]: not used by the exchange :param dict [params]: extra parameters specific to the exchange API endpoint :param str [params.type]: spot or swap, default is spot :returns dict[]: a list of `order structures ` """ if symbol is not None: raise NotSupported(self.id + ' unWatchMyTrades does not support a symbol argument. Unsubscribing from myTrades is global for all symbols.') marketType = None marketType, params = self.handle_market_type_and_params('unWatchMyTrades', None, params) isContract = (marketType != 'spot') subHash = 'myContractTrades' if isContract else 'myTrades' unSubHash = 'unsubscribe::' + subHash channel = 'fill' subscription = { 'unsubscribe': True, 'messageHashes': [unSubHash], 'subMessageHashes': [subHash], 'topic': 'myTrades', 'subHashIsPrefix': True, } return await self.subscribe_private(unSubHash, unSubHash, channel, isContract, params, subscription) def handle_my_trades(self, client: Client, message): # # spot # { # e: 'fill', # E: 1776174283564, # v: 83, # msgEvent: 'OrderUpdate', # d: [ # { # id: '738928502249620072', # symbol: 'DOGEUSDT', # baseCoin: 'DOGE', # quoteCoin: 'USDT', # orderId: '738928502174122600', # orderSide: 'SELL', # fillSize: '200.0', # fillValue: '19.098000', # fillFee: '0.01909800', # direction: 'TAKER', # createdTime: '1776174283564', # updatedTime: '1776174283564' # } # ] # } # # swap # { # "id": "738957755401896296", # "coin": "USDT", # "symbol": "DOGEUSDT", # "orderId": "738957755376730472", # "marginMode": "CROSSED", # "separatedMode": "COMBINED", # "separatedOpenOrderId": "0", # "positionSide": "LONG", # "orderSide": "BUY", # "fillSize": "100", # "fillValue": "9.59500", # "fillFee": "0.00767600", # "liquidateFee": "0", # "realizePnl": "0", # "direction": "TAKER", # "createdTime": "1776181258059", # "updatedTime": "1776181258059" # } # if self.myTrades is None: limit = self.safe_integer(self.options, 'tradesLimit', 1000) self.myTrades = ArrayCacheBySymbolById(limit) trades = self.myTrades data = self.safe_list(message, 'd', []) symbols: dict = {} for i in range(0, len(data)): trade = self.safe_dict(data, i, {}) parsed = self.parse_ws_my_trade(trade) symbol = parsed['symbol'] symbols[symbol] = True trades.append(parsed) messageHash = 'myTrades' symbolKeys = list(symbols.keys()) market = self.get_market_from_symbols(symbolKeys) if market['contract']: messageHash = 'myContractTrades' for j in range(0, len(symbolKeys)): symbol = symbolKeys[j] symbolMessageHash = messageHash + '::' + symbol client.resolve(trades, symbolMessageHash) client.resolve(trades, messageHash) def parse_ws_my_trade(self, trade, market=None): # # spot # { # id: '738928502249620072', # symbol: 'DOGEUSDT', # baseCoin: 'DOGE', # quoteCoin: 'USDT', # orderId: '738928502174122600', # orderSide: 'SELL', # fillSize: '200.0', # fillValue: '19.098000', # fillFee: '0.01909800', # direction: 'TAKER', # createdTime: '1776174283564', # updatedTime: '1776174283564' # } # timestamp = self.safe_integer(trade, 'createdTime') marketId = self.safe_string(trade, 'symbol') marketType = 'spot' positionSide = self.safe_string(trade, 'positionSide') if positionSide is not None: marketType = 'swap' market = self.safe_market(marketId, None, None, marketType) side = self.safe_string_lower(trade, 'orderSide') fee = None commission = self.safe_string(trade, 'fillFee') if commission is not None: commissionAsset = self.safe_string(trade, 'coin') feeCurrency = self.safe_currency_code(commissionAsset) if marketType == 'spot': if side == 'buy': feeCurrency = market['base'] else: feeCurrency = market['quote'] fee = { 'cost': commission, 'currency': feeCurrency, } return self.safe_trade({ 'info': trade, 'id': self.safe_string(trade, 'id'), 'timestamp': timestamp, 'datetime': self.iso8601(timestamp), 'symbol': market['symbol'], 'order': self.safe_string(trade, 'orderId'), 'type': self.safe_string(trade, 'type'), 'side': side, 'takerOrMaker': self.safe_string_lower(trade, 'direction'), 'price': None, 'amount': self.safe_string(trade, 'fillSize'), 'cost': self.safe_string(trade, 'fillValue'), 'fee': fee, }) async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]: """ watches information on multiple orders made by the user https://www.weex.com/api-doc/spot/Websocket/private/Order-Channel https://www.weex.com/api-doc/contract/Websocket/private/Order-Channel :param str symbol: unified market symbol of the market orders were made in :param int [since]: the earliest time in ms to fetch orders for :param int [limit]: the maximum number of order structures to retrieve :param dict [params]: extra parameters specific to the exchange API endpoint :param str [params.type]: spot or swap, default is spot if symbol is not provided :returns dict[]: a list of `order structures ` """ await self.load_markets() market = None if symbol is not None: market = self.market(symbol) symbol = market['symbol'] marketType = None marketType, params = self.handle_market_type_and_params('watchOrders', market, params) isContract = (marketType != 'spot') messageHash = 'contractOrders' if isContract else 'orders' subscriptionHash = messageHash if symbol is not None: messageHash += '::' + symbol channel = 'orders' orders = await self.subscribe_private(messageHash, subscriptionHash, channel, isContract, params) if self.newUpdates: limit = orders.getLimit(symbol, limit) return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True) async def un_watch_orders(self, symbol: Str = None, params={}) -> Any: """ unWatches information on multiple orders made by the user https://www.weex.com/api-doc/spot/Websocket/private/Order-Channel https://www.weex.com/api-doc/contract/Websocket/private/Order-Channel :param str [symbol]: not used by the exchange :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict[]: a list of `order structures ` """ if symbol is not None: raise NotSupported(self.id + ' unWatchOrders does not support a symbol argument. Unsubscribing from orders is global for all symbols.') marketType = None marketType, params = self.handle_market_type_and_params('unWatchOrders', None, params) isContract = (marketType != 'spot') subHash = 'contractOrders' if isContract else 'orders' unSubHash = 'unsubscribe::' + subHash channel = 'orders' subscription = { 'unsubscribe': True, 'messageHashes': [unSubHash], 'subMessageHashes': [subHash], 'topic': 'orders', 'subHashIsPrefix': True, } return await self.subscribe_private(unSubHash, unSubHash, channel, isContract, params, subscription) def handle_orders(self, client: Client, message): # # { # "e": "orders", # "E": 1776184415058, # "v": 153, # "msgEvent": "OrderUpdate", # "d": [ # { # "id": "738970996765098600", # "symbol": "DOGEUSDT", # "baseCoin": "DOGE", # "quoteCoin": "USDT", # "orderSide": "SELL", # "price": "0", # "size": "200.0", # "value": "0", # "clientOrderId": "b-WEEX111125-bf78d975ca38422bb6ea65", # "type": "MARKET", # "timeInForce": "IOC", # "reduceOnly": False, # "triggerPrice": "0", # "orderSource": "API", # "openTpslParentOrderId": "0", # "setOpenTp": False, # "setOpenSl": False, # "takerFeeRate": "0.001", # "makerFeeRate": "0.001", # "feeDiscount": "1", # "takerFeeDiscount": "1", # "makerFeeDiscount": "1", # "status": "FILLED", # "triggerTime": "0", # "triggerPriceTime": "0", # "triggerPriceValue": "0", # "cancelReason": "UNKNOWN_ORDER_CANCEL_REASON", # "latestFillPrice": "0.09571", # "maxFillPrice": "0.09571", # "minFillPrice": "0.09571", # "cumFillSize": "200.0", # "cumFillValue": "19.142000", # "cumFillFee": "0.01914200", # "createdTime": "1776184415046", # "updatedTime": "1776184415058" # } # ] # } # data = self.safe_list(message, 'd', []) symbols: dict = {} if self.orders is None: limit = self.safe_integer(self.options, 'ordersLimit', 1000) self.orders = ArrayCacheBySymbolById(limit) orders = self.orders for i in range(0, len(data)): rawOrder = self.safe_dict(data, i, {}) parsed = self.parse_ws_order(rawOrder) orders.append(parsed) symbol = parsed['symbol'] symbols[symbol] = True messageHash = 'orders' symbolKeys = list(symbols.keys()) market = self.get_market_from_symbols(symbolKeys) if market['contract']: messageHash = 'contractOrders' for i in range(0, len(symbolKeys)): symbol = symbolKeys[i] symbolMessageHash = messageHash + '::' + symbol client.resolve(orders, symbolMessageHash) client.resolve(self.orders, messageHash) def parse_ws_order(self, order, market=None): # # spot # { # "id": "738970996765098600", # "symbol": "DOGEUSDT", # "baseCoin": "DOGE", # "quoteCoin": "USDT", # "orderSide": "SELL", # "price": "0", # "size": "200.0", # "value": "0", # "clientOrderId": "b-WEEX111125-bf78d975ca38422bb6ea65", # "type": "MARKET", # "timeInForce": "IOC", # "reduceOnly": False, # "triggerPrice": "0", # "orderSource": "API", # "openTpslParentOrderId": "0", # "setOpenTp": False, # "setOpenSl": False, # "takerFeeRate": "0.001", # "makerFeeRate": "0.001", # "feeDiscount": "1", # "takerFeeDiscount": "1", # "makerFeeDiscount": "1", # "status": "FILLED", # "triggerTime": "0", # "triggerPriceTime": "0", # "triggerPriceValue": "0", # "cancelReason": "UNKNOWN_ORDER_CANCEL_REASON", # "latestFillPrice": "0.09571", # "maxFillPrice": "0.09571", # "minFillPrice": "0.09571", # "cumFillSize": "200.0", # "cumFillValue": "19.142000", # "cumFillFee": "0.01914200", # "createdTime": "1776184415046", # "updatedTime": "1776184415058" # } # # swap # { # "id": "617414920861909658", # "coin": "USDT", # "symbol": "BTCUSDT", # "marginMode": "CROSSED", # "separatedMode": "COMBINED", # "separatedOpenOrderId": "0", # "positionSide": "LONG", # "orderSide": "BUY", # "price": "0.0", # "size": "0.10000", # "clientOrderId": "1747203186927FPIZRP", # "type": "MARKET", # "timeInForce": "IOC", # "reduceOnly": False, # "triggerPrice": "0", # "triggerPriceType": "CONTRACT_PRICE", # "orderSource": "WEB", # "openTpslParentOrderId": "0", # "positionTpsl": False, # "setOpenTp": False, # "setOpenSl": False, # "leverage": "20", # "takerFeeRate": "0.0006", # "makerFeeRate": "0.0002", # "feeDiscount": "1", # "liquidateFeeRate": "0.01", # "status": "PENDING", # "triggerTime": "0", # "triggerPriceTime": "0", # "triggerPriceValue": "0", # "cancelReason": "UNKNOWN_ORDER_CANCEL_REASON", # "latestFillPrice": "0", # "maxFillPrice": "0", # "minFillPrice": "0", # "cumFillSize": "0", # "cumFillValue": "0", # "cumFillFee": "0", # "cumLiquidateFee": "0", # "cumRealizePnl": "0", # "createdTime": "1747203188148", # "updatedTime": "1747203188148" # } # timestamp = self.safe_integer(order, 'createdTime') marketId = self.safe_string(order, 'symbol') marketType = 'spot' positionSide = self.safe_string(order, 'positionSide') if positionSide is not None: marketType = 'swap' market = self.safe_market(marketId, None, None, marketType) side = self.safe_string_lower(order, 'orderSide') fee = None commission = self.safe_string(order, 'cumFillFee') if commission is not None: commissionAsset = self.safe_string(order, 'coin') feeCurrency = self.safe_currency_code(commissionAsset) if marketType == 'spot': if side == 'buy': feeCurrency = market['base'] else: feeCurrency = market['quote'] fee = { 'cost': commission, 'currency': feeCurrency, } rawStatus = self.safe_string_lower(order, 'status') rawType = self.safe_string(order, 'type') triggerPrice = self.omit_zero(self.safe_string(order, 'triggerPrice')) stopLossPrice = None takeProfitPrice = None if rawType == 'TAKE_PROFIT_MARKET' or rawType == 'TAKE_PROFIT': takeProfitPrice = triggerPrice elif rawType == 'STOP_LOSS' or rawType == 'STOP' or rawType == 'STOP_MARKET': stopLossPrice = triggerPrice return self.safe_order({ 'id': self.safe_string(order, 'id'), 'clientOrderId': self.safe_string(order, 'clientOrderId'), 'symbol': market['symbol'], 'type': self.parseOrderType(rawType), 'timeInForce': self.safe_string(order, 'timeInForce'), 'postOnly': None, 'reduceOnly': self.safe_bool(order, 'reduceOnly'), 'side': side, 'amount': self.safe_string(order, 'size'), 'price': self.safe_string(order, 'price'), 'triggerPrice': triggerPrice, 'cost': self.safe_string(order, 'cumFillValue'), 'filled': self.safe_string(order, 'cumFillSize'), 'remaining': None, 'timestamp': timestamp, 'datetime': self.iso8601(timestamp), 'fee': fee, 'status': self.parse_order_status(rawStatus), 'lastTradeTimestamp': None, 'lastUpdateTimestamp': self.safe_integer(order, 'updatedTime'), 'average': None, 'trades': None, 'stopLossPrice': stopLossPrice, 'takeProfitPrice': takeProfitPrice, 'info': order, }, market) async def watch_balance(self, params={}) -> Balances: """ query for balance and get the amount of funds available for trading or funds locked in orders https://www.weex.com/api-doc/spot/Websocket/private/Account-Channel https://www.weex.com/api-doc/contract/Websocket/private/Account-Channel :param dict [params]: extra parameters specific to the exchange API endpoint :param str [params.type]: 'spot' or 'swap', default is 'spot' :returns dict: a `balance structure ` """ await self.load_markets() type = None type, params = self.handle_market_type_and_params('watchBalance', None, params) isContract = (type != 'spot') urlType = 'contract' if isContract else 'spot' url = self.urls['api']['ws'][urlType] + '/private' self.authenticate(url) client = self.client(url) self.set_balance_cache(client, type) options = self.safe_dict(self.options, 'watchBalance') fetchBalanceSnapshot = self.safe_bool(options, 'fetchBalanceSnapshot', False) awaitBalanceSnapshot = self.safe_bool(options, 'awaitBalanceSnapshot', True) if fetchBalanceSnapshot and awaitBalanceSnapshot: await client.future(type + ':fetchBalanceSnapshot') messageHash = type + ':' + 'balance' return await self.subscribe_private(messageHash, type, 'account', isContract, params) def set_balance_cache(self, client: Client, type): if (type in client.subscriptions) and (type in self.balance): return options = self.safe_dict(self.options, 'watchBalance') fetchBalanceSnapshot = self.safe_bool(options, 'fetchBalanceSnapshot', False) if fetchBalanceSnapshot: messageHash = type + ':fetchBalanceSnapshot' if not (messageHash in client.futures): client.future(messageHash) self.spawn(self.load_balance_snapshot, client, messageHash, type) else: self.balance[type] = {} async def load_balance_snapshot(self, client, messageHash, type): params: dict = { 'type': type, } response = await self.fetch_balance(params) self.balance[type] = self.extend(response, self.safe_value(self.balance, type, {})) # don't remove the future from the .futures cache if messageHash in client.futures: future = client.futures[messageHash] future.resolve() client.resolve(self.balance[type], type + ':balance') def handle_balance(self, client: Client, message): # # spot # { # "e": "account", # "E": 1776187844633, # "v": 178, # "msgEvent": "DepositUpdate", # "d": [ # { # "coin": "USDT", # "equity": "47.98428060", # "available": "47.98428060", # "frozen": "0" # } # ] # } # # coontract # { # "e": "account", # "E": 1776189629849, # "v": 281, # "msgEvent": "DepositUpdate", # "d": [ # { # "coin": "USDT", # "marginMode": "CROSSED", # "crossSymbol": "0", # "isolatedPositionId": "0", # "amount": "0.00000000", # "pendingDepositAmount": "20.00000000", # "pendingWithdrawAmount": "0.00000000", # "pendingTransferInAmount": "0", # "pendingTransferOutAmount": "0", # "liquidating": False, # "legacyAmount": "0.00000000", # "cumDepositAmount": "167.50000925", # "cumWithdrawAmount": "166.94609514", # "cumTransferInAmount": "0", # "cumTransferOutAmount": "0", # "cumMarginMoveInAmount": "10.86162763", # "cumMarginMoveOutAmount": "10.83205378", # "cumPositionOpenLongAmount": "305.59400", # "cumPositionOpenShortAmount": "238.95700", # "cumPositionCloseLongAmount": "305.86600000", # "cumPositionCloseShortAmount": "238.94700000", # "cumPositionFillFeeAmount": "0.00761040", # "cumPositionLiquidateFeeAmount": "0", # "cumPositionFundingAmount": "0.00049824", # "cumOrderFillFeeIncomeAmount": "0", # "cumOrderLiquidateFeeIncomeAmount": "0", # "createdTime": "1775605824300", # "updatedTime": "1776189629849" # } # ] # } # url = client.url accountType = 'spot' if url.find('contract') >= 0: accountType = 'swap' messageHash = accountType + ':balance' if self.balance[accountType] is None: self.balance[accountType] = {} self.balance[accountType]['info'] = message balanceUpdates = self.safe_list(message, 'd', []) for i in range(0, len(balanceUpdates)): entry = self.safe_dict(balanceUpdates, i) currencyId = self.safe_string(entry, 'coin') code = self.safe_currency_code(currencyId) account = self.account() account['free'] = self.safe_string_2(entry, 'available', 'amount') account['used'] = self.safe_string(entry, 'frozen') account['total'] = self.safe_string_2(entry, 'equity', 'legacyAmount') self.balance[accountType][code] = account timestamp = self.safe_integer(message, 'E') self.balance[accountType]['timestamp'] = timestamp self.balance[accountType]['datetime'] = self.iso8601(timestamp) self.balance[accountType] = self.safe_balance(self.balance[accountType]) client.resolve(self.balance[accountType], messageHash) async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]: """ https://www.weex.com/api-doc/contract/Websocket/private/Positions-Channel watch all open positions :param str[]|None symbols: list of unified market symbols :param int [since]: the earliest time in ms to fetch positions for :param int [limit]: the maximum number of position structures to retrieve :param dict params: extra parameters specific to the exchange API endpoint :param int [params.accountNumber]: account number to query orders for, required :returns dict[]: a list of `position structure ` """ await self.load_markets() url = self.urls['api']['ws']['contract'] + '/private' self.authenticate(url) client = self.client(url) symbols = self.market_symbols(symbols, 'swap', True) messageHash = 'positions' subscriptionHash = messageHash if symbols is not None: messageHash += '::' + ','.join(symbols) channel = 'positions' self.set_positions_cache(client, params) fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', True) awaitPositionsSnapshot = self.handle_option('watchPositions', 'awaitPositionsSnapshot', True) if fetchPositionsSnapshot and awaitPositionsSnapshot and self.positions is None: snapshot = await client.future('fetchPositionsSnapshot') return self.filter_by_symbols_since_limit(snapshot, symbols, since, limit, True) newPositions = await self.subscribe_private(messageHash, subscriptionHash, channel, True, params) if self.newUpdates: return newPositions return self.filter_by_symbols_since_limit(self.positions, symbols, since, limit, True) def set_positions_cache(self, client: Client, params: dict = {}): fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', False) if fetchPositionsSnapshot: messageHash = 'fetchPositionsSnapshot' if not (messageHash in client.futures): client.future(messageHash) self.spawn(self.load_positions_snapshot, client, messageHash, params) else: self.positions = ArrayCacheBySymbolById() async def load_positions_snapshot(self, client, messageHash, params): positions = await self.fetch_positions(None, params) self.positions = ArrayCacheBySymbolById() cache = self.positions for i in range(0, len(positions)): position = positions[i] cache.append(position) # don't remove the future from the .futures cache future = client.futures[messageHash] future.resolve(cache) client.resolve(cache, 'positions') async def un_watch_positions(self, symbols: Strings = None, params={}) -> Any: """ unWatches all open positions https://www.weex.com/api-doc/contract/Websocket/private/Positions-Channel :param str[] [symbols]: not used by the exchange, unsubscription from positions is global for all symbols :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: status of the unwatch request """ if symbols is not None: raise NotSupported(self.id + ' unWatchPositions does not support a symbols argument. Unsubscribing from positions is global for all symbols.') subHash = 'positions' unSubHash = 'unsubscribe::' + subHash channel = 'positions' subscription = { 'unsubscribe': True, 'messageHashes': [unSubHash], 'subMessageHashes': [subHash], 'topic': 'positions', 'subHashIsPrefix': True, } return await self.subscribe_private(unSubHash, unSubHash, channel, True, params, subscription) def handle_positions(self, client, message): # # { # "e": "positions", # "E": 1776192398399, # "v": 319, # "msgEvent": "OrderUpdate", # "d": [ # { # "id": "739004481374519656", # "coin": "USDT", # "symbol": "DOGEUSDT", # "side": "LONG", # "marginMode": "CROSSED", # "separatedMode": "COMBINED", # "separatedOpenOrderId": "0", # "leverage": "11", # "size": "100", # "openValue": "9.31100", # "openFee": "0.00744880", # "fundingFee": "0", # "isolatedMargin": "0", # "autoAppendIsolatedMargin": False, # "cumOpenSize": "100", # "cumOpenValue": "9.31100", # "cumOpenFee": "0.00744880", # "cumCloseSize": "0", # "cumCloseValue": "0", # "cumCloseFee": "0", # "cumFundingFee": "0", # "cumLiquidateFee": "0", # "createdMatchSequenceId": "5792711540", # "updatedMatchSequenceId": "5792711540", # "createdTime": "1776192398399", # "updatedTime": "1776192398399" # } # ] # } # if self.positions is None: self.positions = ArrayCacheBySymbolById() cache = self.positions newPositions = [] data = self.safe_list(message, 'd', []) for i in range(0, len(data)): rawPosition = self.safe_dict(data, i, {}) position = self.parse_ws_position(rawPosition) cache.append(position) newPositions.append(position) messageHashes = self.find_message_hashes(client, 'positions::') for i in range(0, len(messageHashes)): messageHash = messageHashes[i] parts = messageHash.split('::') symbolsString = parts[1] symbols = symbolsString.split(',') positions = self.filter_by_array(newPositions, 'symbol', symbols, False) if not self.is_empty(positions): client.resolve(positions, messageHash) client.resolve(newPositions, 'positions') def parse_ws_position(self, position, market=None): # same api return self.parse_position(position, market) def get_market_from_client_and_message(self, client: Client, message): url = client.url marketType = 'spot' if url.find('contract') >= 0: marketType = 'swap' marketId = self.safe_string(message, 's') market = self.safe_market(marketId, None, None, marketType) return market async def pong(self, client: Client, message): # # {"event": "ping", "time": "1776078750000"} - public # # {"type": "ping", "time": "1776172740000"} - private # response: dict = { 'id': self.request_id(), 'method': 'PONG', } await client.send(response) def handle_ping(self, client: Client, message): self.spawn(self.pong, client, message) def handle_subscription_status(self, client: Client, message): # # {"result": True, "id": 2} # id = self.safe_string(message, 'id') subscriptionsById = self.index_by(client.subscriptions, 'id') subscription = self.safe_dict(subscriptionsById, id, {}) unsubscribe = self.safe_bool(subscription, 'unsubscribe', False) if unsubscribe: subHashIsPrefix = self.safe_bool(subscription, 'subHashIsPrefix', False) messageHashes = self.safe_list(subscription, 'messageHashes', []) subHashes = self.safe_list(subscription, 'subMessageHashes', []) for i in range(0, len(messageHashes)): unSubHash = self.safe_string(messageHashes, i) subHash = self.safe_string(subHashes, i) self.clean_unsubscription(client, subHash, unSubHash, subHashIsPrefix) self.clean_cache(subscription) return message def handle_error_message(self, client: Client, message): # # { # "result": False, # "id": 1, # "msg": "INVALID_ARGUMENT: invalid symbol : ASDFS_SPBL" # } # result = self.safe_bool(message, 'result', True) if not result: msg = self.safe_string(message, 'msg', '') feedback = self.id + ' ' + self.json(message) try: self.throw_exactly_matched_exception(self.exceptions['exact'], msg, feedback) self.throw_broadly_matched_exception(self.exceptions['broad'], msg, feedback) raise ExchangeError(feedback) except Exception as error: client.reject(error) return True return False def handle_message(self, client: Client, message): # # {"id": "5", "method": "PONG"} # # {"result": True, "id": 2} # # { # "result": False, # "id": 1, # "msg": "INVALID_ARGUMENT: invalid symbol : ASDFS_SPBL" # } # if self.handle_error_message(client, message): return id = self.safe_string(message, 'id') if id is not None: self.handle_subscription_status(client, message) return event = self.safe_string_n(message, ['e', 'event', 'type']) if event == 'ping': self.handle_ping(client, message) elif event == 'ticker': self.handle_ticker(client, message) elif (event == 'trade') or (event == 'tradeSnapshot'): self.handle_trade(client, message) elif (event == 'kline') or (event == 'klineSnapshot'): self.handle_ohlcv(client, message) elif (event == 'depth') or (event == 'depthSnapshot'): self.handle_order_book(client, message) elif event == 'bookTicker': self.handle_bid_ask(client, message) elif event == 'fill': self.handle_my_trades(client, message) elif event == 'orders': self.handle_orders(client, message) elif event == 'account': self.handle_balance(client, message) elif event == 'positions': self.handle_positions(client, message)