UNPKG

@kraken-crypto/ccxt

Version:

A cryptocurrency trading API with more than 100 exchanges in JavaScript / TypeScript / Python / C# / PHP / Go

1,161 lines 132 kB
// --------------------------------------------------------------------------- import Exchange from './abstract/toobit.js'; import { OperationFailed, ArgumentsRequired, ExchangeError, BadRequest, OrderNotFound, BadSymbol, NotSupported, PermissionDenied, RateLimitExceeded, OperationRejected, InvalidOrder, InsufficientFunds } from './base/errors.js'; import { Precise } from './base/Precise.js'; import { TICK_SIZE } from './base/functions/number.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; // --------------------------------------------------------------------------- /** * @class toobit * @augments Exchange */ export default class toobit extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'toobit', 'name': 'Toobit', 'countries': ['KY'], 'version': 'v1', 'rateLimit': 20, 'certified': false, 'pro': true, 'has': { 'CORS': undefined, 'spot': true, 'margin': false, 'swap': true, 'future': false, 'option': false, 'cancelAllOrders': true, 'cancelOrder': true, 'cancelOrders': true, 'createOrder': true, 'fetchBalance': true, 'fetchBidsAsks': true, 'fetchCurrencies': true, 'fetchDepositAddress': true, 'fetchDeposits': true, 'fetchFundingRateHistory': true, 'fetchFundingRates': true, 'fetchIndexOHLCV': true, 'fetchLastPrices': true, 'fetchLedger': true, 'fetchMarkets': true, 'fetchMarkOHLCV': true, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchStatus': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, 'fetchWithdrawals': true, 'setMarginMode': true, 'transfer': true, 'withdraw': true, }, 'urls': { 'logo': 'https://github.com/user-attachments/assets/0c7a97d5-182c-492e-b921-23540c868e0e', 'api': { 'common': 'https://api.toobit.com', 'private': 'https://api.toobit.com', }, 'www': 'https://www.toobit.com/', 'doc': [ 'https://toobit-docs.github.io/apidocs/spot/v1/en/', 'https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/', ], 'referral': { 'url': 'https://www.toobit.com/en-US/r?i=IFFPy0', 'discount': 0.1, }, 'fees': 'https://www.toobit.com/fee', }, 'api': { 'common': { 'get': { 'api/v1/time': 1, 'api/v1/ping': 1, 'api/v1/exchangeInfo': 1, 'quote/v1/depth': 1, 'quote/v1/depth/merged': 1, 'quote/v1/trades': 1, 'quote/v1/klines': 1, 'quote/v1/index/klines': 1, 'quote/v1/markPrice/klines': 1, 'quote/v1/markPrice': 1, 'quote/v1/index': 1, 'quote/v1/ticker/24hr': 40, 'quote/v1/contract/ticker/24hr': 40, 'quote/v1/ticker/price': 1, 'quote/v1/ticker/bookTicker': 1, 'api/v1/futures/fundingRate': 1, 'api/v1/futures/historyFundingRate': 1, }, }, 'private': { 'get': { 'api/v1/account': 5, 'api/v1/account/checkApiKey': 1, 'api/v1/spot/order': 1 * 1.67, 'api/v1/spot/openOrders': 1 * 1.67, 'api/v1/futures/openOrders': 1 * 1.67, 'api/v1/spot/tradeOrders': 5 * 1.67, 'api/v1/futures/historyOrders': 5 * 1.67, 'api/v1/account/trades': 5 * 1.67, 'api/v1/account/balanceFlow': 5, 'api/v1/account/depositOrders': 5, 'api/v1/account/withdrawOrders': 5, 'api/v1/account/deposit/address': 1, // contracts 'api/v1/subAccount': 5, 'api/v1/futures/accountLeverage': 1, 'api/v1/futures/order': 1 * 1.67, 'api/v1/futures/positions': 5 * 1.67, 'api/v1/futures/balance': 5, 'api/v1/futures/userTrades': 5 * 1.67, 'api/v1/futures/balanceFlow': 5, 'api/v1/futures/commissionRate': 5, 'api/v1/futures/todayPnl': 5, }, 'post': { 'api/v1/spot/orderTest': 1 * 1.67, 'api/v1/spot/order': 1 * 1.67, 'api/v1/futures/order': 1 * 1.67, 'api/v1/spot/batchOrders': 2 * 1.67, 'api/v1/subAccount/transfer': 1, 'api/v1/account/withdraw': 1, // contracts 'api/v1/futures/marginType': 1, 'api/v1/futures/leverage': 1, 'api/v1/futures/batchOrders': 2 * 1.67, 'api/v1/futures/position/trading-stop': 3 * 1.67, 'api/v1/futures/positionMargin': 1, 'api/v1/userDataStream': 1, 'api/v1/listenKey': 1, }, 'delete': { 'api/v1/spot/order': 1 * 1.67, 'api/v1/futures/order': 1 * 1.67, 'api/v1/spot/openOrders': 5 * 1.67, 'api/v1/futures/batchOrders': 5 * 1.67, 'api/v1/spot/cancelOrderByIds': 5 * 1.67, 'api/v1/futures/cancelOrderByIds': 5 * 1.67, 'api/v1/listenKey': 1, }, 'put': { 'api/v1/listenKey': 1, }, }, }, 'timeframes': { '1m': '1m', '3m': '3m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '1h', '2h': '2h', '4h': '4h', '6h': '6h', '8h': '8h', '12h': '12h', '1d': '1d', '1w': '1w', '1M': '1M', }, 'precisionMode': TICK_SIZE, 'exceptions': { 'exact': { '-1000': OperationFailed, '-1001': OperationFailed, '-1002': PermissionDenied, '-1003': RateLimitExceeded, '-1004': BadRequest, '-1006': OperationFailed, '-1007': OperationFailed, '-1014': OperationFailed, '-1015': RateLimitExceeded, '-1016': OperationRejected, '-1020': OperationRejected, '-1021': OperationRejected, '-1022': OperationRejected, '-1100': BadRequest, '-1101': BadRequest, '-1102': BadRequest, '-1103': BadRequest, '-1104': BadRequest, '-1105': BadRequest, '-1106': BadRequest, '-1111': BadRequest, '-1112': OperationRejected, '-1114': BadRequest, '-1115': BadRequest, '-1116': BadRequest, '-1117': BadRequest, '-1118': InvalidOrder, '-1119': InvalidOrder, '-1120': BadRequest, '-1121': BadRequest, '-1125': OperationRejected, '-1127': OperationRejected, '-1128': BadRequest, '-1130': BadRequest, '-1132': OperationRejected, '-1133': OperationRejected, '-1134': OperationRejected, '-1135': OperationRejected, '-1136': OperationRejected, '-1137': OperationRejected, '-1138': OperationRejected, '-1139': OperationRejected, '-1140': OperationRejected, '-1141': InvalidOrder, '-1142': InvalidOrder, '-1143': InvalidOrder, '-1144': OperationRejected, '-1145': OperationRejected, '-1146': OperationFailed, '-1147': OperationFailed, '-1193': OperationRejected, '-1194': OperationRejected, '-1195': OperationRejected, '-1196': OperationRejected, '-1197': OperationRejected, '-1198': OperationRejected, '-1199': OperationRejected, '-1200': OperationRejected, '-1201': OperationRejected, '-1202': OperationRejected, '-1203': OperationRejected, '-1206': OperationRejected, '-2010': OperationFailed, '-2011': OperationFailed, '-2013': InvalidOrder, '-2014': PermissionDenied, '-2015': PermissionDenied, '-2016': BadRequest, // errors above 3xxx are from swap API '-3050': ExchangeError, '-3101': OperationRejected, '-3102': OperationRejected, '-3103': BadRequest, '-3105': OperationRejected, '-3107': OperationRejected, '-3108': OperationRejected, '-3109': OperationRejected, '-3110': InsufficientFunds, '-3116': OperationRejected, '-3117': OperationRejected, '-3120': OperationRejected, '-3124': OperationRejected, '-3125': OperationRejected, '-3126': OperationRejected, '-3127': OperationFailed, '-3128': OperationRejected, '-3129': BadRequest, '-3130': OperationRejected, '-3131': NotSupported, // Leverage reduction is not supported in Isolated Margin Mode with open positions. }, 'broad': { 'Unknown order sent': OrderNotFound, 'Duplicate order sent': InvalidOrder, 'Market is closed': OperationRejected, 'Account has insufficient balance for requested action': InsufficientFunds, 'Market orders are not supported for this symbol': OperationRejected, 'Iceberg orders are not supported for this symbol': OperationRejected, 'Stop loss orders are not supported for this symbol': OperationRejected, 'Stop loss limit orders are not supported for this symbol': OperationRejected, 'Take profit orders are not supported for this symbol': OperationRejected, 'Take profit limit orders are not supported for this symbol': OperationRejected, 'QTY is zero or less': BadRequest, 'IcebergQty exceeds QTY': OperationRejected, 'This action disabled is on this account': PermissionDenied, 'Unsupported order combination': BadRequest, 'Order would trigger immediately': OperationRejected, 'Cancel order is invalid. Check origClOrdId and orderId': OperationRejected, 'Order would immediately match and take': OperationRejected, }, }, 'commonCurrencies': {}, 'options': { 'defaultType': 'spot', 'accountsByType': { 'spot': 'MAIN', 'swap': 'FUTURES', }, 'networks': { 'BTC': 'BTC', 'ERC20': 'ETH', 'ETH': 'ETH', 'BEP20': 'BSC', 'TRC20': 'TRX', 'SOL': 'SOL', 'MATIC': 'MATIC', 'ARBONE': 'ARBITRUM', 'BASE': 'BASE', 'TON': 'TON', 'AVAXC': 'AVAXC', 'DOGE': 'DOGE', 'XRP': 'XRP', 'DOT': 'DOT', 'ADA': 'ADA', 'LTC': 'LTC', 'APT': 'APT', 'ATOM': 'ATOM', 'ALGO': 'ALGO', 'NEAR': 'NEAR', 'XLM': 'XLM', 'SUI': 'SUI', 'ETC': 'ETC', 'EOS': 'EOS', 'WAVES': 'WAVES', 'ICP': 'ICP', 'ONE': 'ONE', // 'CHZ2': 'CHZ2', }, 'networksById': { 'ETH': 'ERC20', 'ERC20': 'ERC20', }, }, 'features': { 'spot': { 'sandbox': false, 'createOrder': { 'marginMode': false, 'triggerPrice': true, 'triggerPriceType': undefined, 'triggerDirection': false, 'stopLossPrice': false, 'takeProfitPrice': false, 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': true, 'FOK': true, 'PO': true, 'GTD': false, }, 'hedged': false, 'trailing': false, 'leverage': false, 'marketBuyRequiresPrice': false, 'marketBuyByCost': false, 'selfTradePrevention': false, 'iceberg': false, }, 'createOrders': undefined, 'fetchOHLCV': { 'limit': 1000, }, 'fetchMyTrades': { 'marginMode': false, 'limit': 1000, 'daysBack': 100000, 'untilDays': 100000, 'symbolRequired': true, }, 'fetchOrder': { 'marginMode': false, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOpenOrders': { 'marginMode': false, 'limit': 1000, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOrders': { 'marginMode': false, 'limit': 500, 'daysBack': 100000, 'untilDays': 100000, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchClosedOrders': undefined, }, 'forDerivatives': { 'createOrders': undefined, }, 'swap': { 'linear': undefined, 'inverse': undefined, }, 'future': { 'linear': undefined, 'inverse': undefined, }, }, }); } /** * @method * @name toobit#fetchStatus * @description the latest known information on the availability of the exchange API * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#test-connectivity * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure} */ async fetchStatus(params = {}) { const response = await this.commonGetApiV1Ping(params); return { 'status': 'ok', 'updated': undefined, 'eta': undefined, 'url': undefined, 'info': response, }; } /** * @method * @name toobit#fetchTime * @description fetches the current integer timestamp in milliseconds from the exchange server * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#check-server-time * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {int} the current integer timestamp in milliseconds from the exchange server */ async fetchTime(params = {}) { const response = await this.commonGetApiV1Time(params); // // { // "serverTime": 1699827319559 // } // return this.safeInteger(response, 'serverTime'); } /** * @method * @name toobit#fetchCurrencies * @description fetches all available currencies on an exchange * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} an associative dictionary of currencies */ async fetchCurrencies(params = {}) { const response = await this.commonGetApiV1ExchangeInfo(params); this.options['exchangeInfo'] = response; // we store it in options for later use in fetchMarkets // // { // "timezone": "UTC", // "serverTime": "1755583099926", // "brokerFilters": [], // "symbols": [ // { // "filters": [ // { // "minPrice": "0.01", // "maxPrice": "10000000.00000000", // "tickSize": "0.01", // "filterType": "PRICE_FILTER" // }, // { // "minQty": "0.0001", // "maxQty": "4000", // "stepSize": "0.0001", // "filterType": "LOT_SIZE" // }, // { // "minNotional": "5", // "filterType": "MIN_NOTIONAL" // }, // { // "minAmount": "5", // "maxAmount": "6600000", // "minBuyPrice": "0.01", // "filterType": "TRADE_AMOUNT" // }, // { // "maxSellPrice": "99999999", // "buyPriceUpRate": "0.1", // "sellPriceDownRate": "0.1", // "filterType": "LIMIT_TRADING" // }, // { // "buyPriceUpRate": "0.1", // "sellPriceDownRate": "0.1", // "filterType": "MARKET_TRADING" // }, // { // "noAllowMarketStartTime": "0", // "noAllowMarketEndTime": "0", // "limitOrderStartTime": "0", // "limitOrderEndTime": "0", // "limitMinPrice": "0", // "limitMaxPrice": "0", // "filterType": "OPEN_QUOTE" // } // ], // "exchangeId": "301", // "symbol": "ETHUSDT", // "symbolName": "ETHUSDT", // "status": "TRADING", // "baseAsset": "ETH", // "baseAssetName": "ETH", // "baseAssetPrecision": "0.0001", // "quoteAsset": "USDT", // "quoteAssetName": "USDT", // "quotePrecision": "0.01", // "icebergAllowed": false, // "isAggregate": false, // "allowMargin": true, // } // ], // "options": [], // "contracts": [ // { // "filters": [ ... ], // "exchangeId": "301", // "symbol": "BTC-SWAP-USDT", // "symbolName": "BTC-SWAP-USDTUSDT", // "status": "TRADING", // "baseAsset": "BTC-SWAP-USDT", // "baseAssetPrecision": "0.001", // "quoteAsset": "USDT", // "quoteAssetPrecision": "0.1", // "icebergAllowed": false, // "inverse": false, // "index": "BTC", // "indexToken": "BTCUSDT", // "marginToken": "USDT", // "marginPrecision": "0.0001", // "contractMultiplier": "0.001", // "underlying": "BTC", // "riskLimits": [ // { // "riskLimitId": "200020911", // "quantity": "42000.0", // "initialMargin": "0.02", // "maintMargin": "0.01", // "isWhite": false // }, // { // "riskLimitId": "200020912", // "quantity": "84000.0", // "initialMargin": "0.04", // "maintMargin": "0.02", // "isWhite": false // }, // ... // ] // }, // ], // "coins": [ // { // "orgId": "9001", // "coinId": "TCOM", // "coinName": "TCOM", // "coinFullName": "TCOM", // "allowWithdraw": true, // "allowDeposit": true, // "chainTypes": [ // { // "chainType": "BSC", // "withdrawFee": "49.55478", // "minWithdrawQuantity": "77", // "maxWithdrawQuantity": "0", // "minDepositQuantity": "48", // "allowDeposit": true, // "allowWithdraw": false // } // ], // "isVirtual": false // }, // ... // const coins = this.safeList(response, 'coins', []); const result = {}; for (let i = 0; i < coins.length; i++) { const coin = coins[i]; const parsed = this.parseCurrency(coin); const code = parsed['code']; result[code] = parsed; } return result; } parseCurrency(rawCurrency) { const id = this.safeString(rawCurrency, 'coinId'); const code = this.safeCurrencyCode(id); const networks = {}; const rawNetworks = this.safeList(rawCurrency, 'chainTypes'); for (let j = 0; j < rawNetworks.length; j++) { const rawNetwork = rawNetworks[j]; const networkId = this.safeString(rawNetwork, 'chainType'); const networkCode = this.networkIdToCode(networkId); networks[networkCode] = { 'id': networkId, 'network': networkCode, 'margin': undefined, 'deposit': this.safeBool(rawNetwork, 'allowDeposit'), 'withdraw': this.safeBool(rawNetwork, 'allowWithdraw'), 'active': undefined, 'fee': this.safeNumber(rawNetwork, 'withdrawFee'), 'precision': undefined, 'limits': { 'deposit': { 'min': this.safeNumber(rawNetwork, 'minDepositQuantity'), 'max': undefined, }, 'withdraw': { 'min': this.safeNumber(rawNetwork, 'minWithdrawQuantity'), 'max': this.safeNumber(rawNetwork, 'maxWithdrawQuantity'), }, }, 'info': rawNetwork, }; } return this.safeCurrencyStructure({ 'id': id, 'code': code, 'name': this.safeString(rawCurrency, 'coinFullName'), 'type': undefined, 'active': undefined, 'deposit': this.safeBool(rawCurrency, 'allowDeposit'), 'withdraw': this.safeBool(rawCurrency, 'allowWithdraw'), 'fee': undefined, 'precision': undefined, 'limits': { 'amount': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': undefined, 'max': undefined, }, }, 'networks': networks, 'info': rawCurrency, }); } /** * @method * @name toobit#fetchMarkets * @description retrieves data on all markets for toobit * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#exchange-information * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#exchange-information * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} an array of objects representing market data */ async fetchMarkets(params = {}) { let response = this.safeDict(this.options, 'exchangeInfo'); if (response !== undefined) { this.options['exchangeInfo'] = undefined; // reset it to avoid using old cached data } else { response = await this.commonGetApiV1ExchangeInfo(params); } // // { // "timezone": "UTC", // "serverTime": "1755583099926", // "brokerFilters": [], // "symbols": [ // { // "filters": [ // { // "minPrice": "0.01", // "maxPrice": "10000000.00000000", // "tickSize": "0.01", // "filterType": "PRICE_FILTER" // }, // { // "minQty": "0.0001", // "maxQty": "4000", // "stepSize": "0.0001", // "filterType": "LOT_SIZE" // }, // { // "minNotional": "5", // "filterType": "MIN_NOTIONAL" // }, // { // "minAmount": "5", // "maxAmount": "6600000", // "minBuyPrice": "0.01", // "filterType": "TRADE_AMOUNT" // }, // { // "maxSellPrice": "99999999", // "buyPriceUpRate": "0.1", // "sellPriceDownRate": "0.1", // "filterType": "LIMIT_TRADING" // }, // { // "buyPriceUpRate": "0.1", // "sellPriceDownRate": "0.1", // "filterType": "MARKET_TRADING" // }, // { // "noAllowMarketStartTime": "0", // "noAllowMarketEndTime": "0", // "limitOrderStartTime": "0", // "limitOrderEndTime": "0", // "limitMinPrice": "0", // "limitMaxPrice": "0", // "filterType": "OPEN_QUOTE" // } // ], // "exchangeId": "301", // "symbol": "ETHUSDT", // "symbolName": "ETHUSDT", // "status": "TRADING", // "baseAsset": "ETH", // "baseAssetName": "ETH", // "baseAssetPrecision": "0.0001", // "quoteAsset": "USDT", // "quoteAssetName": "USDT", // "quotePrecision": "0.01", // "icebergAllowed": false, // "isAggregate": false, // "allowMargin": true, // } // ], // "options": [], // "contracts": [ // { // "filters": [ ... ], // "exchangeId": "301", // "symbol": "BTC-SWAP-USDT", // "symbolName": "BTC-SWAP-USDTUSDT", // "status": "TRADING", // "baseAsset": "BTC-SWAP-USDT", // "baseAssetPrecision": "0.001", // "quoteAsset": "USDT", // "quoteAssetPrecision": "0.1", // "icebergAllowed": false, // "inverse": false, // "index": "BTC", // "indexToken": "BTCUSDT", // "marginToken": "USDT", // "marginPrecision": "0.0001", // "contractMultiplier": "0.001", // "underlying": "BTC", // "riskLimits": [ // { // "riskLimitId": "200020911", // "quantity": "42000.0", // "initialMargin": "0.02", // "maintMargin": "0.01", // "isWhite": false // }, // { // "riskLimitId": "200020912", // "quantity": "84000.0", // "initialMargin": "0.04", // "maintMargin": "0.02", // "isWhite": false // }, // ... // ] // }, // ], // "coins": [ // { // "orgId": "9001", // "coinId": "TCOM", // "coinName": "TCOM", // "coinFullName": "TCOM", // "allowWithdraw": true, // "allowDeposit": true, // "chainTypes": [ // { // "chainType": "BSC", // "withdrawFee": "49.55478", // "minWithdrawQuantity": "77", // "maxWithdrawQuantity": "0", // "minDepositQuantity": "48", // "allowDeposit": true, // "allowWithdraw": false // } // ], // "isVirtual": false // }, // ... // const symbols = this.safeList(response, 'symbols', []); const contracts = this.safeList(response, 'contracts', []); const all = this.arrayConcat(symbols, contracts); const result = []; for (let i = 0; i < all.length; i++) { const market = all[i]; const parsed = this.parseMarket(market); result.push(parsed); } return result; } parseMarket(market) { const id = this.safeString(market, 'symbol'); const baseId = this.safeString(market, 'baseAsset'); const quoteId = this.safeString(market, 'quoteAsset'); const baseParts = baseId.split('-'); const baseIdClean = baseParts[0]; const base = this.safeCurrencyCode(baseIdClean); const quote = this.safeCurrencyCode(quoteId); const settleId = this.safeString(market, 'marginToken'); const settle = this.safeCurrencyCode(settleId); const status = this.safeString(market, 'status'); const active = (status === 'TRADING'); const filters = this.safeList(market, 'filters', []); const filtersByType = this.indexBy(filters, 'filterType'); const priceFilter = this.safeDict(filtersByType, 'PRICE_FILTER', {}); const lotSizeFilter = this.safeDict(filtersByType, 'LOT_SIZE', {}); const minNotionalFilter = this.safeDict(filtersByType, 'MIN_NOTIONAL', {}); let symbol = base + '/' + quote; const isContract = ('contractMultiplier' in market); const inverse = this.safeBool2(market, 'isInverse', 'inverse'); if (isContract) { symbol += ':' + settle; } return this.safeMarketStructure({ 'id': id, 'symbol': symbol, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'quoteId': quoteId, 'settleId': settleId, 'type': isContract ? 'swap' : 'spot', 'spot': !isContract, 'margin': false, 'swap': isContract, 'future': false, 'option': false, 'active': active, 'contract': isContract, 'linear': isContract ? !inverse : undefined, 'inverse': isContract ? inverse : undefined, 'contractSize': this.safeNumber(market, 'contractMultiplier'), 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.safeNumber(lotSizeFilter, 'stepSize'), 'price': this.safeNumber(priceFilter, 'tickSize'), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber(lotSizeFilter, 'minQty'), 'max': this.safeNumber(lotSizeFilter, 'maxQty'), }, 'price': { 'min': this.safeNumber(priceFilter, 'minPrice'), 'max': this.safeNumber(priceFilter, 'maxPrice'), }, 'cost': { 'min': this.safeNumber(minNotionalFilter, 'minNotional'), 'max': undefined, }, }, 'created': undefined, 'info': market, }); } /** * @method * @name toobit#fetchOrderBook * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#order-book * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#order-book * @param {string} 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 {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols */ async fetchOrderBook(symbol, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], }; if (limit !== undefined) { request['limit'] = limit; } const response = await this.commonGetQuoteV1Depth(this.extend(request, params)); // // { // "t": "1755593995237", // "b": [ // [ // "115186.47", // "4.184864" // ], // [ // "115186.46", // "0.002756" // ], // ... // ], // "a": [ // [ // "115186.48", // "6.137369" // ], // [ // "115186.49", // "0.002914" // ], // ... // ] // } // const timestamp = this.safeInteger(response, 't'); return this.parseOrderBook(response, market['symbol'], timestamp, 'b', 'a'); } /** * @method * @name toobit#fetchTrades * @description get a list of the most recent trades for a particular symbol * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#recent-trades-list * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#recent-trades-list * @param {string} 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 number of trades to fetch * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades} */ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], }; if (limit !== undefined) { request['limit'] = limit; } const response = await this.commonGetQuoteV1Trades(this.extend(request, params)); // // [ // { // "t": "1755594277287", // "p": "115276.99", // "q": "0.001508", // "ibm": true // }, // ] // return this.parseTrades(response, market, since, limit); } parseTrade(trade, market = undefined) { // // fetchTrades // // { // "t": "1755594277287", // "p": "115276.99", // "q": "0.001508", // "ibm": true // }, // // watchTrades have also an additional fields: // "v": "4864732022868004630", // trade id // "m": true, // is the buyer taker // // fetchMyTrades // // { // "id": "2024934575206059008", // "symbol": "ETHUSDT", // "orderId": "2024934575097029888", // "ticketId": "4864450547563401875", // "price": "4641.21", // "qty": "0.001", // "time": "1756127012094", // "isMaker": false, // "commission": "0.00464121", // "commissionAsset": "USDT", // "makerRebate": "0", // "symbolName": "ETHUSDT", // only in SPOT // "isBuyer": false, // only in SPOT // "feeAmount": "0.00464121", // only in SPOT // "feeCoinId": "USDT", // only in SPOT // "fee": { // only in SPOT // "feeCoinId": "USDT", // "feeCoinName": "USDT", // "fee": "0.00464121" // }, // "type": "LIMIT", // only in CONTRACT // "side": "BUY_OPEN", // only in CONTRACT // "realizedPnl": "0", // only in CONTRACT // }, // const timestamp = this.safeInteger2(trade, 't', 'time'); const priceString = this.safeString2(trade, 'p', 'price'); const amountString = this.safeString2(trade, 'q', 'qty'); const isBuyer = this.safeBool(trade, 'isBuyer'); let side = undefined; let isBuyerMaker = this.safeBool(trade, 'ibm'); if (isBuyerMaker === undefined) { const isBuyerTaker = this.safeBool(trade, 'm'); if (isBuyerTaker !== undefined) { isBuyerMaker = !isBuyerTaker; } } if (isBuyerMaker !== undefined) { if (isBuyerMaker) { side = 'sell'; } else { side = 'buy'; } } else { if (isBuyer) { side = 'buy'; } else { side = 'sell'; } } const feeCurrencyId = this.safeString(trade, 'feeCoinId'); const feeAmount = this.safeString(trade, 'feeAmount'); let fee = undefined; if (feeAmount !== undefined) { fee = { 'currency': this.safeCurrencyCode(feeCurrencyId), 'cost': feeAmount, }; } const isMaker = this.safeBool(trade, 'isMaker'); let takerOrMaker = undefined; if (isMaker !== undefined) { takerOrMaker = isMaker ? 'maker' : 'taker'; } market = this.safeMarket(undefined, market); const symbol = market['symbol']; return this.safeTrade({ 'info': trade, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': symbol, 'id': this.safeString2(trade, 'id', 'v'), 'order': this.safeString(trade, 'orderId'), 'type': undefined, 'side': side, 'amount': amountString, 'price': priceString, 'cost': undefined, 'takerOrMaker': takerOrMaker, 'fee': fee, }, market); } /** * @method * @name toobit#fetchOHLCV * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#kline-candlestick-data * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#kline-candlestick-data * @param {string} symbol unified symbol of the market to fetch OHLCV data for * @param {string} 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 {object} [params] extra parameters specific to the exchange API endpoint * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume */ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], 'interval': this.safeString(this.timeframes, timeframe, timeframe), }; if (since !== undefined) { request['startTime'] = since; } const until = this.safeInteger(params, 'until'); if (until !== undefined) { params = this.omit(params, 'until'); request['endTime'] = until; } if (limit !== undefined) { request['limit'] = limit; } let response = undefined; let endpoint = undefined; [endpoint, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'price'); if (endpoint === 'index') { response = await this.commonGetQuoteV1IndexKlines(this.extend(request, params)); // // { // "code": 200, // "data": [ // { // "t": 1669155300000,//time // "s": "ETHUSDT",// symbol // "sn": "ETHUSDT",//symbol name // "c": "1127.1",//Close price // "h": "1130.81",//High price // "l": "1126.17",//Low price // "o": "1130.8",//Open price // "v": "0"//Volume // }, // { // "t": 1669156200000, // "s": "ETHUSDT", // "sn": "ETHUSDT", // "c": "1129.44", // "h": "1129.54", // "l": "1127.1", // "o": "1127.1", // "v": "0" // } // ] // } // } else if (endpoint === 'mark') { response = await this.commonGetQuoteV1MarkPriceKlines(this.extend(request, params)); // // { // "code": 200, // "data": [ // { // "symbol": "BTCUSDT",// Symbol // "time": 1670157900000,// time // "low": "16991.14096",//Low price // "open": "16991.78288",//Open price // "high": "16996.30641",// High prce // "close": "16996.30641",// Close price // "volume": "0",// Volume // "curId": 1670157900000 // } // ] // } // } else { response = await this.commonGetQuoteV1Klines(this.extend(request, params)); // // [ // [ // 1755540660000, // "116399.99", // "116399.99", // "116360.09", // "116360.1", // "2.236869", // 0, // "260303.79722607", // 22, // "2.221061", // "258464.10338267" // ], // ... // } return this.parseOHLCVs(response, market, timeframe, since, limit); } parseOHLCV(ohlcv, market = undefined) { return [ this.safeIntegerN(ohlcv, [0