UNPKG

ccxt

Version:

A cryptocurrency trading API with more than 100 exchanges in JavaScript / TypeScript / Python / C# / PHP / Go

1,157 lines (1,153 loc) • 145 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var Precise = require('./base/Precise.js'); var paradex$1 = require('./abstract/paradex.js'); var errors = require('./base/errors.js'); var number = require('./base/functions/number.js'); var crypto = require('./base/functions/crypto.js'); var sha3 = require('./static_dependencies/noble-hashes/sha3.js'); var secp256k1 = require('./static_dependencies/noble-curves/secp256k1.js'); // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- /** * @class paradex * @description Paradex is a decentralized exchange built on the StarkWare layer 2 scaling solution. To access private methods you can either use the ETH public key and private key by setting (exchange.privateKey and exchange.walletAddress) * or alternatively you can provide the startknet private key and public key by setting exchange.options['paradexAccount'] with add {"privateKey": A, "publicKey": B, "address": C} * @augments Exchange */ class paradex extends paradex$1["default"] { describe() { return this.deepExtend(super.describe(), { 'id': 'paradex', 'name': 'Paradex', 'countries': [], 'version': 'v1', 'rateLimit': 50, 'certified': false, 'pro': true, 'dex': true, 'has': { 'CORS': undefined, 'spot': false, 'margin': false, 'swap': true, 'future': false, 'option': false, 'addMargin': false, 'borrowCrossMargin': false, 'borrowIsolatedMargin': false, 'cancelAllOrders': true, 'cancelAllOrdersAfter': false, 'cancelOrder': true, 'cancelOrders': true, 'cancelOrdersForSymbols': false, 'closeAllPositions': false, 'closePosition': false, 'createMarketBuyOrderWithCost': false, 'createMarketOrderWithCost': false, 'createMarketSellOrderWithCost': false, 'createOrder': true, 'createOrders': true, 'createReduceOnlyOrder': false, 'createStopOrder': true, 'createTriggerOrder': true, 'editOrder': true, 'fetchAccounts': false, 'fetchAllGreeks': true, 'fetchBalance': true, 'fetchBorrowInterest': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchCanceledOrders': false, 'fetchClosedOrders': false, 'fetchCrossBorrowRate': false, 'fetchCrossBorrowRates': false, 'fetchCurrencies': false, 'fetchDepositAddress': false, 'fetchDepositAddresses': false, 'fetchDeposits': true, 'fetchDepositWithdrawFee': false, 'fetchDepositWithdrawFees': false, 'fetchFundingHistory': true, 'fetchFundingRate': false, 'fetchFundingRateHistory': true, 'fetchFundingRates': false, 'fetchGreeks': true, 'fetchIndexOHLCV': true, 'fetchIsolatedBorrowRate': false, 'fetchIsolatedBorrowRates': false, 'fetchLedger': false, 'fetchLeverage': true, 'fetchLeverageTiers': false, 'fetchLiquidations': false, 'fetchMarginMode': true, 'fetchMarketLeverageTiers': false, 'fetchMarkets': true, 'fetchMarkOHLCV': true, 'fetchMyLiquidations': true, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenInterest': true, 'fetchOpenInterestHistory': false, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchOrderTrades': false, 'fetchPosition': true, 'fetchPositionMode': false, 'fetchPositions': true, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchStatus': true, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': true, 'fetchTradingFees': true, 'fetchTransfer': false, 'fetchTransfers': true, 'fetchWithdrawal': false, 'fetchWithdrawals': true, 'reduceMargin': false, 'repayCrossMargin': false, 'repayIsolatedMargin': false, 'sandbox': true, 'setLeverage': true, 'setMarginMode': true, 'setPositionMode': false, 'transfer': false, 'withdraw': false, }, 'timeframes': { '1m': 1, '3m': 3, '5m': 5, '15m': 15, '30m': 30, '1h': 60, }, 'hostname': 'paradex.trade', 'urls': { 'logo': 'https://github.com/user-attachments/assets/84628770-784e-4ec4-a759-ec2fbb2244ea', 'api': { 'v1': 'https://api.prod.{hostname}/v1', 'v2': 'https://api.prod.{hostname}/v2', }, 'test': { 'v1': 'https://api.testnet.{hostname}/v1', 'v2': 'https://api.testnet.{hostname}/v2', }, 'www': 'https://www.paradex.trade/', 'doc': 'https://docs.api.testnet.paradex.trade/', 'fees': 'https://docs.paradex.trade/getting-started/trading-fees', 'referral': 'https://app.paradex.trade/r/ccxt24', }, 'api': { 'public': { 'get': { 'bbo/{market}': 1, 'bbo/{market}/interactive': 1, 'funding/data': 1, 'markets': 1, 'markets/klines': 1, 'markets/summary': 1, 'orderbook/{market}': 1, 'orderbook/{market}/impact-price': 1, 'orderbook/{market}/interactive': 1, 'insurance': 1, 'jwks.json': 1, 'onboarding': 1, 'referrals/config': 1, 'staking/config': 1, 'system/announcements': 1, 'system/config': 1, 'system/portfolio-margin-config': 1, 'system/state': 1, 'system/time': 1, 'system/volume-tiers': 1, 'trades': 1, 'vaults': 1, 'vaults/balance': 1, 'vaults/config': 1, 'vaults/history': 1, 'vaults/positions': 1, 'vaults/summary': 1, 'vaults/transfers': 1, 'xp/fee-config': 1, 'xp/public-transfers': 1, 'xp/transfer/{transfer_id}': 1, }, }, 'private': { 'get': { 'account': 1, 'account/compliance': 1, 'account/history': 1, 'account/info': 1, 'account/margin': 1, 'account/profile': 1, 'account/settings': 1, 'account/subaccounts': 1, 'account/summary': 1, 'balance': 1, 'fills': 1, 'funding/payments': 1, 'positions': 1, 'tradebusts': 1, 'transactions': 1, 'account/keys/subkeys': 1, 'account/keys/subkeys/{public_key}': 1, 'account/tokens': 1, 'algo/orders': 1, 'algo/orders-history': 1, 'algo/orders/{algo_id}': 1, 'block-trades': 1, 'block-trades/{block_trade_id}': 1, 'block-trades/{block_trade_id}/offers': 1, 'block-trades/{block_trade_id}/offers/{offer_id}': 1, 'liquidations': 1, 'orders': 1, 'orders-history': 1, 'orders/by_client_id/{client_id}': 1, 'orders/{order_id}': 1, 'referrals/qr-code': 1, 'referrals/summary': 1, 'staking/history': 1, 'staking/summary': 1, 'transfers': 1, 'vaults/account-summary': 1, 'vaults/mine': 1, 'xp/account-balance': 1, 'xp/transfers': 1, // 'points_data/{market}/{program}': 1, }, 'post': { 'account/compliance': 1, 'account/margin/{market}': 1, 'account/profile/market_max_slippage/{market}': 1, 'account/profile/notifications': 1, 'account/profile/notifications/last_seen': 1, 'account/profile/referral_code': 1, 'account/profile/refresh_inventory': 1, 'account/profile/size_currency_display': 1, 'account/profile/username': 1, 'account/referrer': 1, 'account/settings/trading_value_display': 1, 'account/keys/subkeys/activate': 1, 'account/keys/subkeys': 1, 'account/tokens': 1, 'algo/orders': 1, 'auth': 1, 'block-trades': 1, 'block-trades/{block_trade_id}/execute': 1, 'block-trades/{block_trade_id}/offers': 1, 'block-trades/{block_trade_id}/offers/{offer_id}/execute': 1, 'onboarding': 1, 'orders': 1, 'orders/batch': 1, 'v2/auth': 1, 'v2/onboarding': 1, 'vaults': 1, 'xp/transfer': 1, // 'account/profile/max_slippage': 1, }, 'put': { 'account/profile': 1, 'account/keys/subkeys/{public_key}': 1, 'orders/{order_id}': 1, }, 'delete': { 'account/keys/subkeys/{public_key}': 1, 'account/tokens/{lookup_id}': 1, 'algo/orders/{algo_id}': 1, 'block-trades/{block_trade_id}': 1, 'block-trades/{block_trade_id}/offers/{offer_id}': 1, 'orders': 1, 'orders/batch': 1, 'orders/by_client_id/{client_id}': 1, 'orders/{order_id}': 1, }, }, }, 'fees': { 'swap': { 'taker': this.parseNumber('0.0002'), 'maker': this.parseNumber('0.0002'), }, 'spot': { 'taker': this.parseNumber('0.0002'), 'maker': this.parseNumber('0.0002'), }, }, 'requiredCredentials': { 'apiKey': false, 'secret': false, 'walletAddress': true, 'privateKey': true, }, 'exceptions': { 'exact': { 'VALIDATION_ERROR': errors.AuthenticationError, 'BINDING_ERROR': errors.OperationRejected, 'INTERNAL_ERROR': errors.ExchangeError, 'NOT_FOUND': errors.BadRequest, 'SERVICE_UNAVAILABLE': errors.ExchangeError, 'INVALID_REQUEST_PARAMETER': errors.BadRequest, 'ORDER_ID_NOT_FOUND': errors.InvalidOrder, 'ORDER_IS_CLOSED': errors.InvalidOrder, 'ORDER_IS_NOT_OPEN_YET': errors.InvalidOrder, 'CLIENT_ORDER_ID_NOT_FOUND': errors.InvalidOrder, 'DUPLICATED_CLIENT_ID': errors.InvalidOrder, 'INVALID_PRICE_PRECISION': errors.OperationRejected, 'INVALID_SYMBOL': errors.OperationRejected, 'INVALID_TOKEN': errors.OperationRejected, 'INVALID_ETHEREUM_ADDRESS': errors.OperationRejected, 'INVALID_ETHEREUM_SIGNATURE': errors.OperationRejected, 'INVALID_STARKNET_ADDRESS': errors.OperationRejected, 'INVALID_STARKNET_SIGNATURE': errors.OperationRejected, 'STARKNET_SIGNATURE_VERIFICATION_FAILED': errors.AuthenticationError, 'BAD_STARKNET_REQUEST': errors.BadRequest, 'ETHEREUM_SIGNER_MISMATCH': errors.BadRequest, 'ETHEREUM_HASH_MISMATCH': errors.BadRequest, 'NOT_ONBOARDED': errors.BadRequest, 'INVALID_TIMESTAMP': errors.BadRequest, 'INVALID_SIGNATURE_EXPIRATION': errors.AuthenticationError, 'ACCOUNT_NOT_FOUND': errors.AuthenticationError, 'INVALID_ORDER_SIGNATURE': errors.AuthenticationError, 'PUBLIC_KEY_INVALID': errors.BadRequest, 'UNAUTHORIZED_ETHEREUM_ADDRESS': errors.BadRequest, 'ETHEREUM_ADDRESS_ALREADY_ONBOARDED': errors.BadRequest, 'MARKET_NOT_FOUND': errors.BadRequest, 'ALLOWLIST_ENTRY_NOT_FOUND': errors.BadRequest, 'USERNAME_IN_USE': errors.AuthenticationError, 'GEO_IP_BLOCK': errors.PermissionDenied, 'ETHEREUM_ADDRESS_BLOCKED': errors.PermissionDenied, 'PROGRAM_NOT_FOUND': errors.BadRequest, 'INVALID_DASHBOARD': errors.OperationRejected, 'MARKET_NOT_OPEN': errors.BadRequest, 'INVALID_REFERRAL_CODE': errors.OperationRejected, 'PARENT_ADDRESS_ALREADY_ONBOARDED': errors.BadRequest, 'INVALID_PARENT_ACCOUNT': errors.OperationRejected, 'INVALID_VAULT_OPERATOR_CHAIN': errors.OperationRejected, 'VAULT_OPERATOR_ALREADY_ONBOARDED': errors.OperationRejected, 'VAULT_NAME_IN_USE': errors.OperationRejected, 'BATCH_SIZE_OUT_OF_RANGE': errors.OperationRejected, 'ISOLATED_MARKET_ACCOUNT_MISMATCH': errors.OperationRejected, 'POINTS_SUMMARY_NOT_FOUND': errors.OperationRejected, '-32700': errors.BadRequest, '-32600': errors.BadRequest, '-32601': errors.BadRequest, '-32602': errors.BadRequest, '-32603': errors.ExchangeError, '100': errors.BadRequest, '40110': errors.AuthenticationError, '40111': errors.AuthenticationError, '40112': errors.PermissionDenied, // Geo IP blocked }, 'broad': { 'missing or malformed jwt': errors.AuthenticationError, }, }, 'precisionMode': number.TICK_SIZE, 'commonCurrencies': {}, 'options': { 'paradexAccount': undefined, 'broker': 'CCXT', }, 'features': { 'spot': undefined, 'forSwap': { 'sandbox': true, 'createOrder': { 'marginMode': false, 'triggerPrice': true, 'triggerDirection': true, 'triggerPriceType': undefined, 'stopLossPrice': false, 'takeProfitPrice': false, 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': true, 'FOK': false, 'PO': true, 'GTD': false, }, 'hedged': false, 'trailing': false, 'leverage': false, 'marketBuyByCost': false, 'marketBuyRequiresPrice': false, 'selfTradePrevention': true, 'iceberg': false, }, 'createOrders': { 'max': 10, }, 'fetchMyTrades': { 'marginMode': false, 'limit': 100, 'daysBack': 100000, 'untilDays': 100000, 'symbolRequired': false, }, 'fetchOrder': { 'marginMode': false, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOpenOrders': { 'marginMode': false, 'limit': 100, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOrders': { 'marginMode': false, 'limit': 100, 'daysBack': 100000, 'untilDays': 100000, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchClosedOrders': undefined, 'fetchOHLCV': { 'limit': undefined, // todo by from/to }, }, 'swap': { 'linear': { 'extends': 'forSwap', }, 'inverse': undefined, }, 'future': { 'linear': undefined, 'inverse': undefined, }, }, }); } /** * @method * @name paradex#fetchTime * @description fetches the current integer timestamp in milliseconds from the exchange server * @see https://docs.paradex.trade/api/prod/system/get-time-unix-milliseconds * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {int} the current integer timestamp in milliseconds from the exchange server */ async fetchTime(params = {}) { const response = await this.publicGetSystemTime(params); // // { // "server_time": "1681493415023" // } // return this.safeInteger(response, 'server_time'); } /** * @method * @name paradex#fetchStatus * @description the latest known information on the availability of the exchange API * @see https://docs.paradex.trade/api/prod/system/get-state * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [status structure]{@link https://docs.ccxt.com/?id=exchange-status-structure} */ async fetchStatus(params = {}) { const response = await this.publicGetSystemState(params); // // { // "status": "ok" // } // const status = this.safeString(response, 'status'); return { 'status': (status === 'ok') ? 'ok' : 'maintenance', 'updated': undefined, 'eta': undefined, 'url': undefined, 'info': response, }; } /** * @method * @name paradex#fetchMarkets * @description retrieves data on all markets for paradex * @see https://docs.paradex.trade/api/prod/markets/get-markets * @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.publicGetMarkets(params); // // { // "results": [ // { // "symbol": "BODEN-USD-PERP", // "base_currency": "BODEN", // "quote_currency": "USD", // "settlement_currency": "USDC", // "order_size_increment": "1", // "price_tick_size": "0.00001", // "min_notional": "200", // "open_at": 1717065600000, // "expiry_at": 0, // "asset_kind": "PERP", // "position_limit": "2000000", // "price_bands_width": "0.2", // "max_open_orders": 50, // "max_funding_rate": "0.05", // "delta1_cross_margin_params": { // "imf_base": "0.2", // "imf_shift": "180000", // "imf_factor": "0.00071", // "mmf_factor": "0.5" // }, // "price_feed_id": "9LScEHse1ioZt2rUuhwiN6bmYnqpMqvZkQJDNUpxVHN5", // "oracle_ewma_factor": "0.14999987905913592", // "max_order_size": "520000", // "max_funding_rate_change": "0.0005", // "max_tob_spread": "0.2" // } // ] // } // const data = this.safeList(response, 'results'); return this.parseMarkets(data); } parseMarket(market) { // // { // "symbol": "BODEN-USD-PERP", // "base_currency": "BODEN", // "quote_currency": "USD", // "settlement_currency": "USDC", // "order_size_increment": "1", // "price_tick_size": "0.00001", // "min_notional": "200", // "open_at": 1717065600000, // "expiry_at": 0, // "asset_kind": "PERP", // "position_limit": "2000000", // "price_bands_width": "0.2", // "max_open_orders": 50, // "max_funding_rate": "0.05", // "delta1_cross_margin_params": { // "imf_base": "0.2", // "imf_shift": "180000", // "imf_factor": "0.00071", // "mmf_factor": "0.5" // }, // "price_feed_id": "9LScEHse1ioZt2rUuhwiN6bmYnqpMqvZkQJDNUpxVHN5", // "oracle_ewma_factor": "0.14999987905913592", // "max_order_size": "520000", // "max_funding_rate_change": "0.0005", // "max_tob_spread": "0.2" // } // // { // "symbol":"BTC-USD-96000-C", // "base_currency":"BTC", // "quote_currency":"USD", // "settlement_currency":"USDC", // "order_size_increment":"0.001", // "price_tick_size":"0.01", // "min_notional":"100", // "open_at":"1736764200000", // "expiry_at":"0", // "asset_kind":"PERP_OPTION", // "market_kind":"cross", // "position_limit":"10", // "price_bands_width":"0.05", // "iv_bands_width":"0.05", // "max_open_orders":"100", // "max_funding_rate":"0.02", // "option_cross_margin_params":{ // "imf":{ // "long_itm":"0.2", // "short_itm":"0.15", // "short_otm":"0.1", // "short_put_cap":"0.5", // "premium_multiplier":"1" // }, // "mmf":{ // "long_itm":"0.1", // "short_itm":"0.075", // "short_otm":"0.05", // "short_put_cap":"0.5", // "premium_multiplier":"0.5" // } // }, // "price_feed_id":"GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU", // "oracle_ewma_factor":"0.20000046249626113", // "max_order_size":"2", // "max_funding_rate_change":"0.02", // "max_tob_spread":"0.2", // "interest_rate":"0.0001", // "clamp_rate":"0.02", // "option_type":"CALL", // "strike_price":"96000", // "funding_period_hours":"24", // "tags":[ // ] // } // const assetKind = this.safeString(market, 'asset_kind'); const isOptionPerpetual = (assetKind === 'PERP_OPTION'); const isOptionDelivery = (assetKind === 'OPTION'); const isOption = isOptionPerpetual || isOptionDelivery; const type = (isOption) ? 'option' : 'swap'; const isSwap = (type === 'swap'); const marketId = this.safeString(market, 'symbol'); const quoteId = this.safeString(market, 'quote_currency'); const baseId = this.safeString(market, 'base_currency'); const quote = this.safeCurrencyCode(quoteId); const base = this.safeCurrencyCode(baseId); const settleId = this.safeString(market, 'settlement_currency'); const settle = this.safeCurrencyCode(settleId); let symbol = base + '/' + quote + ':' + settle; let expiry = this.safeInteger(market, 'expiry_at'); const optionType = this.safeString(market, 'option_type'); const strikePrice = this.safeString(market, 'strike_price'); const takerFee = this.parseNumber('0.0003'); let makerFee = this.parseNumber('-0.00005'); if (isOption) { const optionTypeSuffix = (optionType === 'CALL') ? 'C' : 'P'; const deliveryValue = (expiry === 0) ? '' : this.yymmdd(expiry) + '-'; symbol = symbol + '-' + deliveryValue + strikePrice + '-' + optionTypeSuffix; makerFee = this.parseNumber('0.0003'); } else { expiry = undefined; } return this.safeMarketStructure({ 'id': marketId, 'symbol': symbol, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'quoteId': quoteId, 'settleId': settleId, 'type': type, 'spot': false, 'margin': undefined, 'swap': isSwap, 'future': false, 'option': isOption, 'active': this.safeBool(market, 'enableTrading'), 'contract': true, 'linear': true, 'inverse': false, 'taker': takerFee, 'maker': makerFee, 'contractSize': this.parseNumber('1'), 'expiry': expiry, 'expiryDatetime': (expiry === 0) ? undefined : this.iso8601(expiry), 'strike': this.parseNumber(strikePrice), 'optionType': this.safeStringLower(market, 'option_type'), 'precision': { 'amount': this.safeNumber(market, 'order_size_increment'), 'price': this.safeNumber(market, 'price_tick_size'), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': undefined, 'max': this.safeNumber(market, 'max_order_size'), }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': this.safeNumber(market, 'min_notional'), 'max': undefined, }, }, 'created': undefined, 'info': market, }); } parseTradingFee(fee, market = undefined) { // // { // "symbol": "BTC-USD-PERP", // "fee_config": { // "api_fee": { // "maker_fee": { // "fee": "0.000075", // "fee_cap": "0.125", // "fee_floor": "-0.125" // }, // "taker_fee": { // "fee": "0.000125", // "fee_cap": "0.125", // "fee_floor": "-0.125" // } // } // } // } // const marketId = this.safeString(fee, 'symbol'); market = this.safeMarket(marketId, market); const feeConfig = this.safeDict(fee, 'fee_config', {}); const apiFee = this.safeDict(feeConfig, 'api_fee', {}); const makerFee = this.safeDict(apiFee, 'maker_fee', {}); const takerFee = this.safeDict(apiFee, 'taker_fee', {}); return { 'info': fee, 'symbol': market['symbol'], 'maker': this.safeNumber(makerFee, 'fee', this.safeNumber(market, 'maker')), 'taker': this.safeNumber(takerFee, 'fee', this.safeNumber(market, 'taker')), 'percentage': true, 'tierBased': false, }; } /** * @method * @name paradex#fetchTradingFee * @description fetch the trading fees for a market * @see https://docs.paradex.trade/api/prod/markets/get-markets * @param {string} symbol unified market symbol * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [fee structure]{@link https://docs.ccxt.com/?id=fee-structure} */ async fetchTradingFee(symbol, params = {}) { if (symbol === undefined) { throw new errors.ArgumentsRequired(this.id + ' fetchTradingFee() requires a symbol argument'); } await this.loadMarkets(); const market = this.market(symbol); const request = { 'market': market['id'], }; const response = await this.publicGetMarkets(this.extend(request, params)); // // { // "results": [ // { // "symbol": "BTC-USD-PERP", // "fee_config": { // "api_fee": { // "maker_fee": { // "fee": "0.000075" // }, // "taker_fee": { // "fee": "0.000125" // } // } // } // } // ] // } // const data = this.safeList(response, 'results', []); const first = this.safeDict(data, 0, {}); return this.parseTradingFee(first, market); } /** * @method * @name paradex#fetchTradingFees * @description fetch the trading fees for multiple markets * @see https://docs.paradex.trade/api/prod/markets/get-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.publicGetMarkets(params); // // { // "results": [ // { // "symbol": "BTC-USD-PERP", // "fee_config": { // "api_fee": { // "maker_fee": { // "fee": "0.000075" // }, // "taker_fee": { // "fee": "0.000125" // } // } // } // } // ] // } // const fees = this.safeList(response, 'results', []); const result = {}; for (let i = 0; i < fees.length; i++) { const fee = this.parseTradingFee(fees[i]); const symbol = fee['symbol']; result[symbol] = fee; } return result; } /** * @method * @name paradex#fetchOHLCV * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market * @see https://docs.paradex.trade/api/prod/markets/klines * @param {string} symbol unified symbol of the market to fetch OHLCV data for * @param {string} timeframe the length of time each candle represents * @param {int} [since] timestamp in ms of the earliest candle to fetch * @param {int} [limit] the maximum amount of candles to fetch * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {int} [params.until] timestamp in ms of the latest candle to fetch * @param {string} [params.price] "last", "mark", "index", default is "last" * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume */ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'resolution': this.safeString(this.timeframes, timeframe, timeframe), 'symbol': market['id'], }; const now = this.milliseconds(); const duration = this.parseTimeframe(timeframe); const until = this.safeInteger2(params, 'until', 'till', now); const price = this.safeString(params, 'price'); if (price !== undefined) { request['price_kind'] = price; } params = this.omit(params, ['until', 'till', 'price']); if (since !== undefined) { request['start_at'] = since; if (limit !== undefined) { request['end_at'] = this.sum(since, duration * (limit + 1) * 1000) - 1; } else { request['end_at'] = until; } } else { request['end_at'] = until; if (limit !== undefined) { request['start_at'] = until - duration * (limit + 1) * 1000 + 1; } else { request['start_at'] = until - duration * 101 * 1000 + 1; } } const response = await this.publicGetMarketsKlines(this.extend(request, params)); // // { // "results": [ // [ // 1720071900000, // 58961.3, // 58961.3, // 58961.3, // 58961.3, // 1591 // ] // ] // } // const data = this.safeList(response, 'results', []); return this.parseOHLCVs(data, market, timeframe, since, limit); } parseOHLCV(ohlcv, market = undefined) { // // [ // 1720071900000, // 58961.3, // 58961.3, // 58961.3, // 58961.3, // 1591 // ] // return [ this.safeInteger(ohlcv, 0), this.safeNumber(ohlcv, 1), this.safeNumber(ohlcv, 2), this.safeNumber(ohlcv, 3), this.safeNumber(ohlcv, 4), this.safeNumber(ohlcv, 5), ]; } /** * @method * @name paradex#fetchTickers * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market * @see https://docs.paradex.trade/api/prod/markets/get-markets-summary * @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 * @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 request = { 'market': 'ALL', }; const response = await this.publicGetMarketsSummary(this.extend(request, params)); // // { // "results": [ // { // "symbol": "BTC-USD-PERP", // "oracle_price": "68465.17449906", // "mark_price": "68465.17449906", // "last_traded_price": "68495.1", // "bid": "68477.6", // "ask": "69578.2", // "volume_24h": "5815541.397939004", // "total_volume": "584031465.525259686", // "created_at": 1718170156580, // "underlying_price": "67367.37268422", // "open_interest": "162.272", // "funding_rate": "0.01629574927887", // "price_change_rate_24h": "0.009032" // } // ] // } // const data = this.safeList(response, 'results', []); return this.parseTickers(data, symbols); } /** * @method * @name paradex#fetchTicker * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market * @see https://docs.paradex.trade/api/prod/markets/get-markets-summary * @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 = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'market': market['id'], }; const response = await this.publicGetMarketsSummary(this.extend(request, params)); // // { // "results": [ // { // "symbol": "BTC-USD-PERP", // "oracle_price": "68465.17449906", // "mark_price": "68465.17449906", // "last_traded_price": "68495.1", // "bid": "68477.6", // "ask": "69578.2", // "volume_24h": "5815541.397939004", // "total_volume": "584031465.525259686", // "created_at": 1718170156580, // "underlying_price": "67367.37268422", // "open_interest": "162.272", // "funding_rate": "0.01629574927887", // "price_change_rate_24h": "0.009032" // } // ] // } // const data = this.safeList(response, 'results', []); const ticker = this.safeDict(data, 0, {}); return this.parseTicker(ticker, market); } parseTicker(ticker, market = undefined) { // // { // "symbol": "BTC-USD-PERP", // "oracle_price": "68465.17449906", // "mark_price": "68465.17449906", // "last_traded_price": "68495.1", // "bid": "68477.6", // "ask": "69578.2", // "volume_24h": "5815541.397939004", // "total_volume": "584031465.525259686", // "created_at": 1718170156581, // "underlying_price": "67367.37268422", // "open_interest": "162.272", // "funding_rate": "0.01629574927887", // "price_change_rate_24h": "0.009032" // } // let percentage = this.safeString(ticker, 'price_change_rate_24h'); if (percentage !== undefined) { percentage = Precise["default"].stringMul(percentage, '100'); } const last = this.safeString(ticker, 'last_traded_price'); const marketId = this.safeString(ticker, 'symbol'); market = this.safeMarket(marketId, market); const symbol = market['symbol']; const timestamp = this.safeInteger(ticker, 'created_at'); return this.safeTicker({ 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'high': undefined, 'low': undefined, 'bid': this.safeString(ticker, 'bid'), 'bidVolume': undefined, 'ask': this.safeString(ticker, 'ask'), 'askVolume': undefined, 'vwap': undefined, 'open': undefined, 'close': last, 'last': last, 'previousClose': undefined, 'change': undefined, 'percentage': percentage, 'average': undefined, 'baseVolume': undefined, 'quoteVolume': this.safeString(ticker, 'volume_24h'), 'markPrice': this.safeString(ticker, 'mark_price'), 'info': ticker, }, market); } /** * @method * @name paradex#fetchOrderBook * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @see https://docs.paradex.trade/api/prod/markets/get-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 * @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 = { 'market': market['id'] }; const response = await this.publicGetOrderbookMarket(this.extend(request, params)); // // { // "market": "BTC-USD-PERP", // "seq_no": 14115975, // "last_updated_at": 1718172538340, // "asks": [ // [ // "69578.2", // "3.019" // ] // ], // "bids": [ // [ // "68477.6", // "0.1" // ] // ] // } // if (limit !== undefined) { request['depth'] = limit; } const timestamp = this.safeInteger(response, 'last_updated_at'); const orderbook = this.parseOrderBook(response, market['symbol'], timestamp); orderbook['nonce'] = this.safeInteger(response, 'seq_no'); return orderbook; } /** * @method * @name paradex#fetchTrades * @description get the list of most recent trades for a particular symbol * @see https://docs.paradex.trade/api/prod/trades/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 * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {int} [params.until] the latest time in ms to fetch trades for * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times * @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(); let paginate = false; [paginate, params] = this.handleOptionAndParams(params, 'fetchTrades', 'paginate'); if (paginate) { return await this.fetchPaginatedCallCursor('fetchTrades', symbol, since, limit, params, 'next', 'cursor', undefined, 100); } const market = this.market(symbol); let request = { 'market': market['id'], }; if (limit !== undefined) { request['page_size'] = Math.min(limit, 1000); } if (since !== undefined) { request['start_at'] = since; } [request, params] = this.handleUntilOption('end_at', request, params); const response = await this.publicGetTrades(this.extend(request, params)); // // { // "next": "...", // "prev": "...", // "results": [ // { // "id": "1718154353750201703989430001", // "market": "BTC-USD-PERP", // "side": "BUY", // "size": "0.026", // "price": "69578.2", // "created_at": 1718154353750, // "trade_type": "FILL" // } // ] // } // const trades = this.safeList(response, 'results', []); for (let i = 0; i < trades.length; i++) { trades[i]['next'] = this.safeString(response, 'next'); } return this.parseTrades(trades, market, since, limit); } parseTrade(trade, market = undefined) { // // fetchTrades (public) // // { // "id": "1718154353750201703989430001", // "market": "BTC-USD-PERP", // "side": "BUY", // "size": "0.026", // "price": "69578.2", // "created_at": 1718154353750, // "trade_type": "FILL" // } // // fetchMyTrades (private) // // { // "id": "1718947571560201703986670001", // "side": "BUY", // "liquidity": "TAKER", // "market": "BTC-USD-PERP", // "order_id": "1718947571540201703992340000", // "price": "64852.9", // "size": "0.01", // "fee": "0.1945587", // "fee_currency": "USDC", // "created_at": 1718947571569, // "remaining_size": "0", // "client_id": "", // "fill_type": "FILL" // } // const marketId = this.safeString(trade, 'market'); market = this.safeMarket(marketId, market); const id = this.safeString(trade, 'id'); const timestamp = this.safeInteger(trade, 'created_at'); const priceString = this.safeString(trade, 'price'); const amountString = this.safeString(trade, 'size'); const side = this.safeStringLower(trade, 'side'); const liability = this.safeStringLower(trade, 'liquidity', 'taker'); const isTaker = liability === 'taker'; const takerOrMaker = (isTaker) ? 'taker' : 'maker'; const currencyId = this.safeString(trade, 'fee_currency'); const code = this.safeCurrencyCode(currencyId); return this.safeTrade({