UNPKG

@proton/ccxt

Version:

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

1,101 lines (1,099 loc) 81.5 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/protondex.js'; import { TICK_SIZE } from './base/functions/number.js'; import { ExchangeError, ArgumentsRequired, InsufficientFunds, OrderNotFound, BadRequest } from './base/errors.js'; import { Precise } from './base/Precise.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; import { ripemd160 } from './static_dependencies/noble-hashes/ripemd160.js'; import { secp256k1 } from './static_dependencies/noble-curves/secp256k1.js'; import { numberToBytesBE, concatBytes, hexToBytes } from './static_dependencies/noble-curves/abstract/utils.js'; // --------------------------------------------------------------------------- export default class protondex extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'protondex', 'name': 'protondex', 'countries': ['US'], 'rateLimit': 600, 'version': 'v1', 'has': { 'CORS': undefined, 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'addMargin': false, 'cancelOrder': true, 'createOrder': true, 'createReduceOnlyOrder': false, 'createStopLimitOrder': false, 'createStopMarketOrder': false, 'createStopOrder': false, 'fetchBalance': true, 'fetchBorrowRate': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchBorrowRates': false, 'fetchBorrowRatesPerSymbol': false, 'fetchCanceledOrders': true, 'fetchClosedOrders': true, 'fetchCurrencies': false, 'fetchDepositAddress': false, 'fetchDepositAddresses': false, 'fetchDeposits': true, 'fetchFundingHistory': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': false, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchL2OrderBook': false, 'fetchLeverage': false, 'fetchLeverageTiers': false, 'fetchMarginMode': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenInterestHistory': false, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchOrderTrades': true, 'fetchPosition': false, 'fetchPositionMode': false, 'fetchPositions': false, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchTicker': true, 'fetchTickers': true, 'fetchTrades': true, 'fetchTradinFee': false, 'fetchTradingFees': true, 'fetchTransfer': false, 'fetchTransfers': false, 'fetchWithdrawals': false, 'reduceMargin': false, 'setLeverage': false, 'setMarginMode': false, 'setPositionMode': false, 'transfer': false, 'withdraw': false, }, 'hostname': 'https://dex.api.mainnet.metalx.com', 'urls': { 'logo': 'https://protonswap.com/img/logo.svg', 'api': { 'rest': 'https://dex.api.mainnet.metalx.com/dex', 'public': 'https://dex.api.mainnet.metalx.com/dex', 'private': 'https://dex.api.mainnet.metalx.com/dex', }, 'test': { 'rest': 'https://dex.api.testnet.metalx.com/dex', 'public': 'https://dex.api.testnet.metalx.com/dex', 'private': 'https://dex.api.testnet.metalx.com/dex', }, 'www': 'https://app.metalx.com/dex/', 'doc': [ 'https://docs.metalx.com/dex/what-is-metal-x', ], 'fees': [ 'https://docs.metalx.com/dex/what-is-metal-x/dex-fees-and-discounts', ], 'referral': 'https://app.metalx.com/dex/', }, 'api': { 'public': { 'get': [ 'markets/all', 'orders/open', 'orders/history', 'orders/lifecycle', 'orders/depth', 'trades/daily', 'trades/history', 'trades/recent', 'chart/ohlcv', 'status/sync', 'account/balances', // ?{account}' ], 'post': [ 'orders/serialize', 'orders/submit', // application/json - serilized_tx_hex, signatures ], }, 'private': { 'post': [], 'get': [ 'user/fees', 'account/deposits', 'account/withdrawals', ], }, }, 'fees': { 'trading': { 'tierBased': true, 'maker': 0.001, 'taker': 0.001, // tiered fee discounts }, }, 'precision': { 'amount': this.parseNumber('0.00000001'), 'price': this.parseNumber('0.00000001'), }, 'precisionMode': TICK_SIZE, }); } async fetchMarkets(params = {}) { /** * @method * @name protondex#fetchMarkets * @description retrieves data on all markets for protondex * @param {object} params extra parameters specific to the exchange api endpoint * @returns {[object]} an array of objects representing market data */ const response = await this.publicGetMarketsAll(params); // // { // "data": [ // { // "name": "ETH-BTC", // "precision": 6, // "min_volume": "0.00000001", // "min_price": "0.000001", // "volume": "0.015713", // "last_price": "0.069322", // "highest_bid": "0.063892", // "lowest_ask": "0.071437", // "change_in_24h": "2.85", // "size_precision": 8, // "price_precision": 6 // }, // ... // ] // } // const markets = this.safeValue(response, 'data', []); const result = []; for (let i = 0; i < markets.length; i++) { const market = markets[i]; const [baseId, quoteId] = market['symbol'].split('_'); const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); result.push({ 'id': market['symbol'], 'symbol': market['symbol'], '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': true, 'contract': false, 'linear': undefined, 'inverse': undefined, 'taker': this.safeValue(market, 'taker_fee'), 'maker': this.safeValue(market, 'maker_fee'), 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.parseNumber(this.parsePrecision(market['bid_token']['precision'])), 'price': this.parseNumber(this.parsePrecision(market['ask_token']['precision'])), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber(market, 'minPrice'), 'max': undefined, }, 'price': { 'min': this.safeNumber(market, 'minVolume'), 'max': undefined, }, 'cost': { 'min': undefined, 'max': undefined, }, }, 'info': market, }); } return result; } parseTicker(ticker, market = undefined) { // // { // "name":"ETH-BTC", // "precision":6, // "min_volume":"0.00000001", // "min_price":"0.000001", // "volume":"0.000452", // "last_price":"0.079059", // "highest_bid":"0.073472", // "lowest_ask":"0.079059", // "change_in_24h":"8.9", // "size_precision":8, // "price_precision":6 // } // const marketId = this.safeString(ticker, 'name'); market = this.safeMarket(marketId, market, '-'); const timestamp = this.milliseconds(); const last = this.safeString(ticker, 'last_price'); return this.safeTicker({ 'symbol': ticker['symbol'], 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'high': this.safeString(ticker, 'high'), 'low': this.safeString(ticker, 'low'), 'bid': this.safeString(ticker, 'highest_bid'), 'bidVolume': this.safeString(ticker, 'volume_bid'), 'ask': this.safeString(ticker, 'lowest_ask'), 'askVolume': this.safeString(ticker, 'volume_ask'), 'vwap': undefined, 'open': this.safeString(ticker, 'open'), 'close': this.safeString(ticker, 'close'), 'last': last, 'previousClose': undefined, 'change': undefined, 'percentage': this.safeString(ticker, 'change_percentage'), 'average': undefined, 'baseVolume': undefined, 'quoteVolume': this.safeString(ticker, 'volume'), 'info': ticker, }, market); } async fetchTicker(symbol, params = {}) { /** * @method * @name protondex#fetchTicker * @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 protondex api endpoint * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure} */ await this.loadMarkets(); const tickers = await this.fetchTickers(); return tickers[symbol]; } async fetchTickers(symbols = undefined, params = {}) { /** * @method * @name protondex#fetchTickers * @description fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours 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 protondex api endpoint * @returns {object} an array of [ticker structures]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure} */ await this.loadMarkets(); symbols = this.marketSymbols(symbols); const response = await this.publicGetTradesDaily(params); // // { // "data":[ // { // "name":"ETH-BTC", // "precision":6, // "min_volume":"0.00000001", // "min_price":"0.000001", // "volume":"0.000452", // "last_price":"0.079059", // "highest_bid":"0.073472", // "lowest_ask":"0.079059", // "change_in_24h":"8.9", // "size_precision":8, // "price_precision":6 // } // ] // } // const tickers = this.safeValue(response, 'data', []); const result = {}; for (let i = 0; i < tickers.length; i++) { const ticker = this.parseTicker(tickers[i]); const symbol = ticker['symbol']; result[symbol] = ticker; } return this.filterByArray(result, 'symbol', symbols); } async fetchOrderBook(symbol, limit = undefined, params = {}) { /** * @method * @name protondex#fetchOrderBook * @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 protondex api endpoint * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-book-structure} indexed by market symbols */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['symbol'], }; request['limit'] = (limit !== undefined) ? limit : 100; request['step'] = (params['step'] !== undefined) ? params['step'] : 100; const response = await this.publicGetOrdersDepth(this.extend(request, params)); const data = this.safeValue(response, 'data', {}); return this.parseOrderBook(data, market['symbol'], undefined, 'bids', 'asks', 'level', 'bid'); } parseTrade(trade, market = undefined) { // // fetchTrades (public) // // { // "id":"5ec36295-5c8d-4874-8d66-2609d4938557", // "price":"4050.06","size":"0.0044", // "market_name":"ETH-USDT", // "side":"sell", // "created_at":"2021-12-07T17:47:36.811000Z" // } // // fetchMyTrades (private) // // { // "id": "0718d520-c796-4061-a16b-915cd13f20c6", // "price": "0.00000358", // "size": "50.0", // "market_name": "DOGE-BTC", // "order_id": "ff2616d8-58d4-40fd-87ae-937c73eb6f1c", // "side": "buy", // "fee': "0.00000036", // "fee_currency_code": "btc", // "liquidity": "T", // "created_at": "2021-12-08T18:26:33.840000Z" // } // const timestamp = this.parse8601(this.safeString(trade, 'block_time')); const tradeId = this.safeString(trade, 'trade_id'); const priceString = this.safeString(trade, 'price'); const orderSide = this.safeString(trade, 'order_side'); const account = this.safeString(trade, 'account'); const amountString = this.safeString(trade, 'bid_amount'); const orderId = account === this.safeString(trade, 'bid_user') ? this.safeString(trade, 'bid_user_ordinal_order_id') : this.safeString(trade, 'ask_user_ordinal_order_id'); const feeString = account === this.safeString(trade, 'bid_user') ? this.safeString(trade, 'bid_fee') : this.safeString(trade, 'ask_fee'); const feeCurrencyId = account === this.safeString(trade, 'bid_user') ? this.safeString(market, 'baseId') : this.safeString(market, 'quoteId'); let fee = undefined; if (feeString !== undefined) { const feeCurrencyCode = this.safeCurrencyCode(feeCurrencyId); fee = { 'cost': feeString, 'currency': feeCurrencyCode, }; } const orderCost = this.safeString(trade, 'ask_amount'); return this.safeTrade({ 'info': trade, 'id': tradeId, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': market['symbol'], 'order': orderId, 'type': null, 'side': orderSide, 'takerOrMaker': undefined, 'price': priceString, 'amount': amountString, 'cost': orderCost, 'fee': fee, }, market); } parseTrades(trades, market = undefined, since = undefined, limit = undefined, params = {}) { trades = this.toArray(trades); const result = []; for (let i = 0; i < trades.length; i++) { trades[i]['account'] = params['account']; if (params['allMarkets']) { const mSymbol = this.safeString(params['allMarkets'], trades[i]['market_id']); market = this.market(mSymbol); } const trade = this.extend(this.parseTrade(trades[i], market)); result.push(trade); } return result; } async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name protondex#fetchMyTrades * @description fetch all trades made by the user * @param {string|undefined} symbol unified market symbol * @param {int|undefined} since the earliest time in ms to fetch trades for * @param {int|undefined} limit the maximum number of trades structures to retrieve * @param {object} params extra parameters specific to the protondex api endpoint * @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} */ await this.loadMarkets(); const market = this.market(symbol); if (params['account'] === undefined) { throw new ArgumentsRequired(this.id + ' fetchMyTrades() requires a account argument in params'); } const request = { 'account': params['account'], 'symbol': market['symbol'], }; request['limit'] = (limit !== undefined) ? limit : 100; request['offset'] = (params['offset'] !== undefined) ? params['offset'] : 0; if (params['ordinal_order_ids'] !== undefined) { request['ordinal_order_ids'] = params['ordinal_order_ids']; } const response = await this.publicGetTradesHistory(this.extend(request, params)); // // [ // { // "id": "32164924331503616", // "symbol": "LINK_USDT", // "accountType": "SPOT", // "orderId": "32164923987566592", // "side": "SELL", // "type": "MARKET", // "matchRole": "TAKER", // "createTime": 1648635115525, // "price": "11", // "quantity": "0.5", // "amount": "5.5", // "feeCurrency": "USDT", // "feeAmount": "0.007975", // "pageId": "32164924331503616", // "clientOrderId": "myOwnId-321" // } // ] // const data = this.safeValue(response, 'data', []); return this.parseTrades(data, market, 1, 100, { 'account': params['account'] }); } mapIdSymbol(allMarkets) { const marketsmap = {}; for (let i = 0; i < allMarkets.length; i++) { marketsmap[allMarkets[i].info.market_id] = this.safeString(allMarkets[i].info, 'symbol'); } return marketsmap; } parseOrders(orders, market = undefined, since = undefined, limit = undefined, params = {}) { // // the value of orders is either a dict or a list // // dict // // { // 'id1': { ... }, // 'id2': { ... }, // 'id3': { ... }, // ... // } // // list // // [ // { 'id': 'id1', ... }, // { 'id': 'id2', ... }, // { 'id': 'id3', ... }, // ... // ] // let results = []; let current_market = market; if (Array.isArray(orders)) { for (let i = 0; i < orders.length; i++) { if (params['allMarkets']) { const mSymbol = this.safeString(params['allMarkets'], orders[i]['market_id']); current_market = this.market(mSymbol); } const order = this.parseOrder(orders[i], current_market); results.push(order); } } else { const ids = Object.keys(orders); for (let i = 0; i < ids.length; i++) { const id = ids[i]; if (params['allMarkets']) { const mSymbol = this.safeString(params['allMarkets'], orders[i]['market_id']); current_market = this.market(mSymbol); } const order = this.parseOrder(this.extend({ 'id': id }, orders[id]), current_market); results.push(order); } } results = this.sortBy(results, 'timestamp'); const symbol = (market !== undefined) ? market['symbol'] : undefined; return this.filterBySymbolSinceLimit(results, symbol, since, limit); } async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name proton#fetchClosedOrders * @description fetches information on multiple closed orders made by the user * @param {string|undefined} symbol unified market symbol of the market orders were made in * @param {int|undefined} since the earliest time in ms to fetch orders for * @param {int|undefined} limit the maximum number of orde structures to retrieve * @param {object} params extra parameters specific to the proton api endpoint * @param {int|undefined} params.account user account to fetch orders for * @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ await this.loadMarkets(); const allMarkets = await this.fetchMarkets(); const marketIds = this.mapIdSymbol(allMarkets); let market = undefined; if (params['account'] === undefined) { throw new ArgumentsRequired(this.id + ' fetchOrders() requires a account argument in params'); } const request = { 'account': params['account'], 'status': 'delete', }; if (symbol !== null) { market = this.market(symbol); request['symbol'] = market['symbol']; } request['offset'] = (params['offset'] !== undefined) ? params['offset'] : 0; request['limit'] = (limit !== undefined) ? limit : 100; const response = await this.publicGetOrdersHistory(this.extend(request, params)); // // { // "data":[ // { // "id":"5ec36295-5c8d-4874-8d66-2609d4938557", // "price":"4050.06","size":"0.0044", // "market_name":"ETH-USDT", // "side":"sell", // "created_at":"2021-12-07T17:47:36.811000Z" // }, // ] // } // const data = this.safeValue(response, 'data', []); const closedOrders = []; for (let p = 0; p < data.length; p++) { if (data[p]['status'] === 'delete' || data[p]['status'] === 'cancel') { let avgPrice = 0.0; let feeCost = undefined; let cost = 0.0; let amount = 0.0; const fee = {}; const ordinalId = this.safeString(data[p], 'ordinal_order_id'); const account = this.safeString(data[p], 'account_name'); let currency = undefined; if (symbol === null) { symbol = this.safeString(marketIds, data[p]['market_id']); market = this.market(symbol); } const trades = await this.fetchOrderTrades(ordinalId, null, 1, 1, { 'account': account, 'allMarkets': marketIds }); for (let j = 0; j < trades.length; j++) { cost += this.safeFloat(trades[j], 'cost'); amount += this.safeFloat(trades[j], 'amount'); feeCost = Precise.stringAdd(feeCost, this.safeString(trades[j]['fee'], 'cost')); currency = this.safeString(trades[j]['fee'], 'currency'); } if (trades.length !== 0) { avgPrice = parseFloat((cost / amount).toString()); } const askTokenPrecision = this.parseToInt(market.info.ask_token.precision); fee['cost'] = feeCost; fee['currency'] = currency; data[p]['avgPrice'] = avgPrice.toFixed(askTokenPrecision); data[p]['fee'] = fee; data[p]['cost'] = cost.toFixed(askTokenPrecision); closedOrders.push(data[p]); } } market = undefined; return this.parseOrders(closedOrders, market, 1, 100, { 'allMarkets': marketIds }); } async fetchCanceledOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name proton#fetchCanceledOrders * @description fetches information on multiple closed orders made by the user * @param {string|undefined} symbol unified market symbol of the market orders were made in * @param {int|undefined} since the earliest time in ms to fetch orders for * @param {int|undefined} limit the maximum number of orde structures to retrieve * @param {object} params extra parameters specific to the proton api endpoint * @param {int|undefined} params.account user account to fetch orders for * @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ await this.loadMarkets(); let market = undefined; if (params['account'] === undefined) { throw new ArgumentsRequired(this.id + ' fetchOrders() requires a account argument in params'); } const request = { 'account': params['account'], 'status': 'cancel', }; if (symbol !== null) { market = this.market(symbol); request['symbol'] = market['symbol']; } request['offset'] = (params['offset'] !== undefined) ? params['offset'] : 0; request['limit'] = (limit !== undefined) ? limit : 100; const response = await this.publicGetOrdersHistory(this.extend(request, params)); // // { // "data":[ // { // "id":"5ec36295-5c8d-4874-8d66-2609d4938557", // "price":"4050.06","size":"0.0044", // "market_name":"ETH-USDT", // "side":"sell", // "created_at":"2021-12-07T17:47:36.811000Z" // }, // ] // } // const data = this.safeValue(response, 'data', []); return this.parseOrders(data, market); } async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name protondex#fetchOrders * @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 protondex 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); if (params['account'] === undefined) { throw new ArgumentsRequired(this.id + ' fetchOrders() requires a account argument in params'); } const request = { 'account': params['account'], 'symbol': market['symbol'], }; request['offset'] = (params['offset'] !== undefined) ? params['offset'] : 0; request['limit'] = (limit !== undefined) ? limit : 100; if (params['ordinal_order_ids'] !== undefined) { request['ordinal_order_ids'] = params['ordinal_order_ids']; } if (params['trx_id'] !== undefined) { request['trx_id'] = params['trx_id']; } if (params['status'] !== undefined) { request['status'] = params['status']; } const response = await this.publicGetOrdersHistory(this.extend(request, params)); // // { // "data":[ // { // "id":"5ec36295-5c8d-4874-8d66-2609d4938557", // "price":"4050.06","size":"0.0044", // "market_name":"ETH-USDT", // "side":"sell", // "created_at":"2021-12-07T17:47:36.811000Z" // }, // ] // } // const data = this.safeValue(response, 'data', []); for (let p = 0; p < data.length; p++) { let avgPrice = 0.0; let feeCost = undefined; let cost = 0.0; let amount = 0.0; const fee = {}; const ordinalId = this.safeString(data[p], 'ordinal_order_id'); const account = this.safeString(data[p], 'account_name'); let currency = undefined; const trades = await this.fetchOrderTrades(ordinalId, symbol, 1, 1, { 'account': account }); for (let j = 0; j < trades.length; j++) { cost += this.safeFloat(trades[j], 'cost'); amount += this.safeFloat(trades[j], 'amount'); feeCost = Precise.stringAdd(feeCost, this.safeString(trades[j]['fee'], 'cost')); currency = this.safeString(trades[j]['fee'], 'currency'); } if (trades.length !== 0) { avgPrice = parseFloat((cost / amount).toString()); } const askTokenPrecision = this.parseToInt(market.info.ask_token.precision); fee['cost'] = feeCost; fee['currency'] = currency; data[p]['avgPrice'] = avgPrice.toFixed(askTokenPrecision); data[p]['fee'] = fee; data[p]['cost'] = cost.toFixed(askTokenPrecision); } return this.parseOrders(data, market); } async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { /** * @method * @name protondexx#fetchTrades * @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 protondex 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['symbol'], }; request['limit'] = (limit !== undefined) ? limit : 100; request['offset'] = (params['offset'] !== undefined) ? params['offset'] : 0; const response = await this.publicGetTradesRecent(this.extend(request, params)); // // { // "data": [ // { // "id": "0718d520-c796-4061-a16b-915cd13f20c6", // "price": "0.00000358", // "size": "50.0", // "market_name": "DOGE-BTC", // "order_id": "ff2616d8-58d4-40fd-87ae-937c73eb6f1c", // "side": "buy", // "fee': "0.00000036", // "fee_currency_code": "btc", // "liquidity": "T", // "created_at": "2021-12-08T18:26:33.840000Z" // }, // ] // } // const data = this.safeValue(response, 'data', []); return this.parseTrades(data, market, 1, 1); } async fetchTradingFees(params = {}) { /** * @method * @name protondex#fetchTradingFees * @description fetch the trading fees for multiple markets * @param {object} params extra parameters specific to the protondex api endpoint * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/en/latest/manual.html#fee-structure} indexed by market symbols */ await this.loadMarkets(); const response = await this.privateGetUserFees(params); // // { // data: { // maker_fee: '0.0', // taker_fee: '0.2', // btc_volume_30d: '0.0' // } // } // const data = this.safeValue(response, 'data', {}); const makerString = this.safeString(data, 'maker_fee'); const takerString = this.safeString(data, 'taker_fee'); const maker = this.parseNumber(Precise.stringDiv(makerString, '100')); const taker = this.parseNumber(Precise.stringDiv(takerString, '100')); const result = {}; for (let i = 0; i < this.symbols.length; i++) { const symbol = this.symbols[i]; result[symbol] = { 'info': response, 'symbol': symbol, 'maker': maker, 'taker': taker, 'percentage': true, 'tierBased': true, }; } return result; } parseBalance(response) { const result = { 'info': response }; const balances = this.safeValue(response, 'data', []); for (let i = 0; i < balances.length; i++) { const balance = balances[i]; const currencyId = this.safeString(balance, 'currency'); const code = this.safeCurrencyCode(currencyId); const account = this.account(); account['token'] = this.safeString(balance, 'contract'); account['free'] = this.safeString(balance, 'amount'); account['total'] = this.safeString(balance, 'amount'); result[code] = account; } return this.safeBalance(result); } async fetchBalance(params = {}) { /** * @method * @name protondex#fetchBalance * @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 protondex api endpoint * @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure} */ await this.loadMarkets(); if (params['account'] === undefined) { throw new ArgumentsRequired(this.id + ' fetchOrders() requires a account argument in params'); } const request = { 'account': params['account'], }; const response = await this.publicGetAccountBalances(this.extend(request, params)); return this.parseBalance(response); } parseDepositAddress(depositAddress, currency = undefined) { // // { // "address":"0x77b5051f97efa9cc52c9ad5b023a53fc15c200d3", // "tag":"0" // } // const address = this.safeString(depositAddress, 'address'); const tag = this.safeString(depositAddress, 'tag'); this.checkAddress(address); return { 'currency': this.safeCurrencyCode(undefined, currency), 'address': address, 'tag': tag, 'network': undefined, 'info': depositAddress, }; } parseOrderStatus(status) { const statuses = { 'fulfilled': 'closed', 'delete': 'closed', 'cancel': 'canceled', 'pending': 'open', 'open': 'open', 'partially_filled': 'open', }; return this.safeString(statuses, status, status); } parseOrder(order, market = undefined) { // // { // "id":"8bdd79f4-8414-40a2-90c3-e9f4d6d1eef4" // "market":"IOT-BTC" // "price":"0.0000003" // "size":"4.0" // "size_filled":"3.0" // "fee":"0.0075" // "fee_currency_code":"iot" // "funds":"0.0" // "status":"canceled" // "order_type":"buy" // "post_only":false // "operation_type":"market_order" // "created_at":"2018-01-12T21:14:06.747828Z" // } // const timestamp = this.parse8601(this.safeString(order, 'block_time')); const priceString = this.safeString(order, 'price'); const symbol = this.safeString(market, 'symbol', undefined); let amountString = this.safeString(order, 'quantity_init'); let remainingString = this.safeString(order, 'quantity_curr'); let costString = this.safeString(order, 'cost'); const status = this.parseOrderStatus(this.safeString(order, 'status')); let type = this.safeString(order, 'order_type'); if (type !== undefined) { const parts = type.split('_'); type = parts[0]; } const side = this.safeString(order, 'order_side'); let filled = undefined; if (side === '1' && status === 'closed' && symbol !== undefined) { amountString = parseFloat(Precise.stringDiv(amountString, this.safeString(order, 'avgPrice'))).toFixed(market.info.bid_token.precision); remainingString = parseFloat(Precise.stringDiv(remainingString, this.safeString(order, 'avgPrice'))).toFixed(market.info.bid_token.precision); } else if (status === 'canceled') { if (order['quantity_init'] === order['quantity_change']) { filled = '0'; } else { remainingString = this.safeString(order, 'quantity_change'); filled = (order['quantity_init'] - order['quantity_change']).toString(); if (side === '1' && symbol !== undefined) { costString = (order['quantity_init'] - order['quantity_change']).toFixed(market.info.ask_token.precision); amountString = parseFloat(Precise.stringDiv(this.safeString(order, 'quantity_init'), this.safeString(order, 'avgPrice'))).toFixed(market.info.bid_token.precision); remainingString = parseFloat(Precise.stringDiv(remainingString, this.safeString(order, 'avgPrice'))).toFixed(market.info.bid_token.precision); filled = parseFloat(Precise.stringDiv(filled, this.safeString(order, 'avgPrice'))).toFixed(market.info.bid_token.precision); } } } const fee = this.safeValue(order, 'fee'); return this.safeOrder({ 'id': this.safeString(order, 'order_id'), 'clientOrderId': this.safeString(order, 'ordinal_order_id'), 'datetime': this.iso8601(timestamp), 'timestamp': timestamp, 'status': status, 'symbol': symbol, 'type': type, 'side': side, 'price': priceString, 'stopPrice': this.safeString(order, 'trigger_price'), 'cost': costString, 'amount': amountString, 'remaining': remainingString, 'lastTradeTimestamp': timestamp, 'average': this.safeString(order, 'avgPrice'), 'fee': fee, 'filled': filled, }, market); } async fetchOrder(id, symbol = undefined, params = {}) { /** * @method * @name protondex#fetchOrder * @description fetches information on an order made by the user * @param {string|undefined} symbol unified symbol of the market the order was made in * @param {object} params extra parameters specific to the protondex api endpoint * @returns {object} An [order structure]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure} */ await this.loadMarkets(); let orderId = 0; let ordinalID = undefined; if (id.length > 15) { ordinalID = id; } else { orderId = parseInt(id); } const request = {}; request['order_id'] = orderId; request['ordinal_order_id'] = ordinalID; const response = await this.publicGetOrdersLifecycle(this.extend(request, params)); const data = this.safeValue(response, 'data', {}); let avgPrice = 0.0; let cost = 0.0; let amount = 0.0; let feeCost = undefined; const fee = {}; let market = undefined; let askTokenPrecision = 0; if (ordinalID !== undefined) { const ordinalId = this.safeString(data[0], 'ordinal_order_id'); const account = this.safeString(data[0], 'account_name'); const marketid = this.safeString(data[0], 'market_id'); const markets = await this.fetchMarkets(); let markSymbol = undefined; for (let i = 0; i < markets.length; i++) { if (markets[i].info.market_id === marketid) { markSymbol = this.safeString(markets[i], 'symbol'); market = markets[i]; } } let currency = undefined; const trades = await this.fetchOrderTrades(ordinalId, markSymbol, 1, 1, { 'account': account }); for (let j = 0; j < trades.length; j++) { cost += this.safeFloat(trades[j], 'cost'); amount += this.safeFloat(trades[j], 'amount'); feeCost = Precise.stringAdd(feeCost, this.safeString(trades[j]['fee'], 'cost')); currency = this.safeString(trades[j]['fee'], 'currency'); } if (trades.length !== 0) { avgPrice = parseFloat((cost / amount).toString()); } fee['cost'] = feeCost; fee['currency'] = currency; askTokenPrecision = this.parseToInt(market.info.ask_token.precision); } data[0]['avgPrice'] = avgPrice.toFixed(askTokenPrecision); data[0]['fee'] = fee; data[0]['cost'] = cost.toFixed(askTokenPrecision); return this.parseOrder(data[0], market); } async fetchOrderTrades(id, symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name poloniex#fetchOrderTrades * @description fetch the trade * @param {string} id order id * @param {string|undefined} symbol unified market symbol * @param {int|undefined} since the earliest time in ms to fetch trades for * @param {int|undefined} limit the maximum number of trades to retrieve * @param {object} params extra parameters specific to the poloniex api endpoint * @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} */ await this.loadMarkets(); if (params['account'] === undefined) { throw new ArgumentsRequired(this.id + ' fetchOrderTrades() requires a account argument in params'); } let market = undefined; const request = { 'account': params['account'], 'ordinal_order_ids': [id], }; if (symbol !== null) { market = this.market(symbol); request['symbol'] = market['symbol']; } const response = await this.publicGetTradesHistory(this.extend(request, params)); // // [ // { // "block_num": "215336694", // "block_time": "2023-09-21T17:54:49.500Z", // "trade_id": "3892445", // "market_id": "1", // "price": "0.000612", // "bid_user": "metallicus", // "bid_user_order_id": "7259690", // "bid_user_ordinal_order_id": 719415c560eab4854d581ca710634669689676518841983011f7721498e85154, // "bid_total": 1764.7058, // "bid_amount": 1762.9411, // "bid_fee": 1.7647, // "bid_referrer": "", // "bid_referrer_fee": 0, // "ask_user": "otctest", // "ask_user_order_id": "7259952", // "ask_user_ordinal_order_id": 1a13fd86ddc3facb2c87bbfb39ce243bebe2c20cf1963ddbcf2a12f05aa44572, // "ask_total": 1.08, // "ask_amount": 1.08, // "ask_fee": 0, // "ask_referrer": "", // "ask_referrer_fee": 0, // "order_side": 1, // "trx_id": 8e135c1e82176d8780c5ef9cbef31a7051dcb0b157b9011e18597770d09c7cee, // } // ] // const data = this.safeValue(response, 'data', []); return this.parseTrades(data, market, 1, 1, { 'account': params['account'], 'allMarkets': params['allMarkets'] }); } async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name protondex#fetchOpenOrders * @description fetch all unfilled currently open orders * @description fetch all unfilled currently open orders * @param {string|undefined} symbol unified market symbol * @param {int|undefined} since the earliest time in ms to fetch open orders for * @param {int|undefined} limit the maximum number of open orders structures to retrieve * @param {object} params extra parameters specific to the protondex api endpoint * @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure} */ await this.loadMarkets(); const market = this.market(symbol); if (params['account'] === undefined) { throw new ArgumentsRequired(this.id + ' fetchOrders() requires a account argument in params'); } const request = { 'account': params['account'], 'symbol': market['symbol'], }; request['offset'] = (params['offset'] !== undefined) ? params['offset'] : 0; request['limit'] = (limit !== undefined) ? limit : 100; if (params['ordinal_order_ids'] !== undefined) { request['ordinal_order_ids'] = params['ordinal_order_ids']; } const response = await this.publicGetOrdersOpen(this.extend(request, params)); const data = this.safeValu