UNPKG

@kraken-crypto/ccxt

Version:

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

1,165 lines (1,162 loc) 110 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var dydx$1 = require('./abstract/dydx.js'); var errors = require('./base/errors.js'); var number = require('./base/functions/number.js'); var Precise = require('./base/Precise.js'); var sha3 = require('./static_dependencies/noble-hashes/sha3.js'); var secp256k1 = require('./static_dependencies/noble-curves/secp256k1.js'); var crypto = require('./base/functions/crypto.js'); // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- /** * @class dydx * @augments Exchange */ class dydx extends dydx$1["default"] { describe() { return this.deepExtend(super.describe(), { 'id': 'dydx', 'name': 'dYdX', 'countries': ['US'], 'rateLimit': 100, 'version': 'v4', 'certified': false, 'dex': true, 'pro': true, 'has': { 'CORS': undefined, 'spot': false, 'margin': false, 'swap': true, 'future': false, 'option': false, 'addMargin': false, 'cancelAllOrders': false, 'cancelAllOrdersAfter': false, 'cancelOrder': true, 'cancelOrders': true, 'cancelWithdraw': false, 'closeAllPositions': 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': true, 'fetchBalance': true, 'fetchCanceledOrders': false, 'fetchClosedOrder': false, 'fetchClosedOrders': true, 'fetchConvertCurrencies': false, 'fetchConvertQuote': false, 'fetchConvertTrade': false, 'fetchConvertTradeHistory': false, 'fetchCurrencies': false, 'fetchDepositAddress': false, 'fetchDepositAddresses': false, 'fetchDepositAddressesByNetwork': false, 'fetchDeposits': true, 'fetchDepositsWithdrawals': true, 'fetchFundingHistory': false, 'fetchFundingInterval': false, 'fetchFundingIntervals': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': true, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchLedger': true, 'fetchLeverage': false, 'fetchMarginAdjustmentHistory': false, 'fetchMarginMode': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': false, 'fetchOHLCV': true, 'fetchOpenInterestHistory': false, 'fetchOpenOrder': false, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchOrderTrades': false, 'fetchPosition': true, 'fetchPositionHistory': false, 'fetchPositionMode': false, 'fetchPositions': true, 'fetchPositionsHistory': false, 'fetchPremiumIndexOHLCV': false, 'fetchStatus': false, 'fetchTicker': false, 'fetchTickers': false, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': false, 'fetchTransactions': false, 'fetchTransfers': true, 'fetchWithdrawals': true, 'reduceMargin': false, 'sandbox': false, 'setLeverage': false, 'setMargin': false, 'setPositionMode': false, 'transfer': true, 'withdraw': true, }, 'timeframes': { '1m': '1MIN', '5m': '5MINS', '15m': '15MINS', '30m': '30MINS', '1h': '1HOUR', '4h': '4HOURS', '1d': '1DAY', }, 'urls': { 'logo': 'https://github.com/user-attachments/assets/617ea0c1-f05a-4d26-9fcb-a0d1d4091ae1', 'api': { 'indexer': 'https://indexer.dydx.trade/v4', 'nodeRpc': 'https://dydx-ops-rpc.kingnodes.com', 'nodeRest': 'https://dydx-rest.publicnode.com', }, 'test': { 'indexer': 'https://indexer.v4testnet.dydx.exchange/v4', 'nodeRpc': 'https://test-dydx-rpc.kingnodes.com', 'nodeRest': 'https://test-dydx-rest.kingnodes.com', }, 'www': 'https://www.dydx.xyz', 'doc': [ 'https://docs.dydx.xyz', ], 'fees': [ 'https://docs.dydx.exchange/introduction-trading_fees', ], 'referral': 'dydx.trade?ref=ccxt', }, 'api': { 'indexer': { 'get': { 'addresses/{address}': 1, 'addresses/{address}/parentSubaccountNumber/{number}': 1, 'addresses/{address}/subaccountNumber/{subaccountNumber}': 1, 'assetPositions': 1, 'assetPositions/parentSubaccountNumber': 1, 'candles/perpetualMarkets/{market}': 1, 'compliance/screen/{address}': 1, 'fills': 1, 'fills/parentSubaccountNumber': 1, 'fundingPayments': 1, 'fundingPayments/parentSubaccount': 1, 'height': 0.1, 'historical-pnl': 1, 'historical-pnl/parentSubaccountNumber': 1, 'historicalBlockTradingRewards/{address}': 1, 'historicalFunding/{market}': 1, 'historicalTradingRewardAggregations/{address}': 1, 'orderbooks/perpetualMarket/{market}': 1, 'orders': 1, 'orders/parentSubaccountNumber': 1, 'orders/{orderId}': 1, 'perpetualMarkets': 1, 'perpetualPositions': 1, 'perpetualPositions/parentSubaccountNumber': 1, 'screen': 1, 'sparklines': 1, 'time': 1, 'trades/perpetualMarket/{market}': 1, 'transfers': 1, 'transfers/between': 1, 'transfers/parentSubaccountNumber': 1, 'vault/v1/megavault/historicalPnl': 1, 'vault/v1/megavault/positions': 1, 'vault/v1/vaults/historicalPnl': 1, // 'perpetualMarketSparklines': 1, 'perpetualMarkets/{ticker}': 1, 'perpetualMarkets/{ticker}/orderbook': 1, 'trades/perpetualMarket/{ticker}': 1, 'historicalFunding/{ticker}': 1, 'candles/{ticker}/{resolution}': 1, 'addresses/{address}/subaccounts': 1, 'addresses/{address}/subaccountNumber/{subaccountNumber}/assetPositions': 1, 'addresses/{address}/subaccountNumber/{subaccountNumber}/perpetualPositions': 1, 'addresses/{address}/subaccountNumber/{subaccountNumber}/orders': 1, 'fills/parentSubaccount': 1, 'historical-pnl/parentSubaccount': 1, }, }, 'nodeRpc': { 'get': { 'abci_info': 1, 'block': 1, 'broadcast_tx_async': 1, 'broadcast_tx_sync': 1, 'tx': 1, }, }, 'nodeRest': { 'get': { 'cosmos/auth/v1beta1/account_info/{dydxAddress}': 1, }, 'post': { 'cosmos/tx/v1beta1/encode': 1, 'cosmos/tx/v1beta1/simulate': 1, }, }, }, 'fees': { 'trading': { 'tierBased': true, 'percentage': true, 'maker': this.parseNumber('0.0001'), 'taker': this.parseNumber('0.0005'), }, }, 'requiredCredentials': { 'apiKey': false, 'secret': false, 'privateKey': false, }, 'options': { 'mnemonic': undefined, 'chainName': 'dydx-mainnet-1', 'chainId': 1, 'sandboxMode': false, 'defaultFeeDenom': 'uusdc', 'defaultFeeMultiplier': '1.6', 'feeDenom': { 'USDC_DENOM': 'ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5', 'USDC_GAS_DENOM': 'uusdc', 'USDC_DECIMALS': 6, 'USDC_GAS_PRICE': '0.025', 'CHAINTOKEN_DENOM': 'adydx', 'CHAINTOKEN_DECIMALS': 18, 'CHAINTOKEN_GAS_PRICE': '25000000000', }, }, 'features': { 'default': { 'sandbox': true, 'createOrder': { 'marginMode': false, 'triggerPrice': true, 'triggerPriceType': { 'last': true, 'mark': true, 'index': false, }, 'triggerDirection': false, 'stopLossPrice': false, 'takeProfitPrice': false, 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': true, 'FOK': true, 'PO': true, 'GTD': true, }, 'hedged': false, 'trailing': false, 'leverage': false, 'marketBuyByCost': false, 'marketBuyRequiresPrice': false, 'selfTradePrevention': false, 'iceberg': false, }, 'createOrders': undefined, 'fetchMyTrades': { 'marginMode': false, 'limit': 500, 'daysBack': 90, 'untilDays': 10000, 'symbolRequired': false, }, 'fetchOrder': { 'marginMode': false, 'trigger': true, 'trailing': false, 'symbolRequired': false, }, 'fetchOpenOrders': { 'marginMode': false, 'limit': 500, 'trigger': true, 'trailing': true, 'symbolRequired': false, }, 'fetchOrders': { 'marginMode': false, 'limit': 500, 'daysBack': undefined, 'untilDays': 100000, 'trigger': true, 'trailing': true, 'symbolRequired': false, }, 'fetchClosedOrders': { 'marginMode': false, 'limit': 500, 'daysBack': undefined, 'daysBackCanceled': undefined, 'untilDays': 100000, 'trigger': true, 'trailing': true, 'symbolRequired': false, }, 'fetchOHLCV': { 'limit': 1000, }, }, 'forSwap': { 'extends': 'default', 'createOrder': { 'hedged': true, }, }, 'swap': { 'linear': { 'extends': 'forSwap', }, 'inverse': undefined, }, 'future': { 'linear': undefined, 'inverse': undefined, }, }, 'commonCurrencies': {}, 'exceptions': { 'exact': { // error collision for clob and sending modules from 2 - 8 // https://github.com/dydxprotocol/v4-chain/blob/5f9f6c9b95cc87d732e23de764909703b81a6e8b/protocol/x/clob/types/errors.go#L320 // https://github.com/dydxprotocol/v4-chain/blob/5f9f6c9b95cc87d732e23de764909703b81a6e8b/protocol/x/sending/types/errors.go '9': errors.InvalidOrder, '10': errors.InvalidOrder, '11': errors.InvalidOrder, '12': errors.InvalidOrder, '13': errors.InvalidOrder, '14': errors.InvalidOrder, '15': errors.InvalidOrder, '16': errors.InvalidOrder, '17': errors.InvalidOrder, '18': errors.InvalidOrder, '19': errors.InvalidOrder, '20': errors.InvalidOrder, '21': errors.InvalidOrder, '22': errors.InvalidOrder, '23': errors.InvalidOrder, '24': errors.InvalidOrder, '25': errors.InvalidOrder, '26': errors.InvalidOrder, '27': errors.InvalidOrder, '28': errors.InvalidOrder, '29': errors.InvalidOrder, '30': errors.InvalidOrder, '31': errors.InvalidOrder, '32': errors.InvalidOrder, '33': errors.InvalidOrder, '34': errors.InvalidOrder, '35': errors.InvalidOrder, '36': errors.InvalidOrder, '37': errors.InvalidOrder, '39': errors.InvalidOrder, '40': errors.InvalidOrder, '41': errors.InvalidOrder, '42': errors.InvalidOrder, '43': errors.InvalidOrder, '44': errors.InvalidOrder, '45': errors.InvalidOrder, '46': errors.InvalidOrder, '47': errors.InvalidOrder, '48': errors.InvalidOrder, '49': errors.InvalidOrder, '50': errors.InvalidOrder, '1000': errors.BadRequest, '1001': errors.BadRequest, '1002': errors.BadRequest, '1003': errors.InvalidOrder, '1004': errors.InvalidOrder, '1005': errors.InvalidOrder, '1006': errors.InvalidOrder, '1007': errors.InvalidOrder, '1008': errors.InvalidOrder, '1009': errors.InvalidOrder, '1010': errors.InvalidOrder, '1011': errors.InvalidOrder, '1012': errors.InvalidOrder, '1013': errors.InvalidOrder, '1014': errors.InvalidOrder, '1015': errors.InvalidOrder, '1017': errors.InvalidOrder, '1018': errors.InvalidOrder, '1019': errors.InvalidOrder, '1020': errors.InvalidOrder, '1021': errors.InvalidOrder, '1022': errors.InvalidOrder, '2000': errors.InvalidOrder, '2001': errors.InvalidOrder, '2002': errors.InvalidOrder, '2003': errors.InvalidOrder, '2004': errors.InvalidOrder, '2005': errors.InvalidOrder, '3000': errors.InvalidOrder, '3001': errors.InvalidOrder, '3002': errors.InvalidOrder, '3003': errors.InvalidOrder, '3004': errors.InvalidOrder, '3005': errors.InvalidOrder, '3006': errors.InvalidOrder, '3007': errors.InvalidOrder, '3008': errors.InvalidOrder, '3009': errors.InvalidOrder, '3010': errors.InvalidOrder, '4000': errors.InvalidOrder, '4001': errors.InvalidOrder, '4002': errors.InvalidOrder, '4003': errors.InvalidOrder, '4004': errors.InvalidOrder, '4005': errors.InvalidOrder, '4006': errors.InvalidOrder, '4007': errors.InvalidOrder, '4008': errors.InvalidOrder, '5000': errors.InvalidOrder, '5001': errors.InvalidOrder, '6000': errors.InvalidOrder, '6001': errors.InvalidOrder, '6002': errors.InvalidOrder, '9000': errors.InvalidOrder, '9001': errors.InvalidOrder, '9002': errors.InvalidOrder, '9003': errors.InvalidOrder, '10000': errors.InvalidOrder, '10001': errors.InvalidOrder, '11000': errors.InvalidOrder, // Invalid order router address }, 'broad': { 'insufficient funds': errors.InsufficientFunds, }, }, 'precisionMode': number.TICK_SIZE, }); } /** * @method * @name dydx#fetchTime * @description fetches the current integer timestamp in milliseconds from the exchange server * @see https://docs.dydx.xyz/indexer-client/http#get-time * @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.indexerGetTime(params); // // { // "iso": "2025-07-20T15:12:13.466Z", // "epoch": 1753024333.466 // } // return this.safeInteger(response, 'epoch'); } parseMarket(market) { // // { // "clobPairId": "0", // "ticker": "BTC-USD", // "status": "ACTIVE", // "oraclePrice": "118976.5376", // "priceChange24H": "659.9736", // "volume24H": "1292729.3605", // "trades24H": 9387, // "nextFundingRate": "0", // "initialMarginFraction": "0.02", // "maintenanceMarginFraction": "0.012", // "openInterest": "52.0691", // "atomicResolution": -10, // "quantumConversionExponent": -9, // "tickSize": "1", // "stepSize": "0.0001", // "stepBaseQuantums": 1000000, // "subticksPerTick": 100000, // "marketType": "CROSS", // "openInterestLowerCap": "0", // "openInterestUpperCap": "0", // "baseOpenInterest": "50.3776", // "defaultFundingRate1H": "0" // } // const quoteId = 'USDC'; const marketId = this.safeString(market, 'ticker'); const parts = marketId.split('-'); const baseName = this.safeString(parts, 0); const base = this.safeCurrencyCode(baseName); const quote = this.safeCurrencyCode(quoteId); const baseId = this.safeString(market, 'baseId'); const settleId = 'USDC'; const settle = this.safeCurrencyCode(settleId); const symbol = base + '/' + quote + ':' + settle; const contract = true; const swap = true; const amountPrecisionStr = this.safeString(market, 'stepSize'); const pricePrecisionStr = this.safeString(market, 'tickSize'); const status = this.safeString(market, 'status'); let active = true; if (status !== 'ACTIVE') { active = false; } return this.safeMarketStructure({ 'id': this.safeString(market, 'ticker'), 'symbol': symbol, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'baseName': baseName, 'quoteId': quoteId, 'settleId': settleId, 'type': 'swap', 'spot': false, 'margin': undefined, 'swap': swap, 'future': false, 'option': false, 'active': active, 'contract': contract, 'linear': true, 'inverse': false, 'taker': undefined, 'maker': undefined, 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.parseNumber(amountPrecisionStr), 'price': this.parseNumber(pricePrecisionStr), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': undefined, 'max': undefined, }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': undefined, 'max': undefined, }, }, 'created': undefined, 'info': market, }); } /** * @method * @name dydx#fetchMarkets * @description retrieves data on all markets for hyperliquid * @see https://docs.dydx.xyz/indexer-client/http#get-perpetual-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 request = { // 'limit': 1000, }; const response = await this.indexerGetPerpetualMarkets(this.extend(request, params)); // // { // "markets": { // "BTC-USD": { // "clobPairId": "0", // "ticker": "BTC-USD", // "status": "ACTIVE", // "oraclePrice": "118976.5376", // "priceChange24H": "659.9736", // "volume24H": "1292729.3605", // "trades24H": 9387, // "nextFundingRate": "0", // "initialMarginFraction": "0.02", // "maintenanceMarginFraction": "0.012", // "openInterest": "52.0691", // "atomicResolution": -10, // "quantumConversionExponent": -9, // "tickSize": "1", // "stepSize": "0.0001", // "stepBaseQuantums": 1000000, // "subticksPerTick": 100000, // "marketType": "CROSS", // "openInterestLowerCap": "0", // "openInterestUpperCap": "0", // "baseOpenInterest": "50.3776", // "defaultFundingRate1H": "0" // } // } // } // const data = this.safeDict(response, 'markets', {}); const markets = Object.values(data); return this.parseMarkets(markets); } parseTrade(trade, market = undefined) { // // { // "id": "02ac5b1f0000000200000002", // "side": "BUY", // "size": "0.0501", // "price": "115732", // "type": "LIMIT", // "createdAt": "2025-07-25T05:11:09.800Z", // "createdAtHeight": "44849951" // } // const timestamp = this.parse8601(this.safeString(trade, 'createdAt')); const symbol = market['symbol']; const price = this.safeString(trade, 'price'); const amount = this.safeString(trade, 'size'); const side = this.safeStringLower(trade, 'side'); const id = this.safeString(trade, 'id'); return this.safeTrade({ 'id': id, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': symbol, 'side': side, 'price': price, 'amount': amount, 'cost': undefined, 'order': undefined, 'takerOrMaker': undefined, 'type': undefined, 'fee': undefined, 'info': trade, }, market); } /** * @method * @name dydx#fetchTrades * @description get the list of most recent trades for a particular symbol * @see https://developer.woox.io/api-reference/endpoint/public_data/marketTrades * @param {string} symbol unified symbol of the market to fetch trades for * @param {int} [since] timestamp in ms of the earliest trade to fetch * @param {int} [limit] the maximum amount of trades to fetch * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades} */ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'market': market['id'], }; if (limit !== undefined) { request['limit'] = limit; } const response = await this.indexerGetTradesPerpetualMarketMarket(this.extend(request, params)); // // { // "trades": [ // { // "id": "02ac5b1f0000000200000002", // "side": "BUY", // "size": "0.0501", // "price": "115732", // "type": "LIMIT", // "createdAt": "2025-07-25T05:11:09.800Z", // "createdAtHeight": "44849951" // } // ] // } // const rows = this.safeList(response, 'trades', []); return this.parseTrades(rows, market, since, limit); } parseOHLCV(ohlcv, market = undefined) { // // { // "startedAt": "2025-07-25T09:47:00.000Z", // "ticker": "BTC-USD", // "resolution": "1MIN", // "low": "116099", // "high": "116099", // "open": "116099", // "close": "116099", // "baseTokenVolume": "0", // "usdVolume": "0", // "trades": 0, // "startingOpenInterest": "54.0594", // "orderbookMidPriceOpen": "115845.5", // "orderbookMidPriceClose": "115845.5" // } // return [ this.parse8601(this.safeString(ohlcv, 'startedAt')), this.safeNumber(ohlcv, 'open'), this.safeNumber(ohlcv, 'high'), this.safeNumber(ohlcv, 'low'), this.safeNumber(ohlcv, 'close'), this.safeNumber(ohlcv, 'baseTokenVolume'), ]; } /** * @method * @name dydx#fetchOHLCV * @see https://docs.dydx.xyz/indexer-client/http#get-candles * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market * @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] the latest time in ms to fetch entries for * @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 = { 'market': market['id'], 'resolution': this.safeString(this.timeframes, timeframe, timeframe), }; if (limit !== undefined) { request['limit'] = Math.min(limit, 1000); } if (since !== undefined) { request['fromIso'] = this.iso8601(since); } const until = this.safeInteger(params, 'until'); params = this.omit(params, 'until'); if (until !== undefined) { request['toIso'] = this.iso8601(until); } const response = await this.indexerGetCandlesPerpetualMarketsMarket(this.extend(request, params)); // // { // "candles": [ // { // "startedAt": "2025-07-25T09:47:00.000Z", // "ticker": "BTC-USD", // "resolution": "1MIN", // "low": "116099", // "high": "116099", // "open": "116099", // "close": "116099", // "baseTokenVolume": "0", // "usdVolume": "0", // "trades": 0, // "startingOpenInterest": "54.0594", // "orderbookMidPriceOpen": "115845.5", // "orderbookMidPriceClose": "115845.5" // } // ] // } // const rows = this.safeList(response, 'candles', []); return this.parseOHLCVs(rows, market, timeframe, since, limit); } /** * @method * @name dydx#fetchFundingRateHistory * @description fetches historical funding rate prices * @see https://docs.dydx.xyz/indexer-client/http#get-historical-funding * @param {string} symbol unified symbol of the market to fetch the funding rate history for * @param {int} [since] timestamp in ms of the earliest funding rate to fetch * @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} to fetch * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {int} [params.until] timestamp in ms of the latest funding rate * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} */ async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) { if (symbol === undefined) { throw new errors.ArgumentsRequired(this.id + ' fetchFundingRateHistory() requires a symbol argument'); } await this.loadMarkets(); const market = this.market(symbol); const request = { 'market': market['id'], }; if (limit !== undefined) { request['limit'] = limit; } const until = this.safeInteger(params, 'until'); if (until !== undefined) { request['effectiveBeforeOrAt'] = this.iso8601(until); } const response = await this.indexerGetHistoricalFundingMarket(this.extend(request, params)); // // { // "historicalFunding": [ // { // "ticker": "BTC-USD", // "rate": "0", // "price": "116302.62419", // "effectiveAtHeight": "44865196", // "effectiveAt": "2025-07-25T11:00:00.013Z" // } // ] // } // const rates = []; const rows = this.safeList(response, 'historicalFunding', []); for (let i = 0; i < rows.length; i++) { const entry = rows[i]; const timestamp = this.parse8601(this.safeString(entry, 'effectiveAt')); const marketId = this.safeString(entry, 'ticker'); rates.push({ 'info': entry, 'symbol': this.safeSymbol(marketId, market), 'fundingRate': this.safeNumber(entry, 'rate'), 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), }); } const sorted = this.sortBy(rates, 'timestamp'); return this.filterBySymbolSinceLimit(sorted, symbol, since, limit); } handlePublicAddress(methodName, params) { let userAux = undefined; [userAux, params] = this.handleOptionAndParams(params, methodName, 'user'); let user = userAux; [user, params] = this.handleOptionAndParams(params, methodName, 'address', userAux); if ((user !== undefined) && (user !== '')) { return [user, params]; } if ((this.walletAddress !== undefined) && (this.walletAddress !== '')) { return [this.walletAddress, params]; } throw new errors.ArgumentsRequired(this.id + ' ' + methodName + '() requires a user parameter inside \'params\' or the walletAddress set'); } parseOrder(order, market = undefined) { // // { // "id": "dad46410-3444-5566-a129-19a619300fb7", // "subaccountId": "8586bcf6-1f58-5ec9-a0bc-e53db273e7b0", // "clientId": "716238006", // "clobPairId": "0", // "side": "BUY", // "size": "0.001", // "totalFilled": "0.001", // "price": "400000", // "type": "LIMIT", // "status": "FILLED", // "timeInForce": "GTT", // "reduceOnly": false, // "orderFlags": "64", // "goodTilBlockTime": "2025-07-28T12:07:33.000Z", // "createdAtHeight": "45058325", // "clientMetadata": "2", // "updatedAt": "2025-07-28T12:06:35.330Z", // "updatedAtHeight": "45058326", // "postOnly": false, // "ticker": "BTC-USD", // "subaccountNumber": 0 // } // const status = this.parseOrderStatus(this.safeStringUpper(order, 'status')); const marketId = this.safeString(order, 'ticker'); const symbol = this.safeSymbol(marketId, market); const filled = this.safeString(order, 'totalFilled'); const timestamp = this.parse8601(this.safeString(order, 'updatedAt')); const price = this.safeString(order, 'price'); const amount = this.safeString(order, 'size'); const type = this.parseOrderType(this.safeStringUpper(order, 'type')); const side = this.safeStringLower(order, 'side'); const timeInForce = this.safeStringUpper(order, 'timeInForce'); return this.safeOrder({ 'info': order, 'id': this.safeString(order, 'id'), 'clientOrderId': this.safeString(order, 'clientId'), 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'lastTradeTimestamp': undefined, 'lastUpdateTimestamp': timestamp, 'symbol': symbol, 'type': type, 'timeInForce': timeInForce, 'postOnly': this.safeBool(order, 'postOnly'), 'reduceOnly': this.safeBool(order, 'reduceOnly'), 'side': side, 'price': price, 'triggerPrice': undefined, 'amount': amount, 'cost': undefined, 'average': undefined, 'filled': filled, 'remaining': undefined, 'status': status, 'fee': undefined, 'trades': undefined, }, market); } parseOrderStatus(status) { const statuses = { 'UNTRIGGERED': 'open', 'OPEN': 'open', 'FILLED': 'closed', 'CANCELED': 'canceled', 'BEST_EFFORT_CANCELED': 'canceling', }; return this.safeString(statuses, status, status); } parseOrderType(type) { const types = { 'LIMIT': 'LIMIT', 'STOP_LIMIT': 'LIMIT', 'TAKE_PROFIT_LIMIT': 'LIMIT', 'MARKET': 'MARKET', 'STOP_MARKET': 'MARKET', 'TAKE_PROFIT_MARKET': 'MARKET', 'TRAILING_STOP': 'MARKET', }; return this.safeStringUpper(types, type, type); } /** * @method * @name dydx#fetchOrder * @description fetches information on an order made by the user * @see https://docs.dydx.xyz/indexer-client/http#get-order * @param {string} id the order id * @param {string} symbol unified symbol of the market the order was made in * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchOrder(id, symbol = undefined, params = {}) { await this.loadMarkets(); const request = { 'orderId': id, }; const order = await this.indexerGetOrdersOrderId(this.extend(request, params)); return this.parseOrder(order); } /** * @method * @name dydx#fetchOrders * @description fetches information on multiple orders made by the user * @see https://docs.dydx.xyz/indexer-client/http#list-orders * @param {string} symbol unified market symbol of the market orders were made in * @param {int} [since] the earliest time in ms to fetch orders for * @param {int} [limit] the maximum number of order structures to retrieve * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.address] wallet address that made trades * @param {string} [params.subAccountNumber] sub account number * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { let userAddress = undefined; let subAccountNumber = undefined; [userAddress, params] = this.handlePublicAddress('fetchOrders', params); [subAccountNumber, params] = this.handleOptionAndParams(params, 'fetchOrders', 'subAccountNumber', '0'); await this.loadMarkets(); const request = { 'address': userAddress, 'subaccountNumber': subAccountNumber, }; let market = undefined; if (symbol !== undefined) { market = this.market(symbol); request['ticker'] = market['id']; } if (limit !== undefined) { request['limit'] = limit; } const response = await this.indexerGetOrders(this.extend(request, params)); // // [ // { // "id": "dad46410-3444-5566-a129-19a619300fb7", // "subaccountId": "8586bcf6-1f58-5ec9-a0bc-e53db273e7b0", // "clientId": "716238006", // "clobPairId": "0", // "side": "BUY", // "size": "0.001", // "totalFilled": "0.001", // "price": "400000", // "type": "LIMIT", // "status": "FILLED", // "timeInForce": "GTT", // "reduceOnly": false, // "orderFlags": "64", // "goodTilBlockTime": "2025-07-28T12:07:33.000Z", // "createdAtHeight": "45058325", // "clientMetadata": "2", // "updatedAt": "2025-07-28T12:06:35.330Z", // "updatedAtHeight": "45058326", // "postOnly": false, // "ticker": "BTC-USD", // "subaccountNumber": 0 // } // ] // return this.parseOrders(response, market, since, limit); } /** * @method * @name dydx#fetchOpenOrders * @description fetch all unfilled currently open orders * @see https://docs.dydx.xyz/indexer-client/http#list-orders * @param {string} symbol unified market symbol of the market orders were made in * @param {int} [since] the earliest time in ms to fetch orders for * @param {int} [limit] the maximum number of order structures to retrieve * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.address] wallet address that made trades * @param {string} [params.subAccountNumber] sub account number * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { const request = { 'status': 'OPEN', // ['OPEN', 'FILLED', 'CANCELED', 'BEST_EFFORT_CANCELED', 'UNTRIGGERED', 'BEST_EFFORT_OPENED'] }; return await this.fetchOrders(symbol, since, limit, this.extend(request, params)); } /** * @method * @name dydx#fetchClosedOrders * @description fetches information on multiple closed orders made by the user * @see https://docs.dydx.xyz/indexer-client/http#list-orders * @param {string} symbol unified market symbol of the market orders were made in * @param {int} [since] the earliest time in ms to fetch orders for * @param {int} [limit] the maximum number of order structures to retrieve * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.address] wallet address that made trades * @param {string} [params.subAccountNumber] sub account number * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { const request = { 'status': 'FILLED', // ['OPEN', 'FILLED', 'CANCELED', 'BEST_EFFORT_CANCELED', 'UNTRIGGERED', 'BEST_EFFORT_OPENED'] }; return await this.fetchOrders(symbol, since, limit, this.extend(request, params)); } parsePosition(position, market = undefined) { // // { // "market": "BTC-USD", // "status": "OPEN", // "side": "SHORT", // "size": "-0.407", // "maxSize": "-0.009", // "entryPrice": "118692.04840909090909090909", // "exitPrice": "119526.565625", // "realizedPnl": "476.42665909090909090909088", // "unrealizedPnl": "-57.26681734000000000000037", // "createdAt": "2025-07-14T07:53:55.631Z", // "createdAtHeight": "44140908", // "closedAt": null, // "sumOpen": "0.44", // "sumClose": "0.032", // "netFunding": "503.13121", // "subaccountNumber": 0 // } // const marketId = this.safeString(position, 'market'); market = this.safeMarket(marketId, market); const symbol = market['symbol']; const side = this.safeStringLower(position, 'side'); let quantity = this.safeString(position, 'size'); if (side !== 'long') { quantity = Precise["default"].stringMul('-1', quantity); } const timestamp = this.parse8601(this.safeString(position, 'createdAt')); return this.safePosition({ 'info': position, 'id': undefined, 'symbol': symbol, 'entryPrice': this.safeNumber(position, 'entryPrice'), 'markPrice': undefined, 'notional': undefined, 'collateral': undefined, 'unrealizedPnl': this.safeNumber(position, 'unrealizedPnl'), 'side': side, 'contracts': this.parseNumber(quantity), 'contractSize': undefined, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'hedged': undefined, 'maintenanceMargin': undefined, 'maintenanceMarginPercentage': undefined, 'initialMargin': undefined, 'initialMarginPercentage': undefined, 'leverage': undefined, 'liquidationPrice': undefined, 'marginRatio': undefined, 'marginMode': undefined, 'percentage': undefined, }); } /** * @method * @name dydx#fetchPosition * @description fetch data on an open position * @see https://docs.dydx.xyz/indexer-client/http#list-positions * @param {string} symbol unified market symbol of the market the position is held in * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.address] wallet address that made trades * @param {string} [params.subAccountNumber] sub account number * @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure} */ async fetchPosition(symbol, params = {}) { const positions = await this.fetchPositions([symbol], params); return this.safeDict(positions, 0, {}); } /** * @method * @name dydx#fetchPositions * @description fetch all open positions * @see https://docs.dydx.xyz/indexer-client/http#list-positions * @param {string[]} [symbols] list of unified market symbols * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.address] wallet address that made trades * @param {string} [params.subAccountNumber] sub account number * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure} */ async fetchPositions(symbols = undefined, params = {}) { let userAddress = undefined; let subAccountNumber = undefined; [userAddress, params] = this.handlePublicAddress('fetchPositions', params); [subAccountNumber, params] = this.handleOptionAndParams(params, 'fetchOrders', 'subAccountNumber', '0'); await this.loadMarkets(); const request = { 'address': userAddress, 'subaccountNumber': subAccountNumber, 'status': 'OPEN', // ['OPEN', 'CLOSED', 'LIQUIDATED'] }; const response = await this.indexerGetPerpetualPositions(this.extend(request, params)); // // { // "positions": [ // { // "market": "BTC-USD", // "status": "OPEN", // "side": "SHORT", // "size": "-0.407", // "maxSize": "-0.009", // "entryPrice": "118692.04840909090909090909", // "exitPrice": "119526.565625", // "realizedPnl": "476.42665909090909090909088", // "unrealizedPnl": "-57.26681734000000000000037", // "createdAt": "2025-07-14T07:53:55.631Z", // "createdAtHeight": "44140908", // "closedAt": null, // "sumOpen": "0.44", // "sumClose": "0.032", // "netFunding": "503.13121", // "suba