UNPKG

ccxt

Version:

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

1,224 lines • 140 kB
// --------------------------------------------------------------------------- import Exchange from './abstract/pacifica.js'; import { ExchangeError, ArgumentsRequired, InvalidOrder, OrderNotFound, BadRequest, InsufficientFunds, PermissionDenied, RateLimitExceeded, ExchangeNotAvailable, RequestTimeout, NotSupported } from './base/errors.js'; import { Precise } from './base/Precise.js'; import { TICK_SIZE } from './base/functions/number.js'; import { eddsa } from './base/functions/crypto.js'; import { ed25519 } from './static_dependencies/noble-curves/ed25519.js'; // --------------------------------------------------------------------------- /** * @class pacifica * @augments Exchange */ export default class pacifica extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'pacifica', 'name': 'Pacifica', 'countries': [], 'version': 'v1', 'isSandboxModeEnabled': false, 'rateLimit': 50, 'certified': false, 'pro': true, 'dex': true, 'has': { 'CORS': undefined, 'spot': false, 'margin': false, 'swap': true, 'future': true, 'option': false, 'addMargin': false, 'borrowCrossMargin': false, 'borrowIsolatedMargin': false, 'cancelAllOrders': true, 'cancelAllOrdersAfter': false, 'cancelOrder': true, 'cancelOrders': true, 'cancelOrdersForSymbols': undefined, 'closeAllPositions': false, 'closePosition': false, 'createMarketBuyOrderWithCost': false, 'createMarketOrderWithCost': false, 'createMarketSellOrderWithCost': false, 'createOrder': true, 'createOrders': true, 'createOrderWithTakeProfitAndStopLoss': true, 'createReduceOnlyOrder': true, 'createStopOrder': true, 'editOrder': true, 'editOrders': false, 'fetchAccounts': true, 'fetchBalance': true, 'fetchBorrowInterest': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchCanceledAndClosedOrders': true, 'fetchCanceledOrders': true, 'fetchClosedOrders': true, 'fetchCrossBorrowRate': false, 'fetchCrossBorrowRates': false, 'fetchCurrencies': false, 'fetchDepositAddress': false, 'fetchDepositAddresses': false, 'fetchDeposits': false, 'fetchDepositWithdrawFee': 'emulated', 'fetchDepositWithdrawFees': false, 'fetchFundingHistory': true, 'fetchFundingRate': false, 'fetchFundingRateHistory': true, 'fetchFundingRates': true, 'fetchIndexOHLCV': false, 'fetchIsolatedBorrowRate': false, 'fetchIsolatedBorrowRates': false, 'fetchLedger': true, 'fetchLeverage': true, 'fetchLeverageTiers': false, 'fetchLiquidations': false, 'fetchMarginMode': true, 'fetchMarketLeverageTiers': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyLiquidations': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenInterest': true, 'fetchOpenInterestHistory': false, 'fetchOpenInterests': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchOrderTrades': false, 'fetchPosition': true, 'fetchPositionMode': false, 'fetchPositions': true, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchStatus': undefined, 'fetchTicker': 'emulated', 'fetchTickers': true, 'fetchTime': undefined, 'fetchTrades': true, 'fetchTradingFee': true, 'fetchTradingFees': false, 'fetchTransfer': false, 'fetchTransfers': false, 'fetchWithdrawal': false, 'fetchWithdrawals': false, 'reduceMargin': false, 'repayCrossMargin': false, 'repayIsolatedMargin': false, 'sandbox': true, 'setLeverage': true, 'setMarginMode': true, 'setPositionMode': false, 'transfer': true, 'withdraw': true, }, 'timeframes': { '1m': '1m', '3m': '3m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '1h', '2h': '2h', '4h': '4h', '8h': '8h', '12h': '12h', '1d': '1d', }, 'hostname': 'pacifica.fi', 'urls': { 'logo': 'https://github.com/user-attachments/assets/f795515a-828e-4a04-8fca-bf19fcf17ea4', 'api': { 'public': 'https://api.{hostname}', 'private': 'https://api.{hostname}', }, 'test': { 'public': 'https://test-api.{hostname}', 'private': 'https://test-api.{hostname}', }, 'www': 'https://www.pacifica.fi', 'doc': 'https://docs.pacifica.fi/api-documentation/api/rest-api', 'fees': 'https://docs.pacifica.fi/trading-on-pacifica/trading-fees', 'referral': 'https://app.pacifica.fi?referral=ccxt', }, 'api': { 'public': { 'get': { // ~12 weight depends on the limit 3 max for api-key, but min without api-key 'info': 1, 'info/prices': 1, 'kline': 12, 'kline/mark': 12, 'book': 1, 'trades': 1, 'funding_rate/history': 1, 'account': 1, 'account/settings': 1, 'positions': 1, 'trades/history': 12, 'funding/history': 1, 'portfolio': 1, 'account/balance/history': 12, 'orders': 1, 'orders/history': 12, 'orders/history_by_id': 1, 'account/builder_codes/approvals': 1, }, }, 'private': { 'post': { 'account/leverage': 1, 'account/margin': 1, 'account/withdraw': 1, 'account/subaccount/create': 1, 'account/subaccount/list': 1, 'account/subaccount/transfer': 1, 'orders/create': 1, 'orders/create_market': 1, 'orders/stop/create': 1, 'positions/tpsl': 1, 'orders/cancel': 0.5, 'orders/cancel_all': 0.5, 'orders/stop/cancel': 0.5, 'orders/edit': 1, 'orders/batch': 1, 'account/builder_codes/approve': 1, 'account/builder_codes/revoke': 1, 'agent/bind': 1, 'account/api_keys/create': 1, 'account/api_keys/revoke': 1, 'account/api_keys': 1, }, }, }, 'fees': { 'swap': { 'taker': this.parseNumber('0.0004'), 'maker': this.parseNumber('0.00015'), }, }, // // Reminder: // If you're using an agent wallet, its private key must also be in the privateKey field in requiredCredentials. // However, walletAddress must ALWAYS be equal to the main address. For the agent wallet address, there's a field in options: agentAddress // 'requiredCredentials': { 'apiKey': false, 'secret': false, 'walletAddress': false, 'privateKey': true, // base58 solana private key }, 'exceptions': { 'exact': { '400': BadRequest, '403': PermissionDenied, '404': BadRequest, '409': ExchangeError, '422': ExchangeError, '429': RateLimitExceeded, '500': ExchangeError, '503': ExchangeNotAvailable, '504': RequestTimeout, }, 'broad': { 'UNKNOWN': ExchangeError, 'ACCOUNT_NOT_FOUND': ExchangeError, 'BOOK_NOT_FOUND': ExchangeError, 'INVALID_TICK_LEVEL': InvalidOrder, 'INSUFFICIENT_BALANCE': InsufficientFunds, 'ORDER_NOT_FOUND': OrderNotFound, 'OVER_WITHDRAWAL': InsufficientFunds, 'INVALID_LEVERAGE': ExchangeError, 'CANNOT_UPDATE_MARGIN': ExchangeError, 'POSITION_NOT_FOUND': ExchangeError, 'POSITION_TPSL_LIMIT_EXCEEDED': InvalidOrder, }, }, 'precisionMode': TICK_SIZE, 'commonCurrencies': {}, 'options': { 'agentAddress': undefined, 'apiKey': undefined, 'builderCode': 'CCXT', 'feeRate': '0.01', 'builderFee': true, 'batchOrdersMax': 10, 'defaultType': 'swap', 'defaultSlippage': '0.5', 'expiryWindow': 5000, 'maxCostHugeWithApiKey': 3, 'marketHelperProps': [], 'defaultMarginMode': 'cross', 'builderSupportOperations': { 'create_market_order': true, 'create_limit_order': true, 'create_stop_order': true, 'set_position_tpsl': true, }, }, 'features': { 'default': { 'sandbox': true, 'createOrder': { 'marginMode': false, 'triggerPrice': false, 'triggerPriceType': undefined, 'triggerDirection': false, 'stopLossPrice': false, 'takeProfitPrice': false, 'attachedStopLossTakeProfit': { 'triggerPriceType': { 'last': false, 'mark': false, 'index': false, }, 'triggerPrice': true, 'type': true, 'price': true, }, 'timeInForce': { 'IOC': true, 'FOK': false, 'PO': true, 'GTD': false, }, 'hedged': false, 'trailing': false, 'leverage': false, 'marketBuyByCost': false, 'marketBuyRequiresPrice': false, 'selfTradePrevention': false, 'iceberg': false, }, 'createOrders': { 'max': 10, }, 'editOrder': { 'side': false, 'type': false, }, 'fetchMyTrades': { 'marginMode': false, 'limit': 100, 'daysBack': undefined, 'untilDays': undefined, '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': undefined, 'untilDays': undefined, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchClosedOrders': { 'marginMode': false, 'limit': 100, 'daysBack': undefined, 'daysBackCanceled': undefined, 'untilDays': undefined, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOHLCV': { 'limit': 3950, }, 'fetchLedger': { 'code': false, }, }, 'forPerps': { 'extends': 'default', 'createOrder': { 'stopLossPrice': true, 'takeProfitPrice': true, 'attachedStopLossTakeProfit': undefined, }, }, 'spot': undefined, 'swap': { 'linear': { 'extends': 'forPerps', }, 'inverse': { 'extends': 'forPerps', }, }, 'future': { 'linear': { 'extends': 'forPerps', }, 'inverse': { 'extends': 'forPerps', }, }, }, }); } async initializeClient() { try { await this.handleBuilderFeeApproval(); } catch (e) { return false; } return true; } async handleBuilderFeeApproval() { if (this.isSandboxModeEnabled) { // At this stage, building codes are mostly only on the mainnet. return false; } const buildFee = this.safeBool(this.options, 'builderFee', true); if (!buildFee) { return false; // skip if builder fee is not enabled } const approvedBuilderFee = this.safeBool(this.options, 'approvedBuilderFee', false); if (approvedBuilderFee) { return true; // skip if builder fee is already approved } try { const builder = this.safeString(this.options, 'builderCode', 'CCXT'); // case sensitive const maxFeeRate = this.safeString(this.options, 'feeRate', '0.01'); await this.approveBuilderCode(builder, maxFeeRate); this.options['approvedBuilderFee'] = true; } catch (e) { this.options['builderFee'] = false; // disable builder fee if an error occurs } return true; } /** * @method * @name pacifica#fetchMarkets * @description retrieves data on all markets for pacifica * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} an array of objects representing market data */ async fetchMarkets(params = {}) { if (this.checkRequiredCredentials(false)) { await this.initializeClient(); await this.loadAccountSettings(); } const swapMarkets = await this.fetchSwapMarkets(params); return swapMarkets; } /** * @method * @name pacifica#fetchSwapMarkets * @description retrieves data on all swap markets for pacifica * @see https://docs.pacifica.fi/api-documentation/api/rest-api/markets/get-market-info * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} an array of objects representing market data */ async fetchSwapMarkets(params = {}) { const response = await this.publicGetInfo(params); // meta // { // "success": true, // "data": [ // { // "symbol": "ETH", // "tick_size": "0.1", // "min_tick": "0", // "max_tick": "1000000", // "lot_size": "0.0001", // "max_leverage": 50, // "isolated_only": false, // "min_order_size": "10", // "max_order_size": "5000000", // "funding_rate": "0.0000125", // "next_funding_rate": "0.0000125", // "created_at": 1748881333944 // }, // { // "symbol": "BTC", // "tick_size": "1", // "min_tick": "0", // "max_tick": "1000000", // "lot_size": "0.00001", // "max_leverage": 50, // "isolated_only": false, // "min_order_size": "10", // "max_order_size": "5000000", // "funding_rate": "0.0000125", // "next_funding_rate": "0.0000125", // "created_at": 1748881333944 // }, // .... // ], // "error": null, // "code": null // } const meta = this.safeList(response, 'data', []); const results = []; for (let i = 0; i < meta.length; i++) { results.push(meta[i]); } return this.parseMarkets(results); } parseMarket(market) { // { // "symbol": "ETH", // "tick_size": "0.1", // "min_tick": "0", // "max_tick": "1000000", // "lot_size": "0.0001", // "max_leverage": 50, // "isolated_only": false, // "min_order_size": "10", // "max_order_size": "5000000", // "funding_rate": "0.0000125", // "next_funding_rate": "0.0000125", // "created_at": 1748881333944 // }, // { // "symbol": "BTC", // "tick_size": "1", // "min_tick": "0", // "max_tick": "1000000", // "lot_size": "0.00001", // "max_leverage": 50, // "isolated_only": false, // "min_order_size": "10", // "max_order_size": "5000000", // "funding_rate": "0.0000125", // "next_funding_rate": "0.0000125", // "created_at": 1748881333944 // }, const quoteId = 'usdc'; const settleId = 'usdc'; const id = this.safeString(market, 'symbol'); const baseId = id.toLowerCase(); const baseName = id.toUpperCase(); const base = this.safeCurrencyCode(baseName); const quote = this.safeCurrencyCode(quoteId); const settle = this.safeCurrencyCode(settleId); let symbol = base + '/' + quote; const contract = true; const swap = true; if (contract) { if (swap) { symbol = symbol + ':' + settle; } } const fees = this.safeDict(this.fees, 'swap', {}); const taker = this.safeNumber(fees, 'taker'); const maker = this.safeNumber(fees, 'maker'); const amountPrecisionStr = this.safeString(market, 'lot_size'); const pricePrecisionStr = this.safeString(market, 'tick_size'); const active = true; // there is no non-active markets comes from endpoint market info return this.safeMarketStructure({ 'id': id, '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': taker, 'maker': maker, 'contractSize': this.parseNumber('1'), 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.parseNumber(amountPrecisionStr), 'price': this.parseNumber(pricePrecisionStr), }, 'limits': { 'leverage': { 'min': 1, 'max': this.safeInteger(market, 'max_leverage'), }, 'amount': { 'min': undefined, 'max': undefined, }, 'price': { 'min': this.safeString(market, 'min_tick'), 'max': this.safeString(market, 'max_tick'), }, 'cost': { 'min': undefined, 'max': undefined, }, }, 'created': undefined, 'marginModes': { 'cross': true, 'isolated': true }, 'info': market, }); } /** * @method * @name pacifica#fetchBalance * @description query for balance and get the amount of funds available for trading or funds locked in orders * @see https://docs.pacifica.fi/api-documentation/api/rest-api/account/get-account-info * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.account] will default to walletAddress if not provided * @returns {object} a [balance structure]{@link https://docs.ccxt.com/?id=balance-structure} */ async fetchBalance(params = {}) { let userAccount = undefined; [userAccount, params] = this.handleOriginAndSingleAddress('fetchBalance', params); const request = { 'account': userAccount, }; const response = await this.publicGetAccount(this.extend(request, params)); // { // "success": true, // "data": { // "balance": "2000.000000", // "fee_level": 0, // "maker_fee": "0.00015", // "taker_fee": "0.0004", // "account_equity": "2150.250000", // "available_to_spend": "1800.750000", // "available_to_withdraw": "1500.850000", // "pending_balance": "0.000000", // "total_margin_used": "349.500000", // "cross_mmr": "420.690000", // "positions_count": 2, // "orders_count": 3, // "stop_orders_count": 1, // "updated_at": 1716200000000, // "use_ltp_for_stop_orders": false // }, // "error": null, // "code": null // } const data = this.safeDict(response, 'data', {}); const result = { 'info': data, }; result['free'] = {}; result['used'] = {}; result['total'] = {}; const totalBalance = this.safeNumber(data, 'account_equity'); const usedMargin = this.safeNumber(data, 'total_margin_used'); const freeBalance = this.safeNumber(data, 'available_to_spend'); result['total']['USDC'] = totalBalance; result['used']['USDC'] = usedMargin; result['free']['USDC'] = freeBalance; const timestamp = this.safeInteger(data, 'updated_at'); result['timestamp'] = timestamp; result['datetime'] = this.iso8601(timestamp); return this.safeBalance(result); } /** * @method * @name pacifica#fetchLeverage * @description fetch the set leverage for a market * @param {string} symbol unified symbol of the market * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.account] will default to walletAddress if not provided * @returns {object} a [leverage structure]{@link https://docs.ccxt.com/?id=leverage-structure} */ async fetchLeverage(symbol, params = {}) { await this.loadAccountSettings(); await this.loadMarkets(); const market = this.market(symbol); let userAccount = undefined; [userAccount, params] = this.handleOriginAndSingleAddress('fetchLeverage', params); const cacheAddress = this.walletAddress; let settings = undefined; if (userAccount === cacheAddress) { settings = this.handleOption('fetchLeverage', 'settings', undefined); } else { const request = { 'account': userAccount, }; settings = await this.fetchAccountSettings(this.extend(request, params)); } const setting = this.safeDict(settings, symbol, undefined); if (setting === undefined) { // NOTE: Upon account creation, all markets have margin settings default to cross margin and leverage default to max. // When querying this endpoint, all markets with default margin and leverage settings on this account will return blank. return this.parseLeverageFromMarket(market); } else { return this.parseLeverageFromSetting(symbol, setting); } } parseLeverageFromSetting(symbol, setting) { // { // "WLFI/USDC:USDC": { // "symbol": "WLFI", // "isolated": false, // "leverage": 5, // "created_at": 1758085929703, // "updated_at": 1758086074002 // }, // } const isIsolated = this.safeBool(setting, 'isolated', false); const leverage = this.safeInteger(setting, 'leverage'); const marginMode = isIsolated ? 'isolated' : 'cross'; return { 'info': setting, 'symbol': symbol, 'marginMode': marginMode, 'longLeverage': leverage, 'shortLeverage': leverage, }; } parseLeverageFromMarket(market) { const marketLimits = this.safeDict(market, 'limits', {}); const leverageLimits = this.safeDict(marketLimits, 'leverage', {}); return { 'info': market, 'symbol': this.safeString(market, 'symbol'), 'marginMode': this.handleOption('fetchLeverage', 'defaultMarginMode', 'cross'), 'longLeverage': this.safeInteger(leverageLimits, 'max'), 'shortLeverage': this.safeInteger(leverageLimits, 'max'), }; } /** * @method * @name pacifica#fetchAccountSettings * @description fetch account's market settings. Settings are cached for walletAddress. To refresh the cache, call loadAccountSettings with refresh=true * @see https://docs.pacifica.fi/api-documentation/api/rest-api/account/get-account-settings * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.account] will default to walletAddress if not provided * @returns {object} Dict repacked from list by symbol key */ async fetchAccountSettings(params = {}) { let userAccount = undefined; [userAccount, params] = this.handleOriginAndSingleAddress('fetchAccountSettings', params); const request = { 'account': userAccount, }; const response = await this.publicGetAccountSettings(this.extend(request, params)); // { // "success": true, // "data": [ // { // "symbol": "WLFI", // "isolated": false, // "leverage": 5, // "created_at": 1758085929703, // "updated_at": 1758086074002 // } // ], // "error": null, // "code": null // } return this.parseAccountSettings(this.safeList(response, 'data', [])); } async loadAccountSettings(refresh = false, params = {}) { let settings = this.handleOption('loadAccountSettings', 'settings', undefined); if ((settings === undefined) || (refresh === true)) { this.options['settings'] = this.createSafeDictionary(); settings = await this.fetchAccountSettings(params); this.options['settings'] = settings; } } parseAccountSettings(settings) { const settingsLen = settings.length; if (settingsLen === 0) { return {}; } const settingsBySymbol = {}; for (let i = 0; i < settings.length; i++) { const marketId = settings[i]['symbol']; const market = this.safeMarket(marketId); const symbol = market['symbol']; settingsBySymbol[symbol] = settings[i]; } return settingsBySymbol; } /** * @method * @name pacifica#fetchMarginMode * @description fetches the margin mode of the trading pair * @param {string} symbol unified symbol of the market to fetch the margin mode for * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.account] will default to walletAddress if not provided * @returns {object} a [margin mode structure]{@link https://docs.ccxt.com/?id=margin-mode-structure} */ async fetchMarginMode(symbol, params = {}) { await this.loadAccountSettings(); let userAccount = undefined; [userAccount, params] = this.handleOriginAndSingleAddress('fetchMarginMode', params); const cacheAddress = this.walletAddress; let settings = undefined; if (userAccount === cacheAddress) { settings = this.handleOption('fetchMarginMode', 'settings', undefined); } else { const request = { 'account': userAccount, }; settings = await this.fetchAccountSettings(this.extend(request, params)); } // { // "WLFI/USDC:USDC": { // "symbol": "WLFI", // "isolated": false, // "leverage": 5, // "created_at": 1758085929703, // "updated_at": 1758086074002 // }, // } const setting = this.safeDict(settings, symbol, undefined); if (setting === undefined) { // NOTE: Upon account creation, all markets have margin settings default to cross margin and leverage default to max. // When querying this endpoint, all markets with default margin and leverage settings on this account will return blank. return { 'symbol': symbol, 'marginMode': this.handleOption('fetchMarginMode', 'defaultMarginMode', 'cross'), }; } else { return this.parseMarginModeFromSetting(symbol, setting); } } parseMarginModeFromSetting(symbol, setting) { // { // "symbol": "WLFI", // "isolated": false, // "leverage": 5, // "created_at": 1758085929703, // "updated_at": 1758086074002 // // } const isIsolated = this.safeBool(setting, 'isolated', false); const marginMode = isIsolated ? 'isolated' : 'cross'; return { 'symbol': symbol, 'marginMode': marginMode, 'info': setting, }; } /** * @method * @name pacifica#fetchOrderBook * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @see https://docs.pacifica.fi/api-documentation/api/rest-api/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 * @param {int} [params.aggLevel] aggregation level for price grouping. Defaults to 1. Can be 1, 10, 100, 1000, 10000 * @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); let aggLevel = undefined; [aggLevel, params] = this.handleOptionAndParams(params, 'fetchOrderBook', 'aggLevel', 1); const request = { 'symbol': market['id'], 'agg_level': aggLevel, }; const response = await this.publicGetBook(this.extend(request, params)); // { // "success": true, // "data": { // "s": "BTC", // "l": [ // [ // { // "p": "106504", // "a": "0.26203", // "n": 1 // }, // { // "p": "106498", // "a": "0.29281", // "n": 1 // } // ], // [ // { // "p": "106559", // "a": "0.26802", // "n": 1 // }, // { // "p": "106564", // "a": "0.3002", // "n": 1 // }, // ] // ], // "t": 1751370536325 // }, // "error": null, // "code": null // } const data = this.safeDict(response, 'data', {}); const levels = this.safeList(data, 'l', []); const result = { 'bids': this.safeList(levels, 0, []), 'asks': this.safeList(levels, 1, []), }; const timestamp = this.safeInteger(data, 't'); return this.parseOrderBook(result, this.safeSymbol(undefined, market), timestamp, 'bids', 'asks', 'p', 'a'); } /** * @method * @name pacifica#fetchFundingRates * @description retrieves data on all swap markets for pacifica * @param {string[]} [symbols] list of unified market symbols * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} an array of objects representing market data */ async fetchFundingRates(symbols = undefined, params = {}) { const response = await this.publicGetInfoPrices(params); // // { // "success": true, // "data": [ // { // "funding": "0.00010529", // "mark": "1.084819", // "mid": "1.08615", // "next_funding": "0.00011096", // "open_interest": "3634796", // "oracle": "1.084524", // "symbol": "XPL", // "timestamp": 1759222967974, // "volume_24h": "20896698.0672", // "yesterday_price": "1.3412" // } // ], // "error": null, // "code": null // } // const result = this.safeList(response, 'data', []); return this.parseFundingRates(result, symbols); } parseFundingRate(info, market = undefined) { // // { // "funding": "0.00010529", // "mark": "1.084819", // "mid": "1.08615", // "next_funding": "0.00011096", // "open_interest": "3634796", // "oracle": "1.084524", // "symbol": "XPL", // "timestamp": 1759222967974, // "volume_24h": "20896698.0672", // "yesterday_price": "1.3412" // } // const marketId = this.safeString(info, 'symbol'); market = this.safeMarket(marketId, market); const symbol = market['symbol']; const funding = this.safeNumber(info, 'funding'); const markPx = this.safeNumber(info, 'mark'); const oraclePx = this.safeNumber(info, 'oracle'); const nextFundingRate = this.safeNumber(info, 'next_funding'); const timestamp = this.safeInteger(info, 'timestamp'); const fundingTimestamp = (Math.floor(this.milliseconds() / 60 / 60 / 1000) + 1) * 60 * 60 * 1000; return { 'info': info, 'symbol': symbol, 'markPrice': markPx, 'indexPrice': oraclePx, 'interestRate': undefined, 'estimatedSettlePrice': undefined, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'fundingRate': funding, 'fundingTimestamp': fundingTimestamp, 'fundingDatetime': this.iso8601(fundingTimestamp), 'nextFundingRate': nextFundingRate, 'nextFundingTimestamp': undefined, 'nextFundingDatetime': undefined, 'previousFundingRate': undefined, 'previousFundingTimestamp': undefined, 'previousFundingDatetime': undefined, 'interval': '1h', }; } /** * @method * @name pacifica#fetchOHLCV * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market * @see https://docs.pacifica.fi/api-documentation/api/rest-api/markets/get-candle-data * @param {string} symbol unified symbol of the market to fetch OHLCV data for * @param {string} timeframe the length of time each candle represents, support '1m', '3m', '5m', '15m', '30m', '1h', '2h', '4h', '8h', '12h', '1d' * @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. 'limit' is priority * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume */ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { if (since === undefined) { throw new ArgumentsRequired(this.id + ' fetchOHLCV() requires a "since" argument'); } if (symbol === undefined) { throw new ArgumentsRequired(this.id + ' fetchOHLCV() requires a "symbol" argument'); } const defaultMaxLimit = 3950; // 4000 by docs, but in fact >~3960 returns error await this.loadMarkets(); const market = this.market(symbol); let paginate = false; [paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate', false); if (paginate) { return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, defaultMaxLimit); } const tf = this.safeString(this.timeframes, timeframe, timeframe); let request = { 'symbol': market['id'], 'interval': tf, 'start_time': since, }; [request, params] = this.handleUntilOption('end_time', request, params); const nowMillis = this.milliseconds(); let until = this.safeInteger(request, 'end_time'); if (until === undefined) { if (limit !== undefined) { until = since + (limit * (this.parseTimeframe(tf) * 1000)) - 1; } if (until === undefined) { until = since + (defaultMaxLimit * (this.parseTimeframe(tf) * 1000)) - 1; } if (until > nowMillis) { until = nowMillis; } request['end_time'] = until; } const response = await this.publicGetKline(this.extend(request, params)); // // { // "success": true, // "data": [ // { // "t": 1748954160000, // "T": 1748954220000, // "s": "BTC", // "i": "1m", // "o": "105376", // "c": "105376", // "h": "105376", // "l": "105376", // "v": "0.00022", // "n": 2 // } // ], // "error": null, // "code": null // } // const candles = this.safeList(response, 'data', []); return this.parseOHLCVs(candles, market, timeframe, since, limit); } parseOHLCV(ohlcv, market = undefined) { // // { // "t": 1748954160000, // "T": 1748954220000, // "s": "BTC", // "i": "1m", // "o": "105376", // "c": "105376", // "h": "105376", // "l": "105376", // "v": "0.00022", // "n": 2 // } // return [ this.safeInteger(ohlcv, 't'), this.safeNumber(ohlcv, 'o'), this.safeNumber(ohlcv, 'h'), this.safeNumber(ohlcv, 'l'), this.safeNumber(ohlcv, 'c'), this.safeNumber(ohlcv, 'v'), ]; } /** * @method * @name pacifica#fetchTrades * @description get the list of most recent trades for a particular symbol * @see https://docs.pacifica.fi/api-documentation/api/rest-api/markets/get-recent-trades * @param {string} symbol unified market symbol * @param {int} [since] the earliest time in ms to fetch trades for * @param {int} [limit] the maximum number of trades structures to retrieve * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=trade-structure} */ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], }; const response = await this.publicGetTrades(this.extend(request, params)); // // { // "success": true, // "data": [ // { // "event_type": "fulfill_taker", // "price": "104721", // "amount": "0.0001", // "side": "close_long", // "cause": "normal", // "created_at": 1765006315306 // } // ], // "error": null, // "code": null, // "last_order_id": 1557404170 // } // const recentTrades = this.safeList(response, 'data', []); return this.parseTrades(recentTrades, market, since, limit); } /** * @method * @name pacifica#fetchMyTrades * @description fetch all trades made by the user * @see https://docs.pacifica.fi/api-documentation/api/rest-api/account/get-trade-history * @param {string} [symbol] unified market symbol * @param {int} [since] the earliest time in ms to fetch trades for * @param {int} [limit] the maximum number of trades structures to retrieve * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {int} [params.until] timestamp in ms of the latest trade * @param {string} [params.account] will default to walletAddress if not provided * @param {string} [params.cursor] pagination cursor from prev request (manual use) * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=trade-structure} */ async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); let market = undefined; if (symbol !== undefined) { market = this.market(symbol); } let paginate = false; [paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate', false); let userAddress = undefined; [userAddress, params] = this.handleOriginAndSingleAddress('fetchMyTrades', params); const defaultLimit = 100; // Default max limit if (paginate) { return await this.fetchPaginatedCallCursor('fetchMyTrades', symbol, since, limit, params, 'next_cursor', 'cursor', undefined, defaultLimit); } let request = {}; [request, params] = this.handleUntilOption('end_time', request, params); request['account'] = userAddress; if (symbol !== undefined) { request['symbol'] = market['id']; } if (limit !== undefined) { request['limit'] = limit; } if (since !== undefined) { request['start_time'] = since; } const response = await this.publicGetTradesHistory(this.extend(request, params)); // // { // "success": true, // "data": [ // { // "history_id": 19329801, // "order_id": 315293920, // "client_order_id": "acf...", // "symbol": "LDO", // "amount": "0.1", // "price": "1.1904", // "entry_price": "1.176247", // "fee": "0", // "pnl": "-0.001415", // "event_type": "fulfill_maker", // "side": "close_short", // "created_at": 1759215599188, // "cause": "normal" // }, // ... // ], // "next_cursor": "11111Z5RK", // not included to info! // "has_more": true // not included to info! // } // const data = this.addPaginationCursorToResult(response); return this.parseTrades(data, market, since, limit); } parseTrade(trade, market = undefined) { // // user trades: // { // "history_id": 19329801, // "order_id": 315293920, // "client_order_id": "acf...", // "symbol": "LDO", // "amount": "0.1", // "price": "1.1904", // "entry_price": "1.176247", // "fee": "0", // "pnl": "-0.001415", // "event_type": "fulfill_maker", // "side": "close_short", // "created_at": 1759215599188, // "cause": "normal" // }, // recent public trades: // { // "event_type": "fulfill_taker", // "price": "104721", // "amount": "0.0001", // "side": "close_long", // "cause": "normal", // "created_at": 1765006315306 // } // const eventType = this.safeString(trade, 'event_type'); const timestamp = this.safeInteger(trade, 'created_at'); const price = this.safeString(trade, 'price'); const amount = this.safeString(trade, 'amount'); const symbol = this.safeSymbol(undefined, market); const id = this.safeString(trade, 'history_id'); let side = this.safeString(trade, 'side'); if (side === 'open_long') { side = 'buy'; } else if (side === 'close_long') { side = 'sell'; } else if (side === 'open_short') { side = 'sell'; } else if (side === 'close_short') { side = 'buy'; } cons