UNPKG

@proton/ccxt

Version:

A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 130+ exchanges

1,117 lines (1,115 loc) 111 kB
// ---------------------------------------------------------------------------- // 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 // EDIT THE CORRESPONDENT .ts FILE INSTEAD // --------------------------------------------------------------------------- import Exchange from './abstract/tokocrypto.js'; import { TRUNCATE, DECIMAL_PLACES } from './base/functions/number.js'; import { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, RateLimitExceeded, PermissionDenied, NotSupported, BadRequest, BadSymbol, AccountSuspended, OrderImmediatelyFillable, OnMaintenance, BadResponse, RequestTimeout, OrderNotFillable, MarginModeAlreadySet } from './base/errors.js'; import { Precise } from './base/Precise.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; // --------------------------------------------------------------------------- export default class tokocrypto extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'tokocrypto', 'name': 'Tokocrypto', 'countries': ['ID'], 'certified': false, 'pro': false, 'version': 'v1', // new metainfo interface 'has': { 'CORS': undefined, 'spot': true, 'margin': true, 'swap': false, 'future': false, 'option': false, 'addMargin': undefined, 'borrowMargin': undefined, 'cancelAllOrders': false, 'cancelOrder': true, 'cancelOrders': undefined, 'createDepositAddress': false, 'createOrder': true, 'createReduceOnlyOrder': undefined, 'createStopLimitOrder': false, 'createStopMarketOrder': false, 'createStopOrder': true, 'fetchAccounts': false, 'fetchBalance': true, 'fetchBidsAsks': true, 'fetchBorrowInterest': undefined, 'fetchBorrowRate': undefined, 'fetchBorrowRateHistories': undefined, 'fetchBorrowRateHistory': undefined, 'fetchBorrowRates': undefined, 'fetchBorrowRatesPerSymbol': undefined, 'fetchCanceledOrders': false, 'fetchClosedOrder': false, 'fetchClosedOrders': 'emulated', 'fetchCurrencies': false, 'fetchDeposit': false, 'fetchDepositAddress': true, 'fetchDepositAddresses': false, 'fetchDepositAddressesByNetwork': false, 'fetchDeposits': true, 'fetchDepositsWithdrawals': false, 'fetchFundingHistory': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': false, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchL3OrderBook': false, 'fetchLedger': undefined, 'fetchLeverage': false, 'fetchLeverageTiers': false, 'fetchMarketLeverageTiers': 'emulated', 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenInterestHistory': false, 'fetchOpenOrder': false, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrderBooks': false, 'fetchOrders': true, 'fetchOrderTrades': false, 'fetchPosition': false, 'fetchPositions': false, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchStatus': false, 'fetchTicker': false, 'fetchTickers': false, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': false, 'fetchTradingLimits': false, 'fetchTransactionFee': false, 'fetchTransactionFees': false, 'fetchTransactions': false, 'fetchTransfers': false, 'fetchWithdrawal': false, 'fetchWithdrawals': true, 'fetchWithdrawalWhitelist': false, 'reduceMargin': false, 'repayMargin': false, 'setLeverage': false, 'setMargin': false, 'setMarginMode': false, 'setPositionMode': false, 'signIn': false, 'transfer': false, 'withdraw': true, }, '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', '3d': '3d', '1w': '1w', '1M': '1M', }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/183870484-d3398d0c-f6a1-4cce-91b8-d58792308716.jpg', 'api': { 'rest': { 'public': 'https://www.tokocrypto.com', 'binance': 'https://api.binance.com/api/v3', 'private': 'https://www.tokocrypto.com', }, }, 'www': 'https://tokocrypto.com', // 'referral': 'https://www.binance.us/?ref=35005074', 'doc': 'https://www.tokocrypto.com/apidocs/', 'fees': 'https://www.tokocrypto.com/fees/newschedule', }, 'api': { 'binance': { 'get': { 'ping': 1, 'time': 1, 'depth': { 'cost': 1, 'byLimit': [[100, 1], [500, 5], [1000, 10], [5000, 50]] }, 'trades': 1, 'aggTrades': 1, 'historicalTrades': 5, 'klines': 1, 'ticker/24hr': { 'cost': 1, 'noSymbol': 40 }, 'ticker/price': { 'cost': 1, 'noSymbol': 2 }, 'ticker/bookTicker': { 'cost': 1, 'noSymbol': 2 }, 'exchangeInfo': 10, }, 'put': { 'userDataStream': 1, }, 'post': { 'userDataStream': 1, }, 'delete': { 'userDataStream': 1, }, }, 'public': { 'get': { 'open/v1/common/time': 1, 'open/v1/common/symbols': 1, // all the actual symbols are type 1 'open/v1/market/depth': 1, 'open/v1/market/trades': 1, 'open/v1/market/agg-trades': 1, 'open/v1/market/klines': 1, // when symbol type is not 1 }, }, 'private': { 'get': { 'open/v1/orders/detail': 1, 'open/v1/orders': 1, 'open/v1/account/spot': 1, 'open/v1/account/spot/asset': 1, 'open/v1/orders/trades': 1, 'open/v1/withdraws': 1, 'open/v1/deposits': 1, 'open/v1/deposits/address': 1, }, 'post': { 'open/v1/orders': 1, 'open/v1/orders/cancel': 1, 'open/v1/orders/oco': 1, 'open/v1/withdraws': 1, 'open/v1/user-data-stream': 1, }, }, }, 'fees': { 'trading': { 'tierBased': true, 'percentage': true, 'taker': this.parseNumber('0.0075'), 'maker': this.parseNumber('0.0075'), // 0.1% trading fee, zero fees for all trading pairs before November 1 }, }, 'precisionMode': DECIMAL_PLACES, 'options': { // 'fetchTradesMethod': 'binanceGetTrades', // binanceGetTrades, binanceGetAggTrades 'defaultTimeInForce': 'GTC', // 'defaultType': 'spot', // 'spot', 'future', 'margin', 'delivery' 'hasAlreadyAuthenticatedSuccessfully': false, 'warnOnFetchOpenOrdersWithoutSymbol': true, // 'fetchPositions': 'positionRisk', // or 'account' 'recvWindow': 5 * 1000, 'timeDifference': 0, 'adjustForTimeDifference': false, 'newOrderRespType': { 'market': 'FULL', 'limit': 'FULL', // we change it from 'ACK' by default to 'FULL' (returns immediately if limit is not hit) }, 'quoteOrderQty': false, 'networks': { 'ERC20': 'ETH', 'TRC20': 'TRX', 'BEP2': 'BNB', 'BEP20': 'BSC', 'OMNI': 'OMNI', 'EOS': 'EOS', 'SPL': 'SOL', }, 'reverseNetworks': { 'tronscan.org': 'TRC20', 'etherscan.io': 'ERC20', 'bscscan.com': 'BSC', 'explorer.binance.org': 'BEP2', 'bithomp.com': 'XRP', 'bloks.io': 'EOS', 'stellar.expert': 'XLM', 'blockchair.com/bitcoin': 'BTC', 'blockchair.com/bitcoin-cash': 'BCH', 'blockchair.com/ecash': 'XEC', 'explorer.litecoin.net': 'LTC', 'explorer.avax.network': 'AVAX', 'solscan.io': 'SOL', 'polkadot.subscan.io': 'DOT', 'dashboard.internetcomputer.org': 'ICP', 'explorer.chiliz.com': 'CHZ', 'cardanoscan.io': 'ADA', 'mainnet.theoan.com': 'AION', 'algoexplorer.io': 'ALGO', 'explorer.ambrosus.com': 'AMB', 'viewblock.io/zilliqa': 'ZIL', 'viewblock.io/arweave': 'AR', 'explorer.ark.io': 'ARK', 'atomscan.com': 'ATOM', 'www.mintscan.io': 'CTK', 'explorer.bitcoindiamond.org': 'BCD', 'btgexplorer.com': 'BTG', 'bts.ai': 'BTS', 'explorer.celo.org': 'CELO', 'explorer.nervos.org': 'CKB', 'cerebro.cortexlabs.ai': 'CTXC', 'chainz.cryptoid.info': 'VIA', 'explorer.dcrdata.org': 'DCR', 'digiexplorer.info': 'DGB', 'dock.subscan.io': 'DOCK', 'dogechain.info': 'DOGE', 'explorer.elrond.com': 'EGLD', 'blockscout.com': 'ETC', 'explore-fetchhub.fetch.ai': 'FET', 'filfox.info': 'FIL', 'fio.bloks.io': 'FIO', 'explorer.firo.org': 'FIRO', 'neoscan.io': 'NEO', 'ftmscan.com': 'FTM', 'explorer.gochain.io': 'GO', 'block.gxb.io': 'GXS', 'hash-hash.info': 'HBAR', 'www.hiveblockexplorer.com': 'HIVE', 'explorer.helium.com': 'HNT', 'tracker.icon.foundation': 'ICX', 'www.iostabc.com': 'IOST', 'explorer.iota.org': 'IOTA', 'iotexscan.io': 'IOTX', 'irishub.iobscan.io': 'IRIS', 'kava.mintscan.io': 'KAVA', 'scope.klaytn.com': 'KLAY', 'kmdexplorer.io': 'KMD', 'kusama.subscan.io': 'KSM', 'explorer.lto.network': 'LTO', 'polygonscan.com': 'POLYGON', 'explorer.ont.io': 'ONT', 'minaexplorer.com': 'MINA', 'nanolooker.com': 'NANO', 'explorer.nebulas.io': 'NAS', 'explorer.nbs.plus': 'NBS', 'explorer.nebl.io': 'NEBL', 'nulscan.io': 'NULS', 'nxscan.com': 'NXS', 'explorer.harmony.one': 'ONE', 'explorer.poa.network': 'POA', 'qtum.info': 'QTUM', 'explorer.rsk.co': 'RSK', 'www.oasisscan.com': 'ROSE', 'ravencoin.network': 'RVN', 'sc.tokenview.com': 'SC', 'secretnodes.com': 'SCRT', 'explorer.skycoin.com': 'SKY', 'steemscan.com': 'STEEM', 'explorer.stacks.co': 'STX', 'www.thetascan.io': 'THETA', 'scan.tomochain.com': 'TOMO', 'explore.vechain.org': 'VET', 'explorer.vite.net': 'VITE', 'www.wanscan.org': 'WAN', 'wavesexplorer.com': 'WAVES', 'wax.eosx.io': 'WAXP', 'waltonchain.pro': 'WTC', 'chain.nem.ninja': 'XEM', 'verge-blockchain.info': 'XVG', 'explorer.yoyow.org': 'YOYOW', 'explorer.zcha.in': 'ZEC', 'explorer.zensystem.io': 'ZEN', }, 'impliedNetworks': { 'ETH': { 'ERC20': 'ETH' }, 'TRX': { 'TRC20': 'TRX' }, }, 'legalMoney': { 'MXN': true, 'UGX': true, 'SEK': true, 'CHF': true, 'VND': true, 'AED': true, 'DKK': true, 'KZT': true, 'HUF': true, 'PEN': true, 'PHP': true, 'USD': true, 'TRY': true, 'EUR': true, 'NGN': true, 'PLN': true, 'BRL': true, 'ZAR': true, 'KES': true, 'ARS': true, 'RUB': true, 'AUD': true, 'NOK': true, 'CZK': true, 'GBP': true, 'UAH': true, 'GHS': true, 'HKD': true, 'CAD': true, 'INR': true, 'JPY': true, 'NZD': true, }, }, // https://binance-docs.github.io/apidocs/spot/en/#error-codes-2 'exceptions': { 'exact': { 'System is under maintenance.': OnMaintenance, 'System abnormality': ExchangeError, 'You are not authorized to execute this request.': PermissionDenied, 'API key does not exist': AuthenticationError, 'Order would trigger immediately.': OrderImmediatelyFillable, 'Stop price would trigger immediately.': OrderImmediatelyFillable, 'Order would immediately match and take.': OrderImmediatelyFillable, 'Account has insufficient balance for requested action.': InsufficientFunds, 'Rest API trading is not enabled.': ExchangeNotAvailable, "You don't have permission.": PermissionDenied, 'Market is closed.': ExchangeNotAvailable, 'Too many requests. Please try again later.': DDoSProtection, 'This action disabled is on this account.': AccountSuspended, '-1000': ExchangeNotAvailable, '-1001': ExchangeNotAvailable, '-1002': AuthenticationError, '-1003': RateLimitExceeded, '-1004': DDoSProtection, '-1005': PermissionDenied, '-1006': BadResponse, '-1007': RequestTimeout, '-1010': BadResponse, '-1011': PermissionDenied, '-1013': InvalidOrder, '-1014': InvalidOrder, '-1015': RateLimitExceeded, '-1016': ExchangeNotAvailable, '-1020': BadRequest, '-1021': InvalidNonce, '-1022': AuthenticationError, '-1023': BadRequest, '-1099': AuthenticationError, '-1100': BadRequest, '-1101': BadRequest, '-1102': BadRequest, '-1103': BadRequest, '-1104': BadRequest, '-1105': BadRequest, '-1106': BadRequest, '-1108': BadRequest, '-1109': AuthenticationError, '-1110': BadRequest, '-1111': BadRequest, '-1112': InvalidOrder, '-1113': BadRequest, '-1114': BadRequest, '-1115': BadRequest, '-1116': BadRequest, '-1117': BadRequest, '-1118': BadRequest, '-1119': BadRequest, '-1120': BadRequest, '-1121': BadSymbol, '-1125': AuthenticationError, '-1127': BadRequest, '-1128': BadRequest, '-1130': BadRequest, '-1131': BadRequest, '-1136': BadRequest, '-2008': AuthenticationError, '-2010': ExchangeError, '-2011': OrderNotFound, '-2013': OrderNotFound, '-2014': AuthenticationError, '-2015': AuthenticationError, '-2016': BadRequest, '-2018': InsufficientFunds, '-2019': InsufficientFunds, '-2020': OrderNotFillable, '-2021': OrderImmediatelyFillable, '-2022': InvalidOrder, '-2023': InsufficientFunds, '-2024': InsufficientFunds, '-2025': InvalidOrder, '-2026': InvalidOrder, '-2027': InvalidOrder, '-2028': InsufficientFunds, '-3000': ExchangeError, '-3001': AuthenticationError, '-3002': BadSymbol, '-3003': BadRequest, '-3004': ExchangeError, '-3005': InsufficientFunds, '-3006': InsufficientFunds, '-3007': ExchangeError, '-3008': InsufficientFunds, '-3009': BadRequest, '-3010': ExchangeError, '-3011': BadRequest, '-3012': ExchangeError, '-3013': BadRequest, '-3014': AccountSuspended, '-3015': ExchangeError, '-3016': BadRequest, '-3017': ExchangeError, '-3018': AccountSuspended, '-3019': AccountSuspended, '-3020': InsufficientFunds, '-3021': BadRequest, '-3022': AccountSuspended, '-3023': BadRequest, '-3024': ExchangeError, '-3025': BadRequest, '-3026': BadRequest, '-3027': BadSymbol, '-3028': BadSymbol, '-3029': ExchangeError, '-3036': AccountSuspended, '-3037': ExchangeError, '-3038': BadRequest, '-3041': InsufficientFunds, '-3042': BadRequest, '-3043': BadRequest, '-3044': DDoSProtection, '-3045': ExchangeError, '-3999': ExchangeError, '-4001': BadRequest, '-4002': BadRequest, '-4003': BadRequest, '-4004': AuthenticationError, '-4005': RateLimitExceeded, '-4006': BadRequest, '-4007': BadRequest, '-4008': BadRequest, '-4010': BadRequest, '-4011': BadRequest, '-4012': BadRequest, '-4013': AuthenticationError, '-4014': PermissionDenied, '-4015': ExchangeError, '-4016': PermissionDenied, '-4017': PermissionDenied, '-4018': BadSymbol, '-4019': BadSymbol, '-4021': BadRequest, '-4022': BadRequest, '-4023': ExchangeError, '-4024': InsufficientFunds, '-4025': InsufficientFunds, '-4026': InsufficientFunds, '-4027': ExchangeError, '-4028': BadRequest, '-4029': BadRequest, '-4030': ExchangeError, '-4031': ExchangeError, '-4032': ExchangeError, '-4033': BadRequest, '-4034': ExchangeError, '-4035': PermissionDenied, '-4036': BadRequest, '-4037': ExchangeError, '-4038': ExchangeError, '-4039': BadRequest, '-4040': BadRequest, '-4041': ExchangeError, '-4042': ExchangeError, '-4043': BadRequest, '-4044': BadRequest, '-4045': ExchangeError, '-4046': AuthenticationError, '-4047': BadRequest, '-5001': BadRequest, '-5002': InsufficientFunds, '-5003': InsufficientFunds, '-5004': BadRequest, '-5005': InsufficientFunds, '-5006': BadRequest, '-5007': BadRequest, '-5008': InsufficientFunds, '-5009': BadRequest, '-5010': ExchangeError, '-5011': BadRequest, '-5012': ExchangeError, '-5013': InsufficientFunds, '-5021': BadRequest, '-6001': BadRequest, '-6003': BadRequest, '-6004': ExchangeError, '-6005': InvalidOrder, '-6006': BadRequest, '-6007': BadRequest, '-6008': BadRequest, '-6009': RateLimitExceeded, '-6011': BadRequest, '-6012': InsufficientFunds, '-6013': ExchangeError, '-6014': BadRequest, '-6015': BadRequest, '-6016': BadRequest, '-6017': BadRequest, '-6018': BadRequest, '-6019': AuthenticationError, '-6020': BadRequest, '-7001': BadRequest, '-7002': BadRequest, '-9000': InsufficientFunds, '-10017': BadRequest, '-11008': InsufficientFunds, '-12014': RateLimitExceeded, '-13000': BadRequest, '-13001': BadRequest, '-13002': BadRequest, '-13003': BadRequest, '-13004': BadRequest, '-13005': BadRequest, '-13006': InvalidOrder, '-13007': AuthenticationError, '-21001': BadRequest, '-21002': BadRequest, '-21003': BadRequest, '100001003': BadRequest, '2202': InsufficientFunds, '3210': InvalidOrder, '3203': InvalidOrder, '3211': InvalidOrder, '3207': InvalidOrder, '3218': OrderNotFound, // {"code":3218,"msg":"Order does not exist","timestamp":1662739749275} }, 'broad': { 'has no operation privilege': PermissionDenied, 'MAX_POSITION': InvalidOrder, // {"code":-2010,"msg":"Filter failure: MAX_POSITION"} }, }, }); } nonce() { return this.milliseconds() - this.options['timeDifference']; } async fetchTime(params = {}) { /** * @method * @name tokocrypto#fetchTime * @see https://www.tokocrypto.com/apidocs/#check-server-time * @description fetches the current integer timestamp in milliseconds from the exchange server * @param {object} params extra parameters specific to the tokocrypto api endpoint * @returns {int} the current integer timestamp in milliseconds from the exchange server */ const response = await this.publicGetOpenV1CommonTime(params); // // // return this.safeInteger(response, 'serverTime'); } async fetchMarkets(params = {}) { /** * @method * @name tokocrypto#fetchMarkets * @see https://www.tokocrypto.com/apidocs/#get-all-supported-trading-symbol * @description retrieves data on all markets for tokocrypto * @param {object} params extra parameters specific to the exchange api endpoint * @returns {[object]} an array of objects representing market data */ const response = await this.publicGetOpenV1CommonSymbols(params); // // { // "code":0, // "msg":"Success", // "data":{ // "list":[ // { // "type":1, // "symbol":"1INCH_BTC", // "baseAsset":"1INCH", // "basePrecision":8, // "quoteAsset":"BTC", // "quotePrecision":8, // "filters":[ // {"filterType":"PRICE_FILTER","minPrice":"0.00000001","maxPrice":"1000.00000000","tickSize":"0.00000001","applyToMarket":false}, // {"filterType":"PERCENT_PRICE","multiplierUp":5,"multiplierDown":0.2,"avgPriceMins":"5","applyToMarket":false}, // {"filterType":"LOT_SIZE","minQty":"0.10000000","maxQty":"90000000.00000000","stepSize":"0.10000000","applyToMarket":false}, // {"filterType":"MIN_NOTIONAL","avgPriceMins":"5","minNotional":"0.00010000","applyToMarket":true}, // {"filterType":"ICEBERG_PARTS","applyToMarket":false,"limit":"10"}, // {"filterType":"MARKET_LOT_SIZE","minQty":"0.00000000","maxQty":"79460.14117231","stepSize":"0.00000000","applyToMarket":false}, // {"filterType":"TRAILING_DELTA","applyToMarket":false}, // {"filterType":"MAX_NUM_ORDERS","applyToMarket":false}, // {"filterType":"MAX_NUM_ALGO_ORDERS","applyToMarket":false,"maxNumAlgoOrders":"5"} // ], // "orderTypes":["LIMIT","LIMIT_MAKER","MARKET","STOP_LOSS_LIMIT","TAKE_PROFIT_LIMIT"], // "icebergEnable":1, // "ocoEnable":1, // "spotTradingEnable":1, // "marginTradingEnable":1, // "permissions":["SPOT","MARGIN"] // }, // ] // }, // "timestamp":1659492212507 // } // if (this.options['adjustForTimeDifference']) { await this.loadTimeDifference(); } const data = this.safeValue(response, 'data', {}); const list = this.safeValue(data, 'list', []); const result = []; for (let i = 0; i < list.length; i++) { const market = list[i]; const baseId = this.safeString(market, 'baseAsset'); const quoteId = this.safeString(market, 'quoteAsset'); const id = this.safeString(market, 'symbol'); const lowercaseId = this.safeStringLower(market, 'symbol'); const settleId = this.safeString(market, 'marginAsset'); const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); const settle = this.safeCurrencyCode(settleId); const symbol = base + '/' + quote; const filters = this.safeValue(market, 'filters', []); const filtersByType = this.indexBy(filters, 'filterType'); const status = this.safeString(market, 'spotTradingEnable'); let active = (status === '1'); const permissions = this.safeValue(market, 'permissions', []); for (let j = 0; j < permissions.length; j++) { if (permissions[j] === 'TRD_GRP_003') { active = false; break; } } const isMarginTradingAllowed = this.safeValue(market, 'isMarginTradingAllowed', false); const entry = { 'id': id, 'lowercaseId': lowercaseId, 'symbol': symbol, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'quoteId': quoteId, 'settleId': settleId, 'type': 'spot', 'spot': true, 'margin': isMarginTradingAllowed, 'swap': false, 'future': false, 'delivery': false, 'option': false, 'active': active, 'contract': false, 'linear': undefined, 'inverse': undefined, 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.safeInteger(market, 'quantityPrecision'), 'price': this.safeInteger(market, 'pricePrecision'), 'base': this.safeInteger(market, 'baseAssetPrecision'), 'quote': this.safeInteger(market, 'quotePrecision'), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': undefined, 'max': undefined, }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': undefined, 'max': undefined, }, }, 'info': market, }; if ('PRICE_FILTER' in filtersByType) { const filter = this.safeValue(filtersByType, 'PRICE_FILTER', {}); const tickSize = this.safeString(filter, 'tickSize'); entry['precision']['price'] = this.precisionFromString(tickSize); // PRICE_FILTER reports zero values for maxPrice // since they updated filter types in November 2018 // https://github.com/ccxt/ccxt/issues/4286 // therefore limits['price']['max'] doesn't have any meaningful value except undefined entry['limits']['price'] = { 'min': this.safeNumber(filter, 'minPrice'), 'max': this.safeNumber(filter, 'maxPrice'), }; entry['precision']['price'] = this.precisionFromString(filter['tickSize']); } if ('LOT_SIZE' in filtersByType) { const filter = this.safeValue(filtersByType, 'LOT_SIZE', {}); const stepSize = this.safeString(filter, 'stepSize'); entry['precision']['amount'] = this.precisionFromString(stepSize); entry['limits']['amount'] = { 'min': this.safeNumber(filter, 'minQty'), 'max': this.safeNumber(filter, 'maxQty'), }; } if ('MARKET_LOT_SIZE' in filtersByType) { const filter = this.safeValue(filtersByType, 'MARKET_LOT_SIZE', {}); entry['limits']['market'] = { 'min': this.safeNumber(filter, 'minQty'), 'max': this.safeNumber(filter, 'maxQty'), }; } if ('MIN_NOTIONAL' in filtersByType) { const filter = this.safeValue(filtersByType, 'MIN_NOTIONAL', {}); entry['limits']['cost']['min'] = this.safeNumber2(filter, 'minNotional', 'notional'); } result.push(entry); } return result; } async fetchOrderBook(symbol, limit = undefined, params = {}) { /** * @method * @name tokocrypto#fetchOrderBook * @see https://www.tokocrypto.com/apidocs/#order-book * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @param {string} symbol unified symbol of the market to fetch the order book for * @param {int|undefined} limit the maximum amount of order book entries to return * @param {object} params extra parameters specific to the tokocrypto api endpoint * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['baseId'] + market['quoteId'], }; if (limit !== undefined) { request['limit'] = limit; // default 100, max 5000, see https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#order-book } const response = await this.binanceGetDepth(this.extend(request, params)); // // future // // { // "lastUpdateId":333598053905, // "E":1618631511986, // "T":1618631511964, // "bids":[ // ["2493.56","20.189"], // ["2493.54","1.000"], // ["2493.51","0.005"] // ], // "asks":[ // ["2493.57","0.877"], // ["2493.62","0.063"], // ["2493.71","12.054"], // ] // } const timestamp = this.safeInteger(response, 'T'); const orderbook = this.parseOrderBook(response, symbol, timestamp); orderbook['nonce'] = this.safeInteger(response, 'lastUpdateId'); return orderbook; } parseTrade(trade, market = undefined) { // // aggregate trades // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#compressedaggregate-trades-list // // { // "a": 26129, // Aggregate tradeId // "p": "0.01633102", // Price // "q": "4.70443515", // Quantity // "f": 27781, // First tradeId // "l": 27781, // Last tradeId // "T": 1498793709153, // Timestamp // "m": true, // Was the buyer the maker? // "M": true // Was the trade the best price match? // } // // recent public trades and old public trades // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#recent-trades-list // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#old-trade-lookup-market_data // // { // "id": 28457, // "price": "4.00000100", // "qty": "12.00000000", // "time": 1499865549590, // "isBuyerMaker": true, // "isBestMatch": true // } // // private trades // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#account-trade-list-user_data // // { // "symbol": "BNBBTC", // "id": 28457, // "orderId": 100234, // "price": "4.00000100", // "qty": "12.00000000", // "commission": "10.10000000", // "commissionAsset": "BNB", // "time": 1499865549590, // "isBuyer": true, // "isMaker": false, // "isBestMatch": true // } // // futures trades // https://binance-docs.github.io/apidocs/futures/en/#account-trade-list-user_data // // { // "accountId": 20, // "buyer": False, // "commission": "-0.07819010", // "commissionAsset": "USDT", // "counterPartyId": 653, // "id": 698759, // "maker": False, // "orderId": 25851813, // "price": "7819.01", // "qty": "0.002", // "quoteQty": "0.01563", // "realizedPnl": "-0.91539999", // "side": "SELL", // "symbol": "BTCUSDT", // "time": 1569514978020 // } // { // "symbol": "BTCUSDT", // "id": 477128891, // "orderId": 13809777875, // "side": "SELL", // "price": "38479.55", // "qty": "0.001", // "realizedPnl": "-0.00009534", // "marginAsset": "USDT", // "quoteQty": "38.47955", // "commission": "-0.00076959", // "commissionAsset": "USDT", // "time": 1612733566708, // "positionSide": "BOTH", // "maker": true, // "buyer": false // } // // { respType: FULL } // // { // "price": "4000.00000000", // "qty": "1.00000000", // "commission": "4.00000000", // "commissionAsset": "USDT", // "tradeId": "1234", // } // const timestamp = this.safeInteger2(trade, 'T', 'time'); const price = this.safeString2(trade, 'p', 'price'); const amount = this.safeString2(trade, 'q', 'qty'); const cost = this.safeString2(trade, 'quoteQty', 'baseQty'); // inverse futures const marketId = this.safeString(trade, 'symbol'); const symbol = this.safeSymbol(marketId, market); let id = this.safeString2(trade, 't', 'a'); id = this.safeString2(trade, 'id', 'tradeId', id); let side = undefined; const orderId = this.safeString(trade, 'orderId'); const buyerMaker = this.safeValue2(trade, 'm', 'isBuyerMaker'); let takerOrMaker = undefined; if (buyerMaker !== undefined) { side = buyerMaker ? 'sell' : 'buy'; // this is reversed intentionally takerOrMaker = 'taker'; } else if ('side' in trade) { side = this.safeStringLower(trade, 'side'); } else { if ('isBuyer' in trade) { side = trade['isBuyer'] ? 'buy' : 'sell'; // this is a true side } } let fee = undefined; if ('commission' in trade) { fee = { 'cost': this.safeString(trade, 'commission'), 'currency': this.safeCurrencyCode(this.safeString(trade, 'commissionAsset')), }; } if ('isMaker' in trade) { takerOrMaker = trade['isMaker'] ? 'maker' : 'taker'; } if ('maker' in trade) { takerOrMaker = trade['maker'] ? 'maker' : 'taker'; } return this.safeTrade({ 'info': trade, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': symbol, 'id': id, 'order': orderId, 'type': undefined, 'side': side, 'takerOrMaker': takerOrMaker, 'price': price, 'amount': amount, 'cost': cost, 'fee': fee, }, market); } async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { /** * @method * @name tokocrypto#fetchTrades * @see https://www.tokocrypto.com/apidocs/#recent-trades-list * @see https://www.tokocrypto.com/apidocs/#compressedaggregate-trades-list * @description get the list of most recent trades for a particular symbol * @param {string} symbol unified symbol of the market to fetch trades for * @param {int|undefined} since timestamp in ms of the earliest trade to fetch * @param {int|undefined} limit the maximum amount of trades to fetch * @param {object} params extra parameters specific to the tokocrypto api endpoint * @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades} */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['baseId'] + market['quoteId'], // 'fromId': 123, // ID to get aggregate trades from INCLUSIVE. // 'startTime': 456, // Timestamp in ms to get aggregate trades from INCLUSIVE. // 'endTime': 789, // Timestamp in ms to get aggregate trades until INCLUSIVE. // 'limit': 500, // default = 500, maximum = 1000 }; const defaultMethod = 'binanceGetTrades'; const method = this.safeString(this.options, 'fetchTradesMethod', defaultMethod); if ((method === 'binanceGetAggTrades') && (since !== undefined)) { request['startTime'] = since; // https://github.com/ccxt/ccxt/issues/6400 // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#compressedaggregate-trades-list request['endTime'] = this.sum(since, 3600000); } if (limit !== undefined) { request['limit'] = limit; // default = 500, maximum = 1000 } // // Caveats: // - default limit (500) applies only if no other parameters set, trades up // to the maximum limit may be returned to satisfy other parameters // - if both limit and time window is set and time window contains more // trades than the limit then the last trades from the window are returned // - 'tradeId' accepted and returned by this method is "aggregate" trade id // which is different from actual trade id // - setting both fromId and time window results in error const response = await this[method](this.extend(request, params)); // // aggregate trades // // [ // { // "a": 26129, // Aggregate tradeId // "p": "0.01633102", // Price // "q": "4.70443515", // Quantity // "f": 27781, // First tradeId // "l": 27781, // Last tradeId // "T": 1498793709153, // Timestamp // "m": true, // Was the buyer the maker? // "M": true // Was the trade the best price match? // } // ] // // recent public trades and historical public trades // // [ // { // "id": 28457, // "price": "4.00000100", // "qty": "12.00000000", // "time": 1499865549590, // "isBuyerMaker": true, // "isBestMatch": true // } // ] // return this.parseTrades(response, market, since, limit); } parseTicker(ticker, market = undefined) { // // { // symbol: 'ETHBTC', // priceChange: '0.00068700', // priceChangePercent: '2.075', // weightedAvgPrice: '0.03342681', // prevClosePrice: '0.03310300', // lastPrice: '0.03378900', // lastQty: '0.07700000', // bidPrice: '0.03378900', // bidQty: '7.16800000', // askPrice: '0.03379000', // askQty: '24.00000000', // openPrice: '0.03310200', // highPrice: '0.03388900', // lowPrice: '0.03306900', // volume: '205478.41000000', // quoteVolume: '6868.48826294', // openTime: 1601469986932, // closeTime: 1601556386932, // firstId: 196098772, // lastId: 196186315, // count: 87544 // } // // coinm // { // baseVolume: '214549.95171161', // closeTime: '1621965286847', // count: '1283779', // firstId: '152560106', // highPrice: '39938.3', // lastId: '153843955', // lastPrice: '37993.4', // lastQty: '1', // lowPrice: '36457.2', // openPrice: '37783.4', // openTime: '1621878840000', // pair: 'BTCUSD', // priceChange: '210.0', // priceChangePercent: '0.556', // symbol: 'BTCUSD_PERP', // volume: '81990451', // weightedAvgPrice: '38215.08713747' // } // const timestamp = this.safeInteger(ticker, 'closeTime'); const marketId = this.safeString(ticker, 'symbol'); const symbol = this.safeSymbol(marketId, market); const last = this.safeString(ticker, 'lastPrice'); const isCoinm = ('baseVolume' in ticker); let baseVolume = undefined; let quoteVolume = undefined; if (isCoinm) { baseVolume = this.safeString(ticker, 'baseVolume'); quoteVolume = this.safeString(ticker, 'volume'); } else { baseVolume = this.safeString(ticker, 'volume'); quoteVolume = this.safeString(ticker, 'quoteVolume'); } return this.safeTicker({ 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'high': this.safeString(ticker, 'highPrice'), 'low': this.safeString(ticker, 'lowPrice'), 'bid': this.safeString(ticker, 'bidPrice'), 'bidVolume': this.safeString(ticker, 'bidQty'), 'ask': this.safeString(ticker, 'askPrice'), 'askVolume': this.safeString(ticker, 'askQty'), 'vwap': this.safeString(ticker, 'weightedAvgPrice'), 'open': this.safeString(ticker, 'openPrice'), 'close': last, 'last': last, 'previousClose': this.safeString(ticker, 'prevClosePrice'), 'change': this.safeString(ticker, 'priceCha