@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
JavaScript
// ----------------------------------------------------------------------------
// 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