@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
JavaScript
'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