UNPKG

ccxt

Version:

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

1,130 lines (1,127 loc) • 48.9 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/cryptomus.js'; import { ArgumentsRequired, ExchangeError, InsufficientFunds, InvalidOrder } from './base/errors.js'; import { Precise } from './base/Precise.js'; import { TICK_SIZE } from './base/functions/number.js'; import { md5 } from './static_dependencies/noble-hashes/md5.js'; // --------------------------------------------------------------------------- /** * @class cryptomus * @augments Exchange */ export default class cryptomus extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'cryptomus', 'name': 'Cryptomus', 'countries': ['CA'], 'rateLimit': 100, 'version': 'v2', 'certified': false, 'pro': false, 'has': { 'CORS': undefined, 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'addMargin': false, 'cancelAllOrders': false, 'cancelAllOrdersAfter': false, 'cancelOrder': true, 'cancelOrders': false, 'cancelWithdraw': false, 'closePosition': false, 'createConvertTrade': false, 'createDepositAddress': false, 'createMarketBuyOrderWithCost': false, 'createMarketOrder': false, 'createMarketOrderWithCost': false, 'createMarketSellOrderWithCost': false, 'createOrder': true, 'createOrderWithTakeProfitAndStopLoss': false, 'createReduceOnlyOrder': false, 'createStopLimitOrder': false, 'createStopLossOrder': false, 'createStopMarketOrder': false, 'createStopOrder': false, 'createTakeProfitOrder': false, 'createTrailingAmountOrder': false, 'createTrailingPercentOrder': false, 'createTriggerOrder': false, 'fetchAccounts': false, 'fetchBalance': true, 'fetchCanceledAndClosedOrders': true, 'fetchCanceledOrders': false, 'fetchClosedOrder': false, 'fetchClosedOrders': false, 'fetchConvertCurrencies': false, 'fetchConvertQuote': false, 'fetchConvertTrade': false, 'fetchConvertTradeHistory': false, 'fetchCurrencies': true, 'fetchDepositAddress': false, 'fetchDeposits': false, 'fetchDepositsWithdrawals': false, 'fetchFundingHistory': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': false, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchLedger': false, 'fetchLeverage': false, 'fetchLeverageTiers': false, 'fetchMarginAdjustmentHistory': false, 'fetchMarginMode': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': false, 'fetchOHLCV': false, 'fetchOpenInterestHistory': false, 'fetchOpenOrder': false, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': false, 'fetchOrderTrades': false, 'fetchPosition': false, 'fetchPositionHistory': false, 'fetchPositionMode': false, 'fetchPositions': false, 'fetchPositionsForSymbol': false, 'fetchPositionsHistory': false, 'fetchPremiumIndexOHLCV': false, 'fetchStatus': false, 'fetchTicker': false, 'fetchTickers': true, 'fetchTime': false, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': true, 'fetchTransactions': false, 'fetchTransfers': false, 'fetchWithdrawals': false, 'reduceMargin': false, 'sandbox': false, 'setLeverage': false, 'setMargin': false, 'setPositionMode': false, 'transfer': false, 'withdraw': false, }, 'timeframes': {}, 'urls': { 'logo': 'https://github.com/user-attachments/assets/8e0b1c48-7c01-4177-9224-f1b01d89d7e7', 'api': { 'public': 'https://api.cryptomus.com', 'private': 'https://api.cryptomus.com', }, 'www': 'https://cryptomus.com', 'doc': 'https://doc.cryptomus.com/personal', 'fees': 'https://cryptomus.com/tariffs', 'referral': 'https://app.cryptomus.com/signup/?ref=JRP4yj', // todo }, 'api': { 'public': { 'get': { 'v2/user-api/exchange/markets': 1, 'v2/user-api/exchange/market/price': 1, 'v1/exchange/market/assets': 1, 'v1/exchange/market/order-book/{currencyPair}': 1, 'v1/exchange/market/tickers': 1, 'v1/exchange/market/trades/{currencyPair}': 1, // done }, }, 'private': { 'get': { 'v2/user-api/exchange/orders': 1, 'v2/user-api/exchange/orders/history': 1, 'v2/user-api/exchange/account/balance': 1, 'v2/user-api/exchange/account/tariffs': 1, 'v2/user-api/payment/services': 1, 'v2/user-api/payout/services': 1, 'v2/user-api/transaction/list': 1, }, 'post': { 'v2/user-api/exchange/orders': 1, 'v2/user-api/exchange/orders/market': 1, // done }, 'delete': { 'v2/user-api/exchange/orders/{orderId}': 1, // done }, }, }, 'fees': { 'trading': { 'percentage': true, 'feeSide': 'get', 'maker': this.parseNumber('0.02'), 'taker': this.parseNumber('0.02'), }, }, 'options': { 'createMarketBuyOrderRequiresPrice': true, 'networks': { 'BEP20': 'bsc', 'DASH': 'dash', 'POLYGON': 'polygon', 'ARB': 'arbitrum', 'SOL': 'sol', 'TON': 'ton', 'ERC20': 'eth', 'TRC20': 'tron', 'LTC': 'ltc', 'XMR': 'xmr', 'BCH': 'bch', 'DOGE': 'doge', 'AVAX': 'avalanche', 'BTC': 'btc', 'RUB': 'rub', }, 'networksById': { 'bsc': 'BEP20', 'dash': 'DASH', 'polygon': 'POLYGON', 'arbitrum': 'ARB', 'sol': 'SOL', 'ton': 'TON', 'eth': 'ERC20', 'tron': 'TRC20', 'ltc': 'LTC', 'xmr': 'XMR', 'bch': 'BCH', 'doge': 'DOGE', 'avalanche': 'AVAX', 'btc': 'BTC', 'rub': 'RUB', }, 'fetchOrderBook': { 'level': 0, // 0, 1, 2, 4 or 5 }, }, 'commonCurrencies': {}, 'exceptions': { 'exact': { '500': ExchangeError, '6': InsufficientFunds, 'Insufficient funds.': InsufficientFunds, 'Minimum amount 15 USDT': InvalidOrder, // {"code":500,"message":"Server error."} // {"message":"Minimum amount 15 USDT","state":1} // {"message":"Insufficient funds. USDT wallet balance is 35.21617400.","state":1} }, 'broad': {}, }, 'precisionMode': TICK_SIZE, 'requiredCredentials': { 'apiKey': false, 'uid': true, }, 'features': {}, }); } /** * @method * @name cryptomus#fetchMarkets * @description retrieves data on all markets for the exchange * @see https://doc.cryptomus.com/personal/market-cap/tickers * @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.publicGetV2UserApiExchangeMarkets(params); // // { // "result": [ // { // "id": "01JHN5EFT64YC4HR9KCGM5M65D", // "symbol": "POL_USDT", // "baseCurrency": "POL", // "quoteCurrency": "USDT", // "baseMinSize": "1.00000000", // "quoteMinSize": "5.00000000", // "baseMaxSize": "50000.00000000", // "quoteMaxSize": "10000000000.00000000", // "basePrec": "1", // "quotePrec": "4" // }, // ... // ] // } // const result = this.safeList(response, 'result', []); return this.parseMarkets(result); } parseMarket(market) { // // { // "id": "01JHN5EFT64YC4HR9KCGM5M65D", // "symbol": "POL_USDT", // "baseCurrency": "POL", // "quoteCurrency": "USDT", // "baseMinSize": "1.00000000", // "quoteMinSize": "5.00000000", // "baseMaxSize": "50000.00000000", // "quoteMaxSize": "10000000000.00000000", // "basePrec": "1", // "quotePrec": "4" // } // const marketId = this.safeString(market, 'symbol'); const parts = marketId.split('_'); const baseId = parts[0]; const quoteId = parts[1]; const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); const fees = this.safeDict(this.fees, 'trading'); return this.safeMarketStructure({ 'id': marketId, 'symbol': base + '/' + quote, 'base': base, 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, 'active': true, 'type': 'spot', 'subType': undefined, 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'contract': false, 'settle': undefined, 'settleId': undefined, 'contractSize': undefined, 'linear': undefined, 'inverse': undefined, 'taker': this.safeNumber(fees, 'taker'), 'maker': this.safeNumber(fees, 'maker'), 'percentage': this.safeBool(fees, 'percentage'), 'tierBased': undefined, 'feeSide': this.safeString(fees, 'feeSide'), 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.parseNumber(this.parsePrecision(this.safeString(market, 'quotePrec'))), 'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'basePrec'))), }, 'limits': { 'amount': { 'min': this.safeNumber(market, 'quoteMinSize'), 'max': this.safeNumber(market, 'quoteMaxSize'), }, 'price': { 'min': this.safeNumber(market, 'baseMinSize'), 'max': this.safeNumber(market, 'baseMaxSize'), }, 'leverage': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': undefined, 'max': undefined, }, }, 'created': undefined, 'info': market, }); } /** * @method * @name cryptomus#fetchCurrencies * @description fetches all available currencies on an exchange * @see https://doc.cryptomus.com/personal/market-cap/assets * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} an associative dictionary of currencies */ async fetchCurrencies(params = {}) { const response = await this.publicGetV1ExchangeMarketAssets(params); // // { // 'state': '0', // 'result': [ // { // 'currency_code': 'USDC', // 'network_code': 'bsc', // 'can_withdraw': true, // 'can_deposit': true, // 'min_withdraw': '1.00000000', // 'max_withdraw': '10000000.00000000', // 'max_deposit': '10000000.00000000', // 'min_deposit': '1.00000000' // }, // ... // ] // } // const coins = this.safeList(response, 'result'); const groupedById = this.groupBy(coins, 'currency_code'); const keys = Object.keys(groupedById); const result = {}; for (let i = 0; i < keys.length; i++) { const id = keys[i]; const code = this.safeCurrencyCode(id); const networks = {}; const networkEntries = groupedById[id]; for (let j = 0; j < networkEntries.length; j++) { const networkEntry = networkEntries[j]; const networkId = this.safeString(networkEntry, 'network_code'); const networkCode = this.networkIdToCode(networkId); networks[networkCode] = { 'id': networkId, 'network': networkCode, 'limits': { 'withdraw': { 'min': this.safeNumber(networkEntry, 'min_withdraw'), 'max': this.safeNumber(networkEntry, 'max_withdraw'), }, 'deposit': { 'min': this.safeNumber(networkEntry, 'min_deposit'), 'max': this.safeNumber(networkEntry, 'max_deposit'), }, }, 'active': undefined, 'deposit': this.safeBool(networkEntry, 'can_withdraw'), 'withdraw': this.safeBool(networkEntry, 'can_deposit'), 'fee': undefined, 'precision': undefined, 'info': networkEntry, }; } result[code] = this.safeCurrencyStructure({ 'id': id, 'code': code, 'networks': networks, 'info': networkEntries, }); } return result; } /** * @method * @name cryptomus#fetchTickers * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market * @see https://doc.cryptomus.com/personal/market-cap/tickers * @param {string[]} [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 * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ async fetchTickers(symbols = undefined, params = {}) { await this.loadMarkets(); symbols = this.marketSymbols(symbols); const response = await this.publicGetV1ExchangeMarketTickers(params); // // { // "data": [ // { // "currency_pair": "MATIC_USDT", // "last_price": "0.342", // "base_volume": "1676.84092771", // "quote_volume": "573.48033609043" // }, // ... // } // const data = this.safeList(response, 'data'); return this.parseTickers(data, symbols); } parseTicker(ticker, market = undefined) { // // { // "currency_pair": "XMR_USDT", // "last_price": "158.04829772", // "base_volume": "0.35185785", // "quote_volume": "55.523761128544" // } // const marketId = this.safeString(ticker, 'currency_pair'); market = this.safeMarket(marketId, market); const symbol = market['symbol']; const last = this.safeString(ticker, 'last_price'); return this.safeTicker({ 'symbol': symbol, 'timestamp': undefined, 'datetime': undefined, 'high': undefined, 'low': undefined, 'bid': undefined, 'bidVolume': undefined, 'ask': undefined, 'askVolume': undefined, 'vwap': undefined, 'open': undefined, 'close': last, 'last': last, 'previousClose': undefined, 'change': undefined, 'percentage': undefined, 'average': undefined, 'baseVolume': this.safeString(ticker, 'base_volume'), 'quoteVolume': this.safeString(ticker, 'quote_volume'), 'info': ticker, }, market); } /** * @method * @name cryptomus#fetchOrderBook * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @see https://doc.cryptomus.com/personal/market-cap/orderbook * @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 * @param {int} [params.level] 0 or 1 or 2 or 3 or 4 or 5 - the level of volume * @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 = { 'currencyPair': market['id'], }; let level = 0; [level, params] = this.handleOptionAndParams(params, 'fetchOrderBook', 'level', level); request['level'] = level; const response = await this.publicGetV1ExchangeMarketOrderBookCurrencyPair(this.extend(request, params)); // // { // "data": { // "timestamp": "1730138702", // "bids": [ // { // "price": "2250.00", // "quantity": "1.00000" // } // ], // "asks": [ // { // "price": "2428.69", // "quantity": "0.16470" // } // ] // } // } // const data = this.safeDict(response, 'data', {}); const timestamp = this.safeTimestamp(data, 'timestamp'); return this.parseOrderBook(data, symbol, timestamp, 'bids', 'asks', 'price', 'quantity'); } /** * @method * @name cryptomus#fetchTrades * @description get the list of most recent trades for a particular symbol * @see https://doc.cryptomus.com/personal/market-cap/trades * @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 (maximum value is 100) * @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 = { 'currencyPair': market['id'], }; const response = await this.publicGetV1ExchangeMarketTradesCurrencyPair(this.extend(request, params)); // // { // "data": [ // { // "trade_id": "01J829C3RAXHXHR09HABGQ1YAT", // "price": "2315.6320500000000000", // "base_volume": "21.9839623057260000", // "quote_volume": "0.0094937200000000", // "timestamp": 1726653796, // "type": "sell" // } // ] // } // const data = this.safeList(response, 'data'); return this.parseTrades(data, market, since, limit); } parseTrade(trade, market = undefined) { // // { // "trade_id": "01J017Q6B3JGHZRP9D2NZHVKFX", // "price": "59498.63487492", // "base_volume": "94.00784310", // "quote_volume": "0.00158000", // "timestamp": 1718028573, // "type": "sell" // } // const timestamp = this.safeTimestamp(trade, 'timestamp'); return this.safeTrade({ 'id': this.safeString(trade, 'trade_id'), 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': market['symbol'], 'side': this.safeString(trade, 'type'), 'price': this.safeString(trade, 'price'), 'amount': this.safeString(trade, 'quote_volume'), 'cost': this.safeString(trade, 'base_volume'), 'takerOrMaker': undefined, 'type': undefined, 'order': undefined, 'fee': { 'currency': undefined, 'cost': undefined, }, 'info': trade, }, market); } /** * @method * @name cryptomus#fetchBalance * @description query for balance and get the amount of funds available for trading or funds locked in orders * @see https://doc.cryptomus.com/personal/converts/balance * @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 request = {}; const response = await this.privateGetV2UserApiExchangeAccountBalance(this.extend(request, params)); // // { // "result": [ // { // "ticker": "AVAX", // "available": "0.00000000", // "held": "0.00000000" // } // ] // } // const result = this.safeList(response, 'result', []); return this.parseBalance(result); } parseBalance(balance) { // // { // "ticker": "AVAX", // "available": "0.00000000", // "held": "0.00000000" // } // const result = { 'info': balance, }; for (let i = 0; i < balance.length; i++) { const balanceEntry = balance[i]; const currencyId = this.safeString(balanceEntry, 'ticker'); const code = this.safeCurrencyCode(currencyId); const account = this.account(); account['free'] = this.safeString(balanceEntry, 'available'); account['used'] = this.safeString(balanceEntry, 'held'); result[code] = account; } return this.safeBalance(result); } /** * @method * @name cryptomus#createOrder * @description create a trade order * @see https://doc.cryptomus.com/personal/exchange/market-order-creation * @see https://doc.cryptomus.com/personal/exchange/limit-order-creation * @param {string} symbol unified symbol of the market to create an order in * @param {string} type 'market' or 'limit' or for spot * @param {string} side 'buy' or 'sell' * @param {float} amount how much of you want to trade in units of the base currency * @param {float} [price] the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders (only for limit orders) * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {float} [params.cost] *market buy only* the quote quantity that can be used as an alternative for the amount * @param {string} [params.clientOrderId] a unique identifier for the order (optional) * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ async createOrder(symbol, type, side, amount, price = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'market': market['id'], 'direction': side, 'tag': 'ccxt', }; const clientOrderId = this.safeString(params, 'clientOrderId'); if (clientOrderId !== undefined) { params = this.omit(params, 'clientOrderId'); request['client_order_id'] = clientOrderId; } const sideBuy = side === 'buy'; const amountToString = this.numberToString(amount); const priceToString = this.numberToString(price); let cost = undefined; [cost, params] = this.handleParamString(params, 'cost'); let response = undefined; if (type === 'market') { if (sideBuy) { let createMarketBuyOrderRequiresPrice = true; [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true); if (createMarketBuyOrderRequiresPrice) { if ((price === undefined) && (cost === undefined)) { throw new InvalidOrder(this.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend (amount * price), alternatively set the createMarketBuyOrderRequiresPrice option of param to false and pass the cost to spend in the amount argument'); } else if (cost === undefined) { cost = Precise.stringMul(amountToString, priceToString); } } else { cost = cost ? cost : amountToString; } request['value'] = cost; } else { request['quantity'] = amountToString; } response = await this.privatePostV2UserApiExchangeOrdersMarket(this.extend(request, params)); } else if (type === 'limit') { if (price === undefined) { throw new ArgumentsRequired(this.id + ' createOrder() requires a price parameter for a ' + type + ' order'); } request['quantity'] = amountToString; request['price'] = price; response = await this.privatePostV2UserApiExchangeOrders(this.extend(request, params)); } else { throw new ArgumentsRequired(this.id + ' createOrder() requires a type parameter (limit or market)'); } // // { // "order_id": "01JEXAFCCC5ZVJPZAAHHDKQBNG" // } // return this.parseOrder(response, market); } /** * @method * @name cryptomus#cancelOrder * @description cancels an open limit order * @see https://doc.cryptomus.com/personal/exchange/limit-order-cancellation * @param {string} id order id * @param {string} symbol unified symbol of the market the order was made in (not used in cryptomus) * @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 = {}; request['orderId'] = id; const response = await this.privateDeleteV2UserApiExchangeOrdersOrderId(this.extend(request, params)); // // { // "success": true // } // return response; } /** * @method * @name cryptomus#fetchOrders * @description fetches information on multiple orders made by the user * @see https://doc.cryptomus.com/personal/exchange/history-of-completed-orders * @param {string} symbol unified market symbol of the market orders were made in (not used in cryptomus) * @param {int} [since] the earliest time in ms to fetch orders for (not used in cryptomus) * @param {int} [limit] the maximum number of order structures to retrieve (not used in cryptomus) * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.direction] order direction 'buy' or 'sell' * @param {string} [params.order_id] order id * @param {string} [params.client_order_id] client order id * @param {string} [params.limit] A special parameter that sets the maximum number of records the request will return * @param {string} [params.offset] A special parameter that sets the number of records from the beginning of the list * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchCanceledAndClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const request = {}; let market = undefined; if (symbol !== undefined) { market = this.market(symbol); request['market'] = market['id']; } if (limit !== undefined) { request['limit'] = limit; } const response = await this.privateGetV2UserApiExchangeOrdersHistory(this.extend(request, params)); // // { // "result": [ // { // "id": "01JEXAPY04JDFBVFC2D23BCKMK", // "type": "market", // "direction": "sell", // "symbol": "TRX_USDT", // "quantity": "67.5400000000000000", // "filledQuantity": "67.5400000000000000", // "filledValue": "20.0053480000000000", // "state": "completed", // "internalState": "filled", // "createdAt": "2024-12-12 11:40:19", // "finishedAt": "2024-12-12 11:40:21", // "deal": { // "id": "01JEXAPZ9C9TWENPFZJASZ1YD2", // "state": "completed", // "createdAt": "2024-12-12 11:40:21", // "completedAt": "2024-12-12 11:40:21", // "averageFilledPrice": "0.2962000000000000", // "transactions": [ // { // "id": "01JEXAPZ9C9TWENPFZJASZ1YD3", // "tradeRole": "taker", // "filledPrice": "0.2962000000000000", // "filledQuantity": "67.5400000000000000", // "filledValue": "20.0053480000000000", // "fee": "0.0000000000000000", // "feeCurrency": "USDT", // "committedAt": "2024-12-12 11:40:21" // } // ] // } // }, // ... // ] // } // const result = this.safeList(response, 'result', []); const orders = []; for (let i = 0; i < result.length; i++) { const order = result[i]; orders.push(this.parseOrder(order, market)); } return orders; } /** * @method * @name cryptomus#fetchOpenOrders * @description fetch all unfilled currently open orders * @see https://doc.cryptomus.com/personal/exchange/list-of-active-orders * @param {string} symbol unified market symbol * @param {int} [since] the earliest time in ms to fetch open orders for (not used in cryptomus) * @param {int} [limit] the maximum number of open orders structures to retrieve (not used in cryptomus) * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.direction] order direction 'buy' or 'sell' * @param {string} [params.order_id] order id * @param {string} [params.client_order_id] client order id * @param {string} [params.limit] A special parameter that sets the maximum number of records the request will return * @param {string} [params.offset] A special parameter that sets the number of records from the beginning of the list * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); let market = undefined; if (symbol !== undefined) { market = this.market(symbol); } const request = {}; if (market !== undefined) { request['market'] = market['id']; } const response = await this.privateGetV2UserApiExchangeOrders(this.extend(request, params)); // // { // "result": [ // { // "id": "01JFFG72CBRDP68K179KC9DSTG", // "direction": "sell", // "symbol": "BTC_USDT", // "price": "102.0130000000000000", // "quantity": "0.0005000000000000", // "value": "0.0510065000000000", // "filledQuantity": "0.0000000000000000", // "filledValue": "0.0000000000000000", // "createdAt": "2024-12-19 09:02:51", // "clientOrderId": "987654321", // "stopLossPrice": "101.12" // }, // ... // ] // } const result = this.safeList(response, 'result', []); return this.parseOrders(result, market, undefined, undefined); } parseOrder(order, market = undefined) { // // createOrder // { // "order_id": "01JEXAFCCC5ZVJPZAAHHDKQBNG" // } // // fetchOrders // { // "id": "01JEXAPY04JDFBVFC2D23BCKMK", // "type": "market", // "direction": "sell", // "symbol": "TRX_USDT", // "quantity": "67.5400000000000000", // "filledQuantity": "67.5400000000000000", // "filledValue": "20.0053480000000000", // "state": "completed", // "internalState": "filled", // "createdAt": "2024-12-12 11:40:19", // "finishedAt": "2024-12-12 11:40:21", // "deal": { // "id": "01JEXAPZ9C9TWENPFZJASZ1YD2", // "state": "completed", // "createdAt": "2024-12-12 11:40:21", // "completedAt": "2024-12-12 11:40:21", // "averageFilledPrice": "0.2962000000000000", // "transactions": [ // { // "id": "01JEXAPZ9C9TWENPFZJASZ1YD3", // "tradeRole": "taker", // "filledPrice": "0.2962000000000000", // "filledQuantity": "67.5400000000000000", // "filledValue": "20.0053480000000000", // "fee": "0.0000000000000000", // "feeCurrency": "USDT", // "committedAt": "2024-12-12 11:40:21" // } // ] // } // }, // ... // // fetchOpenOrders // { // "id": "01JFFG72CBRDP68K179KC9DSTG", // "direction": "sell", // "symbol": "BTC_USDT", // "price": "102.0130000000000000", // "quantity": "0.0005000000000000", // "value": "0.0510065000000000", // "filledQuantity": "0.0000000000000000", // "filledValue": "0.0000000000000000", // "createdAt": "2024-12-19 09:02:51", // "clientOrderId": "987654321", // "stopLossPrice": "101.12" // } // const id = this.safeString2(order, 'order_id', 'id'); const marketId = this.safeString(order, 'symbol'); market = this.safeMarket(marketId, market); const dateTime = this.safeString(order, 'createdAt'); const timestamp = this.parse8601(dateTime); const deal = this.safeDict(order, 'deal', {}); const averageFilledPrice = this.safeNumber(deal, 'averageFilledPrice'); const type = this.safeString(order, 'type'); const side = this.safeString(order, 'direction'); let price = this.safeNumber(order, 'price'); const transaction = this.safeList(deal, 'transactions', []); let fee = undefined; const firstTx = this.safeDict(transaction, 0); const feeCurrency = this.safeString(firstTx, 'feeCurrency'); if (feeCurrency !== undefined) { fee = { 'currency': this.safeCurrencyCode(feeCurrency), 'cost': this.safeNumber(firstTx, 'fee'), }; } if (price === undefined) { price = this.safeNumber(firstTx, 'filledPrice'); } const amount = this.safeNumber(order, 'quantity'); const cost = this.safeNumber(order, 'value'); const status = this.parseOrderStatus(this.safeString(order, 'state')); const clientOrderId = this.safeString(order, 'clientOrderId'); return this.safeOrder({ 'id': id, 'clientOrderId': clientOrderId, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'lastTradeTimestamp': undefined, 'symbol': market['symbol'], 'type': type, 'timeInForce': undefined, 'postOnly': undefined, 'side': side, 'price': price, 'stopPrice': this.safeString(order, 'stopLossPrice'), 'triggerPrice': this.safeString(order, 'stopLossPrice'), 'amount': amount, 'cost': cost, 'average': averageFilledPrice, 'filled': this.safeString(order, 'filledQuantity'), 'remaining': undefined, 'status': status, 'fee': fee, 'trades': undefined, 'info': order, }, market); } parseOrderStatus(status = undefined) { const statuses = { 'active': 'open', 'completed': 'closed', 'partially_completed': 'open', 'cancelled': 'canceled', 'expired': 'expired', 'failed': 'failed', }; return this.safeString(statuses, status, status); } /** * @method * @name cryptomus#fetchTradingFees * @description fetch the trading fees for multiple markets * @see https://trade-docs.coinlist.co/?javascript--nodejs#list-fees * @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 = {}) { const response = await this.privateGetV2UserApiExchangeAccountTariffs(params); // // { // result: { // equivalent_currency_code: 'USD', // current_tariff_step: { // step: '0', // from_turnover: '0.00000000', // maker_percent: '0.08', // taker_percent: '0.1' // }, // tariff_steps: [ // { // step: '0', // from_turnover: '0.00000000', // maker_percent: '0.08', // taker_percent: '0.1' // }, // { // step: '1', // from_turnover: '100001.00000000', // maker_percent: '0.06', // taker_percent: '0.095' // }, // { // step: '2', // from_turnover: '250001.00000000', // maker_percent: '0.055', // taker_percent: '0.085' // }, // { // step: '3', // from_turnover: '500001.00000000', // maker_percent: '0.05', // taker_percent: '0.075' // }, // { // step: '4', // from_turnover: '2500001.00000000', // maker_percent: '0.04', // taker_percent: '0.07' // } // ], // daily_turnover: '0.00000000', // monthly_turnover: '77.52062617', // circulation_funds: '25.48900443' // } // } // const data = this.safeDict(response, 'result', {}); const currentFeeTier = this.safeDict(data, 'current_tariff_step', {}); let makerFee = this.safeString(currentFeeTier, 'maker_percent'); let takerFee = this.safeString(currentFeeTier, 'taker_percent'); makerFee = Precise.stringDiv(makerFee, '100'); takerFee = Precise.stringDiv(takerFee, '100'); const feeTiers = this.safeList(data, 'tariff_steps', []); const result = {}; const tiers = this.parseFeeTiers(feeTiers); for (let i = 0; i < this.symbols.length; i++) { const symbol = this.symbols[i]; result[symbol] = { 'info': response, 'symbol': symbol, 'maker': this.parseNumber(makerFee), 'taker': this.parseNumber(takerFee), 'percentage': true, 'tierBased': true, 'tiers': tiers, }; } return result; } parseFeeTiers(feeTiers, market = undefined) { const takerFees = []; const makerFees = []; for (let i = 0; i < feeTiers.length; i++) { const tier = feeTiers[i]; const turnover = this.safeNumber(tier, 'from_turnover'); let taker = this.safeString(tier, 'taker_percent'); let maker = this.safeString(tier, 'maker_percent'); maker = Precise.stringDiv(maker, '100'); taker = Precise.stringDiv(taker, '100'); makerFees.push([turnover, this.parseNumber(maker)]); takerFees.push([turnover, this.parseNumber(taker)]); } return { 'maker': makerFees, 'taker': takerFees, }; } sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { const endpoint = this.implodeParams(path, params); params = this.omit(params, this.extractParams(path)); let url = this.urls['api'][api] + '/' + endpoint; if (api === 'private') { this.checkRequiredCredentials(); let jsonParams = ''; headers = { 'userId': this.uid, }; if (method !== 'GET') { body = this.json(params); jsonParams = body; headers['Content-Type'] = 'application/json'; } else { const query = this.urlencode(params); if (query.length !== 0) { url += '?' + query; } } const jsonParamsBase64 = this.stringToBase64(jsonParams); const stringToSign = jsonParamsBase64 + this.secret; const signature = this.hash(this.encode(stringToSign), md5); headers['sign'] = signature; } else { const query = this.urlencode(params); if (query.length !== 0) { url += '?' + query; } } return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) { if (response === undefined) { return undefined; } if ('code' in response) { const code = this.safeString(response, 'code'); const feedback = this.id + ' ' + body; this.throwExactlyMatchedException(this.exceptions['exact'], code, feedback); throw new ExchangeError(feedback); } else if ('message' in response) { // // {"message":"Minimum amount 15 USDT","state":1} // const message = this.safeString(response, 'message'); const feedback = this.id + ' ' + body; this.throwExactlyMatchedException(this.exceptions['exact'], message, feedback); this.throwBroadlyMatchedException(this.exceptions['broad'], message, feedback); throw new ExchangeError(feedback); // unknown message } return undefined; } }