Files
beast-trader/dashboard/venv/lib/python3.12/site-packages/ccxt/pro/weex.py

1810 lines
79 KiB
Python

# -*- 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 <https://docs.ccxt.com/?id=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 <https://docs.ccxt.com/?id=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 <https://docs.ccxt.com/?id=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 <https://docs.ccxt.com/?id=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 <https://docs.ccxt.com/?id=public-trades>`
"""
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 <https://docs.ccxt.com/?id=public-trades>`
"""
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 <https://docs.ccxt.com/?id=public-trades>`
"""
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 <https://docs.ccxt.com/?id=public-trades>`
"""
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 <https://docs.ccxt.com/?id=order-book-structure>` 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 <https://docs.ccxt.com/?id=order-book-structure>` 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 <https://docs.ccxt.com/?id=order-book-structure>` 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 <https://docs.ccxt.com/?id=order-book-structure>` 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 <https://docs.ccxt.com/?id=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 <https://docs.ccxt.com/?id=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 <https://docs.ccxt.com/?id=trade-structure>`
"""
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 <https://docs.ccxt.com/?id=order-structure>`
"""
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 <https://docs.ccxt.com/?id=order-structure>`
"""
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 <https://docs.ccxt.com/?id=order-structure>`
"""
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 <https://docs.ccxt.com/?id=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 <https://docs.ccxt.com/en/latest/manual.html#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)