UNPKG

ccxt

Version:

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

1,205 lines (1,203 loc) 60 kB
'use strict'; var yobit$1 = require('./abstract/yobit.js'); var errors = require('./base/errors.js'); var Precise = require('./base/Precise.js'); var number = require('./base/functions/number.js'); var sha512 = require('./static_dependencies/noble-hashes/sha512.js'); // ---------------------------------------------------------------------------- // --------------------------------------------------------------------------- /** * @class yobit * @augments Exchange */ class yobit extends yobit$1 { describe() { return this.deepExtend(super.describe(), { 'id': 'yobit', 'name': 'YoBit', 'countries': ['RU'], 'rateLimit': 2000, 'version': '3', 'pro': false, 'has': { 'CORS': undefined, 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'addMargin': false, 'cancelOrder': true, 'closeAllPositions': false, 'closePosition': false, 'createDepositAddress': true, 'createMarketOrder': false, 'createOrder': true, 'createReduceOnlyOrder': false, 'createStopLimitOrder': false, 'createStopMarketOrder': false, 'createStopOrder': false, 'fetchBalance': true, 'fetchBorrowInterest': false, 'fetchBorrowRate': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchBorrowRates': false, 'fetchBorrowRatesPerSymbol': false, 'fetchCrossBorrowRate': false, 'fetchCrossBorrowRates': false, 'fetchDepositAddress': true, 'fetchDepositAddresses': false, 'fetchDepositAddressesByNetwork': false, 'fetchDeposits': false, 'fetchFundingHistory': false, 'fetchFundingInterval': false, 'fetchFundingIntervals': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': false, 'fetchFundingRates': false, 'fetchGreeks': false, 'fetchIndexOHLCV': false, 'fetchIsolatedBorrowRate': false, 'fetchIsolatedBorrowRates': false, 'fetchIsolatedPositions': false, 'fetchLeverage': false, 'fetchLeverages': false, 'fetchLeverageTiers': false, 'fetchLiquidations': false, 'fetchMarginAdjustmentHistory': false, 'fetchMarginMode': false, 'fetchMarginModes': false, 'fetchMarketLeverageTiers': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMarkPrices': false, 'fetchMyLiquidations': false, 'fetchMySettlementHistory': false, 'fetchMyTrades': true, 'fetchOpenInterest': false, 'fetchOpenInterestHistory': false, 'fetchOpenOrders': true, 'fetchOption': false, 'fetchOptionChain': false, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrderBooks': true, 'fetchPosition': false, 'fetchPositionHistory': false, 'fetchPositionMode': false, 'fetchPositions': false, 'fetchPositionsForSymbol': false, 'fetchPositionsHistory': false, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchSettlementHistory': false, 'fetchTicker': true, 'fetchTickers': true, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': true, 'fetchTransactions': false, 'fetchTransfer': false, 'fetchTransfers': false, 'fetchUnderlyingAssets': false, 'fetchVolatilityHistory': false, 'fetchWithdrawals': false, 'reduceMargin': false, 'repayCrossMargin': false, 'repayIsolatedMargin': false, 'setLeverage': false, 'setMargin': false, 'setMarginMode': false, 'setPositionMode': false, 'transfer': false, 'withdraw': true, 'ws': false, }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/27766910-cdcbfdae-5eea-11e7-9859-03fea873272d.jpg', 'api': { 'public': 'https://yobit.net/api', 'private': 'https://yobit.net/tapi', }, 'www': 'https://www.yobit.net', 'doc': 'https://www.yobit.net/en/api/', 'fees': 'https://www.yobit.net/en/fees/', }, 'api': { 'public': { 'get': { 'depth/{pair}': 1, 'info': 1, 'ticker/{pair}': 1, 'trades/{pair}': 1, }, }, 'private': { 'post': { 'ActiveOrders': 1, 'CancelOrder': 1, 'GetDepositAddress': 1, 'getInfo': 1, 'OrderInfo': 1, 'Trade': 1, 'TradeHistory': 1, 'WithdrawCoinsToAddress': 1, }, }, }, 'fees': { 'trading': { 'maker': 0.002, 'taker': 0.002, }, 'funding': { 'withdraw': {}, }, }, 'commonCurrencies': { 'AIR': 'AirCoin', 'ANI': 'ANICoin', 'ANT': 'AntsCoin', 'ATMCHA': 'ATM', 'ASN': 'Ascension', 'AST': 'Astral', 'ATM': 'Autumncoin', 'AUR': 'AuroraCoin', 'BAB': 'Babel', 'BAN': 'BANcoin', 'BCC': 'BCH', 'BCS': 'BitcoinStake', 'BITS': 'Bitstar', 'BLN': 'Bulleon', 'BNS': 'Benefit Bonus Coin', 'BOT': 'BOTcoin', 'BON': 'BONES', 'BPC': 'BitcoinPremium', 'BST': 'BitStone', 'BTS': 'Bitshares2', 'CAT': 'BitClave', 'CBC': 'CryptoBossCoin', 'CMT': 'CometCoin', 'COIN': 'Coin.com', 'COV': 'Coven Coin', 'COVX': 'COV', 'CPC': 'Capricoin', 'CREDIT': 'Creditbit', 'CS': 'CryptoSpots', 'DCT': 'Discount', 'DFT': 'DraftCoin', 'DGD': 'DarkGoldCoin', 'DIRT': 'DIRTY', 'DROP': 'FaucetCoin', 'DSH': 'DASH', 'EGC': 'EverGreenCoin', 'EGG': 'EggCoin', 'EKO': 'EkoCoin', 'ENTER': 'ENTRC', 'EPC': 'ExperienceCoin', 'ESC': 'EdwardSnowden', 'EUROPE': 'EUROP', 'EXT': 'LifeExtension', 'FUND': 'FUNDChains', 'FUNK': 'FUNKCoin', 'FX': 'FCoin', 'GCC': 'GlobalCryptocurrency', 'GEN': 'Genstake', 'GENE': 'Genesiscoin', 'GMR': 'Gimmer', 'GOLD': 'GoldMint', 'GOT': 'Giotto Coin', 'GSX': 'GlowShares', 'GT': 'GTcoin', 'HTML5': 'HTML', 'HYPERX': 'HYPER', 'ICN': 'iCoin', 'INSANE': 'INSN', 'JNT': 'JointCoin', 'JPC': 'JupiterCoin', 'JWL': 'Jewels', 'KNC': 'KingN Coin', 'LBTCX': 'LiteBitcoin', 'LIZI': 'LiZi', 'LOC': 'LocoCoin', 'LOCX': 'LOC', 'LUNYR': 'LUN', 'LUN': 'LunarCoin', 'LUNA': 'Luna Coin', 'MASK': 'Yobit MASK', 'MDT': 'Midnight', 'MEME': 'Memez Token', 'MIS': 'MIScoin', 'MM': 'MasterMint', 'NAV': 'NavajoCoin', 'NBT': 'NiceBytes', 'OMG': 'OMGame', 'ONX': 'Onix', 'PAC': '$PAC', 'PLAY': 'PlayCoin', 'PIVX': 'Darknet', 'PURE': 'PurePOS', 'PUTIN': 'PutinCoin', 'SPACE': 'Spacecoin', 'STK': 'StakeCoin', 'SUB': 'Subscriptio', 'PAY': 'EPAY', 'PLC': 'Platin Coin', 'RAI': 'RaiderCoin', 'RCN': 'RCoin', 'REP': 'Republicoin', 'RUR': 'RUB', 'SBTC': 'Super Bitcoin', 'SMC': 'SmartCoin', 'SOLO': 'SoloCoin', 'SOUL': 'SoulCoin', 'STAR': 'StarCoin', 'SUPER': 'SuperCoin', 'TNS': 'Transcodium', 'TTC': 'TittieCoin', 'UNI': 'Universe', 'UST': 'Uservice', 'VOL': 'VolumeCoin', 'XIN': 'XINCoin', 'XMT': 'SummitCoin', 'XRA': 'Ratecoin', 'BCHN': 'BSV', }, 'options': { 'maxUrlLength': 2048, 'fetchOrdersRequiresSymbol': true, 'networks': { 'ETH': 'ERC20', 'TRX': 'TRC20', 'BSC': 'BEP20', }, }, 'precisionMode': number.TICK_SIZE, 'exceptions': { 'exact': { '803': errors.InvalidOrder, '804': errors.InvalidOrder, '805': errors.InvalidOrder, '806': errors.InvalidOrder, '807': errors.InvalidOrder, '831': errors.InsufficientFunds, '832': errors.InsufficientFunds, '833': errors.OrderNotFound, // "Order with id X was not found." (cancelling non-existent, closed and cancelled order) }, 'broad': { 'Invalid pair name': errors.ExchangeError, 'invalid api key': errors.AuthenticationError, 'invalid sign': errors.AuthenticationError, 'api key dont have trade permission': errors.AuthenticationError, 'invalid parameter': errors.InvalidOrder, 'invalid order': errors.InvalidOrder, 'The given order has already been cancelled': errors.InvalidOrder, 'Requests too often': errors.DDoSProtection, 'not available': errors.ExchangeNotAvailable, 'data unavailable': errors.ExchangeNotAvailable, 'external service unavailable': errors.ExchangeNotAvailable, 'Total transaction amount': errors.InvalidOrder, 'The given order has already been closed and cannot be cancelled': errors.InvalidOrder, 'Insufficient funds': errors.InsufficientFunds, 'invalid key': errors.AuthenticationError, 'invalid nonce': errors.InvalidNonce, 'Total order amount is less than minimal amount': errors.InvalidOrder, 'Rate Limited': errors.RateLimitExceeded, }, }, 'features': { 'spot': { 'sandbox': false, 'createOrder': { 'marginMode': false, 'triggerPrice': false, 'triggerDirection': false, 'triggerPriceType': undefined, 'stopLossPrice': false, 'takeProfitPrice': false, 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': false, 'FOK': false, 'PO': false, 'GTD': false, }, 'hedged': false, 'trailing': false, 'leverage': false, 'marketBuyByCost': false, 'marketBuyRequiresPrice': false, 'selfTradePrevention': false, 'iceberg': false, }, 'createOrders': undefined, 'fetchMyTrades': { 'marginMode': false, 'limit': 1000, 'daysBack': 100000, 'untilDays': 100000, 'symbolRequired': true, }, 'fetchOrder': { 'marginMode': false, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOpenOrders': { 'marginMode': false, 'limit': undefined, 'trigger': false, 'trailing': false, 'symbolRequired': true, }, 'fetchOrders': undefined, 'fetchClosedOrders': undefined, 'fetchOHLCV': undefined, }, 'swap': { 'linear': undefined, 'inverse': undefined, }, 'future': { 'linear': undefined, 'inverse': undefined, }, }, 'orders': {}, // orders cache / emulation }); } parseBalance(response) { const balances = this.safeDict(response, 'return', {}); const timestamp = this.safeInteger(balances, 'server_time'); const result = { 'info': response, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), }; const free = this.safeDict(balances, 'funds', {}); const total = this.safeDict(balances, 'funds_incl_orders', {}); const currencyIds = Object.keys(this.extend(free, total)); for (let i = 0; i < currencyIds.length; i++) { const currencyId = currencyIds[i]; const code = this.safeCurrencyCode(currencyId); const account = this.account(); account['free'] = this.safeString(free, currencyId); account['total'] = this.safeString(total, currencyId); result[code] = account; } return this.safeBalance(result); } /** * @method * @name yobit#fetchBalance * @see https://yobit.net/en/api * @description query for balance and get the amount of funds available for trading or funds locked in orders * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure} */ async fetchBalance(params = {}) { await this.loadMarkets(); const response = await this.privatePostGetInfo(params); // // { // "success":1, // "return":{ // "funds":{ // "ltc":22, // "nvc":423.998, // "ppc":10, // }, // "funds_incl_orders":{ // "ltc":32, // "nvc":523.998, // "ppc":20, // }, // "rights":{ // "info":1, // "trade":0, // "withdraw":0 // }, // "transaction_count":0, // "open_orders":1, // "server_time":1418654530 // } // } // return this.parseBalance(response); } /** * @method * @name yobit#fetchMarkets * @see https://yobit.net/en/api * @description retrieves data on all markets for yobit * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} an array of objects representing market data */ async fetchMarkets(params = {}) { const response = await this.publicGetInfo(params); // // { // "server_time":1615856752, // "pairs":{ // "ltc_btc":{ // "decimal_places":8, // "min_price":0.00000001, // "max_price":10000, // "min_amount":0.0001, // "min_total":0.0001, // "hidden":0, // "fee":0.2, // "fee_buyer":0.2, // "fee_seller":0.2 // }, // }, // } // const markets = this.safeDict(response, 'pairs', {}); const keys = Object.keys(markets); const result = []; for (let i = 0; i < keys.length; i++) { const id = keys[i]; const market = markets[id]; const [baseId, quoteId] = id.split('_'); let base = baseId.toUpperCase(); let quote = quoteId.toUpperCase(); base = this.safeCurrencyCode(base); quote = this.safeCurrencyCode(quote); const hidden = this.safeInteger(market, 'hidden'); let feeString = this.safeString(market, 'fee'); feeString = Precise["default"].stringDiv(feeString, '100'); // yobit maker = taker result.push({ 'id': id, 'symbol': base + '/' + quote, 'base': base, 'quote': quote, 'settle': undefined, 'baseId': baseId, 'quoteId': quoteId, 'settleId': undefined, 'type': 'spot', 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'active': (hidden === 0), 'contract': false, 'linear': undefined, 'inverse': undefined, 'taker': this.parseNumber(feeString), 'maker': this.parseNumber(feeString), 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.parseNumber(this.parsePrecision(this.safeString(market, 'decimal_places'))), 'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'decimal_places'))), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber(market, 'min_amount'), 'max': this.safeNumber(market, 'max_amount'), }, 'price': { 'min': this.safeNumber(market, 'min_price'), 'max': this.safeNumber(market, 'max_price'), }, 'cost': { 'min': this.safeNumber(market, 'min_total'), 'max': undefined, }, }, 'created': undefined, 'info': market, }); } return result; } /** * @method * @name yobit#fetchOrderBook * @see https://yobit.net/en/api * @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} [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 = { 'pair': market['id'], }; if (limit !== undefined) { request['limit'] = limit; // default = 150, max = 2000 } const response = await this.publicGetDepthPair(this.extend(request, params)); const market_id_in_reponse = (market['id'] in response); if (!market_id_in_reponse) { throw new errors.ExchangeError(this.id + ' ' + market['symbol'] + ' order book is empty or not available'); } const orderbook = response[market['id']]; return this.parseOrderBook(orderbook, symbol); } /** * @method * @name yobit#fetchOrderBooks * @see https://yobit.net/en/api * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data for multiple markets * @param {string[]|undefined} symbols list of unified market symbols, all symbols fetched if undefined, default is undefined * @param {int} [limit] max number of entries per orderbook to return, default is undefined * @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 symbol */ async fetchOrderBooks(symbols = undefined, limit = undefined, params = {}) { await this.loadMarkets(); let ids = undefined; if (symbols === undefined) { ids = this.ids.join('-'); // max URL length is 2083 symbols, including http schema, hostname, tld, etc... if (ids.length > 2048) { const numIds = this.ids.length; throw new errors.ExchangeError(this.id + ' fetchOrderBooks() has ' + numIds.toString() + ' symbols exceeding max URL length, you are required to specify a list of symbols in the first argument to fetchOrderBooks'); } } else { ids = this.marketIds(symbols); ids = ids.join('-'); } const request = { 'pair': ids, // 'ignore_invalid': true, }; if (limit !== undefined) { request['limit'] = limit; } const response = await this.publicGetDepthPair(this.extend(request, params)); const result = {}; ids = Object.keys(response); for (let i = 0; i < ids.length; i++) { const id = ids[i]; const symbol = this.safeSymbol(id); result[symbol] = this.parseOrderBook(response[id], symbol); } return result; } parseTicker(ticker, market = undefined) { // // { // "high": 0.03497582, // "low": 0.03248474, // "avg": 0.03373028, // "vol": 120.11485715062999, // "vol_cur": 3572.24914074, // "last": 0.0337611, // "buy": 0.0337442, // "sell": 0.03377798, // "updated": 1537522009 // } // const timestamp = this.safeTimestamp(ticker, 'updated'); const last = this.safeString(ticker, 'last'); return this.safeTicker({ 'symbol': this.safeSymbol(undefined, market), 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'high': this.safeString(ticker, 'high'), 'low': this.safeString(ticker, 'low'), 'bid': this.safeString(ticker, 'buy'), 'bidVolume': undefined, 'ask': this.safeString(ticker, 'sell'), 'askVolume': undefined, 'vwap': undefined, 'open': undefined, 'close': last, 'last': last, 'previousClose': undefined, 'change': undefined, 'percentage': undefined, 'average': this.safeString(ticker, 'avg'), 'baseVolume': this.safeString(ticker, 'vol_cur'), 'quoteVolume': this.safeString(ticker, 'vol'), 'info': ticker, }, market); } async fetchTickersHelper(idsString, params = {}) { const request = { 'pair': idsString, }; const tickers = await this.publicGetTickerPair(this.extend(request, params)); const result = {}; const keys = Object.keys(tickers); for (let k = 0; k < keys.length; k++) { const id = keys[k]; const ticker = tickers[id]; const market = this.safeMarket(id); const symbol = market['symbol']; result[symbol] = this.parseTicker(ticker, market); } return result; } /** * @method * @name yobit#fetchTickers * @see https://yobit.net/en/api * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market * @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {object} [params.all] you can set to `true` for convenience to fetch all tickers from this exchange by sending multiple requests * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ async fetchTickers(symbols = undefined, params = {}) { let allSymbols = undefined; [allSymbols, params] = this.handleParamBool(params, 'all', false); if (symbols === undefined && !allSymbols) { throw new errors.ArgumentsRequired(this.id + ' fetchTickers() requires "symbols" argument or use `params["all"] = true` to send multiple requests for all markets'); } await this.loadMarkets(); const promises = []; const maxLength = this.safeInteger(this.options, 'maxUrlLength', 2048); // max URL length is 2048 symbols, including http schema, hostname, tld, etc... const lenghtOfBaseUrl = 40; // safe space for the url including api-base and endpoint dir is 30 chars if (allSymbols) { symbols = this.symbols; let ids = ''; for (let i = 0; i < this.ids.length; i++) { const id = this.ids[i]; const prefix = (ids === '') ? '' : '-'; ids += prefix + id; if (ids.length > maxLength) { promises.push(this.fetchTickersHelper(ids, params)); ids = ''; } } if (ids !== '') { promises.push(this.fetchTickersHelper(ids, params)); } } else { symbols = this.marketSymbols(symbols); const ids = this.marketIds(symbols); const idsLength = ids.length; const idsString = ids.join('-'); const actualLength = idsString.length + lenghtOfBaseUrl; if (actualLength > maxLength) { throw new errors.ArgumentsRequired(this.id + ' fetchTickers() is being requested for ' + idsLength.toString() + ' markets (which has an URL length of ' + actualLength.toString() + ' characters), but it exceedes max URL length (' + maxLength.toString() + '), please pass limisted symbols array to fetchTickers to fit in one request'); } promises.push(this.fetchTickersHelper(idsString, params)); } const resultAll = await Promise.all(promises); let finalResult = {}; for (let i = 0; i < resultAll.length; i++) { const result = this.filterByArrayTickers(resultAll[i], 'symbol', symbols); finalResult = this.extend(finalResult, result); } return finalResult; } /** * @method * @name yobit#fetchTicker * @see https://yobit.net/en/api * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market * @param {string} symbol unified symbol of the market to fetch the ticker for * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ async fetchTicker(symbol, params = {}) { const tickers = await this.fetchTickers([symbol], params); return tickers[symbol]; } parseTrade(trade, market = undefined) { // // fetchTrades (public) // // { // "type":"bid", // "price":0.14046179, // "amount":0.001, // "tid":200256901, // "timestamp":1649861004 // } // // fetchMyTrades (private) // // { // "pair":"doge_usdt", // "type":"sell", // "amount":139, // "rate":0.139, // "order_id":"2101103631773172", // "is_your_order":1, // "timestamp":"1649861561" // } // const timestamp = this.safeTimestamp(trade, 'timestamp'); let side = this.safeString(trade, 'type'); if (side === 'ask') { side = 'sell'; } else if (side === 'bid') { side = 'buy'; } const priceString = this.safeString2(trade, 'rate', 'price'); const id = this.safeString2(trade, 'trade_id', 'tid'); const order = this.safeString(trade, 'order_id'); const marketId = this.safeString(trade, 'pair'); const symbol = this.safeSymbol(marketId, market); const amountString = this.safeString(trade, 'amount'); // arguments for calculateFee (need to be numbers) const price = this.parseNumber(priceString); const amount = this.parseNumber(amountString); const type = 'limit'; // all trades are still limit trades let fee = undefined; const feeCostString = this.safeNumber(trade, 'commission'); if (feeCostString !== undefined) { const feeCurrencyId = this.safeString(trade, 'commissionCurrency'); const feeCurrencyCode = this.safeCurrencyCode(feeCurrencyId); fee = { 'cost': feeCostString, 'currency': feeCurrencyCode, }; } const isYourOrder = this.safeString(trade, 'is_your_order'); if (isYourOrder !== undefined) { if (fee === undefined) { const feeInNumbers = this.calculateFee(symbol, type, side, amount, price, 'taker'); fee = { 'currency': this.safeString(feeInNumbers, 'currency'), 'cost': this.safeString(feeInNumbers, 'cost'), 'rate': this.safeString(feeInNumbers, 'rate'), }; } } return this.safeTrade({ 'id': id, 'order': order, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': symbol, 'type': type, 'side': side, 'takerOrMaker': undefined, 'price': priceString, 'amount': amountString, 'cost': undefined, 'fee': fee, 'info': trade, }, market); } /** * @method * @name yobit#fetchTrades * @see https://yobit.net/en/api * @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} [since] timestamp in ms of the earliest trade to fetch * @param {int} [limit] the maximum amount 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 = { 'pair': market['id'], }; if (limit !== undefined) { request['limit'] = limit; } const response = await this.publicGetTradesPair(this.extend(request, params)); // // { // "doge_usdt": [ // { // "type":"ask", // "price":0.13956743, // "amount":0.0008, // "tid":200256900, // "timestamp":1649860521 // }, // ] // } // if (Array.isArray(response)) { const numElements = response.length; if (numElements === 0) { return []; } } const result = this.safeList(response, market['id'], []); return this.parseTrades(result, market, since, limit); } /** * @method * @name yobit#fetchTradingFees * @see https://yobit.net/en/api * @description fetch the trading fees for multiple markets * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols */ async fetchTradingFees(params = {}) { await this.loadMarkets(); const response = await this.publicGetInfo(params); // // { // "server_time":1615856752, // "pairs":{ // "ltc_btc":{ // "decimal_places":8, // "min_price":0.00000001, // "max_price":10000, // "min_amount":0.0001, // "min_total":0.0001, // "hidden":0, // "fee":0.2, // "fee_buyer":0.2, // "fee_seller":0.2 // }, // ... // }, // } // const pairs = this.safeDict(response, 'pairs', {}); const marketIds = Object.keys(pairs); const result = {}; for (let i = 0; i < marketIds.length; i++) { const marketId = marketIds[i]; const pair = this.safeDict(pairs, marketId, {}); const symbol = this.safeSymbol(marketId, undefined, '_'); const takerString = this.safeString(pair, 'fee_buyer'); const makerString = this.safeString(pair, 'fee_seller'); const taker = this.parseNumber(Precise["default"].stringDiv(takerString, '100')); const maker = this.parseNumber(Precise["default"].stringDiv(makerString, '100')); result[symbol] = { 'info': pair, 'symbol': symbol, 'taker': taker, 'maker': maker, 'percentage': true, 'tierBased': false, }; } return result; } /** * @method * @name yobit#createOrder * @see https://yobit.net/en/api * @description create a trade order * @param {string} symbol unified symbol of the market to create an order in * @param {string} type must be 'limit' * @param {string} side 'buy' or 'sell' * @param {float} amount how much of currency you want to trade in units of base currency * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ async createOrder(symbol, type, side, amount, price = undefined, params = {}) { if (type === 'market') { throw new errors.ExchangeError(this.id + ' createOrder() allows limit orders only'); } await this.loadMarkets(); const market = this.market(symbol); const request = { 'pair': market['id'], 'type': side, 'amount': this.amountToPrecision(symbol, amount), 'rate': this.priceToPrecision(symbol, price), }; const response = await this.privatePostTrade(this.extend(request, params)); // // { // "success":1, // "return": { // "received":0, // "remains":10, // "order_id":1101103635125179, // "funds": { // "usdt":27.84756553, // "usdttrc20":0, // "doge":19.98327206 // }, // "funds_incl_orders": { // "usdt":30.35256553, // "usdttrc20":0, // "doge":19.98327206 // }, // "server_time":1650114256 // } // } // const result = this.safeDict(response, 'return'); return this.parseOrder(result, market); } /** * @method * @name yobit#cancelOrder * @see https://yobit.net/en/api * @description cancels an open order * @param {string} id order id * @param {string} symbol not used by yobit cancelOrder () * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ async cancelOrder(id, symbol = undefined, params = {}) { await this.loadMarkets(); const request = { 'order_id': parseInt(id), }; const response = await this.privatePostCancelOrder(this.extend(request, params)); // // { // "success":1, // "return": { // "order_id":1101103632552304, // "funds": { // "usdt":30.71055443, // "usdttrc20":0, // "doge":9.98327206 // }, // "funds_incl_orders": { // "usdt":31.81275443, // "usdttrc20":0, // "doge":9.98327206 // }, // "server_time":1649918298 // } // } // const result = this.safeDict(response, 'return', {}); return this.parseOrder(result); } parseOrderStatus(status) { const statuses = { '0': 'open', '1': 'closed', '2': 'canceled', '3': 'open', // or partially-filled and canceled? https://github.com/ccxt/ccxt/issues/1594 }; return this.safeString(statuses, status, status); } parseOrder(order, market = undefined) { // // createOrder (private) // // { // "received":0, // "remains":10, // "order_id":1101103635125179, // "funds": { // "usdt":27.84756553, // "usdttrc20":0, // "doge":19.98327206 // }, // "funds_incl_orders": { // "usdt":30.35256553, // "usdttrc20":0, // "doge":19.98327206 // }, // "server_time":1650114256 // } // // fetchOrder (private) // // { // "id: "1101103635103335", // id-field is manually added in fetchOrder () from exchange response id-order dictionary structure // "pair":"doge_usdt", // "type":"buy", // "start_amount":10, // "amount":10, // "rate":0.05, // "timestamp_created":"1650112553", // "status":0 // } // // fetchOpenOrders (private) // // { // "id":"1101103635103335", // id-field is manually added in fetchOpenOrders () from exchange response id-order dictionary structure // "pair":"doge_usdt", // "type":"buy", // "amount":10, // "rate":0.05, // "timestamp_created":"1650112553", // "status":0 // } // // cancelOrder (private) // // { // "order_id":1101103634000197, // "funds": { // "usdt":31.81275443, // "usdttrc20":0, // "doge":9.98327206 // }, // "funds_incl_orders": { // "usdt":31.81275443, // "usdttrc20":0, // "doge":9.98327206 // } // } // let id = this.safeString2(order, 'id', 'order_id'); let status = this.parseOrderStatus(this.safeString(order, 'status', 'open')); if (id === '0') { id = this.safeString(order, 'init_order_id'); status = 'closed'; } const timestamp = this.safeTimestamp2(order, 'timestamp_created', 'server_time'); const marketId = this.safeString(order, 'pair'); const symbol = this.safeSymbol(marketId, market); const amount = this.safeString(order, 'start_amount'); const remaining = this.safeString2(order, 'amount', 'remains'); const filled = this.safeString(order, 'received', '0.0'); const price = this.safeString(order, 'rate'); const fee = undefined; const type = 'limit'; const side = this.safeString(order, 'type'); return this.safeOrder({ 'info': order, 'id': id, 'clientOrderId': undefined, 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'lastTradeTimestamp': undefined, 'type': type, 'timeInForce': undefined, 'postOnly': undefined, 'side': side, 'price': price, 'triggerPrice': undefined, 'cost': undefined, 'amount': amount, 'remaining': remaining, 'filled': filled, 'status': status, 'fee': fee, 'average': undefined, 'trades': undefined, }, market); } /** * @method * @name yobit#fetchOrder * @see https://yobit.net/en/api * @description fetches information on an order made by the user * @param {string} id order id * @param {string} symbol not used by yobit fetchOrder * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchOrder(id, symbol = undefined, params = {}) { await this.loadMarkets(); const request = { 'order_id': parseInt(id), }; const response = await this.privatePostOrderInfo(this.extend(request, params)); id = id.toString(); const orders = this.safeDict(response, 'return', {}); // // { // "success":1, // "return": { // "1101103635103335": { // "pair":"doge_usdt", // "type":"buy", // "start_amount":10, // "amount":10, // "rate":0.05, // "timestamp_created":"1650112553", // "status":0 // } // } // } // return this.parseOrder(this.extend({ 'id': id }, orders[id])); } /** * @method * @name yobit#fetchOpenOrders * @see https://yobit.net/en/api * @description fetch all unfilled currently open orders * @param {string} symbol unified market symbol * @param {int} [since] the earliest time in ms to fetch open orders for * @param {int} [limit] the maximum number of open order structures to retrieve * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { if (symbol === undefined) { throw new errors.ArgumentsRequired(this.id + ' fetchOpenOrders() requires a symbol argument'); } await this.loadMarkets(); const request = {}; const market = undefined; if (symbol !== undefined) { const marketInner = this.market(symbol); request['pair'] = marketInner['id']; } const response = await this.privatePostActiveOrders(this.extend(request, params)); // // { // "success":1, // "return": { // "1101103634006799": { // "pair":"doge_usdt", // "type":"buy", // "amount":10, // "rate":0.1, // "timestamp_created":"1650034937", // "status":0 // }, // "1101103634006738": { // "pair":"doge_usdt", // "type":"buy", // "amount":10, // "rate":0.1, // "timestamp_created":"1650034932", // "status":0 // } // } // } // const result = this.safeDict(response, 'return', {}); return this.parseOrders(result, market, since, limit); } /** * @method * @name yobit#fetchMyTrades * @see https://yobit.net/en/api * @description fetch all trades made by the user * @param {string} symbol unified market symbol * @param {int} [since] the earliest time in ms to fetch trades for * @param {int} [limit] the maximum number of trades structures to retrieve * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} */ async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) { if (symbol === undefined) { throw new errors.ArgumentsRequired(this.id + ' fetchMyTrades() requires a symbol argument'); } await this.loadMarkets(); const market = this.market(symbol); // some derived classes use camelcase notation for request fields const request = { // 'from': 123456789, // trade ID, from which the display starts numerical 0 (test result: liqui ignores this field) // 'count': 1000, // the number of trades for display numerical, default = 1000 // 'from_id': trade ID, from which the display starts numerical 0 // 'end_id': trade ID on which the display ends numerical ∞ // 'order': 'ASC', // sorting, default = DESC (test result: liqui ignores this field, most recent trade always goes last) // 'since': 1234567890, // UTC start time, default = 0 (test result: liqui ignores this field) // 'end': 1234567890, // UTC end time, default = ∞ (test result: liqui ignores this field