UNPKG

ccxt

Version:

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

1,115 lines (1,113 loc) • 106 kB
'use strict'; var coinbaseinternational$1 = require('./abstract/coinbaseinternational.js'); var errors = require('./base/errors.js'); var Precise = require('./base/Precise.js'); var number = require('./base/functions/number.js'); var sha256 = require('./static_dependencies/noble-hashes/sha256.js'); // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- /** * @class coinbaseinternational * @augments Exchange */ class coinbaseinternational extends coinbaseinternational$1 { describe() { return this.deepExtend(super.describe(), { 'id': 'coinbaseinternational', 'name': 'Coinbase International', 'countries': ['US'], 'certified': false, 'pro': true, 'rateLimit': 100, 'version': 'v1', 'userAgent': this.userAgents['chrome'], 'headers': { 'CB-VERSION': '2018-05-30', }, 'has': { 'CORS': true, 'spot': true, 'margin': true, 'swap': true, 'future': true, 'option': false, 'addMargin': false, 'cancelAllOrders': true, 'cancelOrder': true, 'cancelOrders': false, 'closeAllPositions': false, 'closePosition': false, 'createDepositAddress': true, 'createLimitBuyOrder': true, 'createLimitSellOrder': true, 'createMarketBuyOrder': true, 'createMarketBuyOrderWithCost': false, 'createMarketOrderWithCost': false, 'createMarketSellOrder': true, 'createMarketSellOrderWithCost': false, 'createOrder': true, 'createPostOnlyOrder': true, 'createReduceOnlyOrder': false, 'createStopLimitOrder': true, 'createStopMarketOrder': true, 'createStopOrder': true, 'editOrder': true, 'fetchAccounts': true, 'fetchBalance': true, 'fetchBidsAsks': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchCanceledOrders': false, 'fetchClosedOrders': false, 'fetchCrossBorrowRate': false, 'fetchCrossBorrowRates': false, 'fetchCurrencies': true, 'fetchDeposits': true, 'fetchFundingHistory': true, 'fetchFundingRate': false, 'fetchFundingRateHistory': true, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchIsolatedBorrowRate': false, 'fetchIsolatedBorrowRates': false, 'fetchL2OrderBook': false, 'fetchLedger': false, 'fetchLeverage': false, 'fetchLeverageTiers': false, 'fetchMarginAdjustmentHistory': false, 'fetchMarginMode': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyBuys': true, 'fetchMySells': true, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenInterestHistory': false, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': false, 'fetchOrders': false, 'fetchPosition': true, 'fetchPositionHistory': false, 'fetchPositionMode': false, 'fetchPositions': true, 'fetchPositionsHistory': false, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': false, 'fetchTrades': false, 'fetchTradingFee': false, 'fetchTradingFees': false, 'fetchTransfers': true, 'fetchWithdrawals': true, 'reduceMargin': false, 'sandbox': true, 'setLeverage': false, 'setMargin': true, 'setMarginMode': false, 'setPositionMode': false, 'withdraw': true, }, 'urls': { 'logo': 'https://github.com/ccxt/ccxt/assets/43336371/866ae638-6ab5-4ebf-ab2c-cdcce9545625', 'api': { 'rest': 'https://api.international.coinbase.com/api', }, 'test': { 'rest': 'https://api-n5e1.coinbase.com/api', }, 'www': 'https://international.coinbase.com', 'doc': [ 'https://docs.cloud.coinbase.com/intx/docs', ], 'fees': [ 'https://help.coinbase.com/en/international-exchange/trading-deposits-withdrawals/international-exchange-fees', ], 'referral': '', }, 'requiredCredentials': { 'apiKey': true, 'secret': true, 'password': true, }, 'api': { 'v1': { 'public': { 'get': [ 'assets', 'assets/{assets}', 'assets/{asset}/networks', 'instruments', 'instruments/{instrument}', 'instruments/{instrument}/quote', 'instruments/{instrument}/funding', 'instruments/{instrument}/candles', ], }, 'private': { 'get': [ 'orders', 'orders/{id}', 'portfolios', 'portfolios/{portfolio}', 'portfolios/{portfolio}/detail', 'portfolios/{portfolio}/summary', 'portfolios/{portfolio}/balances', 'portfolios/{portfolio}/balances/{asset}', 'portfolios/{portfolio}/positions', 'portfolios/{portfolio}/positions/{instrument}', 'portfolios/fills', 'portfolios/{portfolio}/fills', 'transfers', 'transfers/{transfer_uuid}', ], 'post': [ 'orders', 'portfolios', 'portfolios/margin', 'portfolios/transfer', 'transfers/withdraw', 'transfers/address', 'transfers/create-counterparty-id', 'transfers/validate-counterparty-id', 'transfers/withdraw/counterparty', ], 'put': [ 'orders/{id}', 'portfolios/{portfolio}', ], 'delete': [ 'orders', 'orders/{id}', ], }, }, }, 'fees': { 'trading': { 'taker': this.parseNumber('0.004'), 'maker': this.parseNumber('0.002'), 'tierBased': true, 'percentage': true, 'tiers': { 'taker': [ [this.parseNumber('0'), this.parseNumber('0.004')], [this.parseNumber('1000000'), this.parseNumber('0.004')], [this.parseNumber('5000000'), this.parseNumber('0.0035')], [this.parseNumber('10000000'), this.parseNumber('0.0035')], [this.parseNumber('50000000'), this.parseNumber('0.003')], [this.parseNumber('250000000'), this.parseNumber('0.0025')], ], 'maker': [ [this.parseNumber('0'), this.parseNumber('0.002')], [this.parseNumber('1000000'), this.parseNumber('0.0016')], [this.parseNumber('5000000'), this.parseNumber('0.001')], [this.parseNumber('10000000'), this.parseNumber('0.0008')], [this.parseNumber('50000000'), this.parseNumber('0.0005')], [this.parseNumber('250000000'), this.parseNumber('0')], ], }, }, }, 'precisionMode': number.TICK_SIZE, 'exceptions': { 'exact': {}, 'broad': { 'DUPLICATE_CLIENT_ORDER_ID': errors.DuplicateOrderId, 'Order rejected': errors.InvalidOrder, 'market orders must be IoC': errors.InvalidOrder, 'tif is required': errors.InvalidOrder, 'Invalid replace order request': errors.InvalidOrder, 'Unauthorized': errors.PermissionDenied, 'invalid result_limit': errors.BadRequest, 'is a required field': errors.BadRequest, 'Not Found': errors.BadRequest, 'ip not allowed': errors.AuthenticationError, }, }, 'timeframes': { '1m': 'ONE_MINUTE', '5m': 'FIVE_MINUTE', '15m': 'FIFTEEN_MINUTE', '30m': 'THIRTY_MINUTE', '1h': 'ONE_HOUR', '2h': 'TWO_HOUR', '6h': 'SIX_HOUR', '1d': 'ONE_DAY', }, 'options': { 'brokerId': 'nfqkvdjp', 'portfolio': '', 'withdraw': { 'method': 'v1PrivatePostTransfersWithdraw', // use v1PrivatePostTransfersWithdrawCounterparty for counterparty withdrawals }, 'networksById': { 'ethereum': 'ETH', 'arbitrum': 'ARBITRUM', 'avacchain': 'AVAX', 'optimism': 'OPTIMISM', 'polygon': 'MATIC', 'solana': 'SOL', 'bitcoin': 'BTC', }, }, 'features': { 'default': { 'sandbox': true, 'createOrder': { 'marginMode': false, 'triggerPrice': true, 'triggerPriceType': undefined, 'triggerDirection': true, 'stopLossPrice': false, 'takeProfitPrice': false, 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': true, 'FOK': true, 'PO': true, 'GTD': true, 'GTC': true, // has 30 days max }, 'hedged': false, 'trailing': false, 'leverage': false, 'marketBuyByCost': false, 'marketBuyRequiresPrice': true, 'selfTradePrevention': true, 'iceberg': false, }, 'createOrders': undefined, 'fetchMyTrades': { 'marginMode': false, 'limit': 100, 'daysBack': undefined, 'untilDays': 10000, 'symbolRequired': false, }, 'fetchOrder': { 'marginMode': false, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOpenOrders': { 'marginMode': false, 'limit': 100, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOrders': undefined, 'fetchClosedOrders': undefined, 'fetchOHLCV': { 'limit': 300, }, }, 'spot': { 'extends': 'default', }, 'swap': { 'linear': { 'extends': 'default', }, 'inverse': { 'extends': 'default', }, }, 'future': { 'linear': undefined, 'inverse': undefined, }, }, }); } async handlePortfolioAndParams(methodName, params = {}) { let portfolio = undefined; [portfolio, params] = this.handleOptionAndParams(params, methodName, 'portfolio'); if ((portfolio !== undefined) && (portfolio !== '')) { return [portfolio, params]; } const defaultPortfolio = this.safeString(this.options, 'portfolio'); if ((defaultPortfolio !== undefined) && (defaultPortfolio !== '')) { return [defaultPortfolio, params]; } const accounts = await this.fetchAccounts(); for (let i = 0; i < accounts.length; i++) { const account = accounts[i]; const info = this.safeDict(account, 'info', {}); if (this.safeBool(info, 'is_default')) { const portfolioId = this.safeString(info, 'portfolio_id'); this.options['portfolio'] = portfolioId; return [portfolioId, params]; } } throw new errors.ArgumentsRequired(this.id + ' ' + methodName + '() requires a portfolio parameter or set the default portfolio with this.options["portfolio"]'); } async handleNetworkIdAndParams(currencyCode, methodName, params) { let networkId = undefined; [networkId, params] = this.handleOptionAndParams(params, methodName, 'network_arn_id'); if (networkId === undefined) { await this.loadCurrencyNetworks(currencyCode); const networks = this.currencies[currencyCode]['networks']; const network = this.safeString2(params, 'networkCode', 'network'); if (network === undefined) { // find default network if (this.isEmpty(networks)) { throw new errors.BadRequest(this.id + ' createDepositAddress network not found for currency ' + currencyCode + ' please specify networkId in params'); } const defaultNetwork = this.findDefaultNetwork(networks); networkId = defaultNetwork['id']; } else { networkId = this.networkCodeToId(network, currencyCode); } } return [networkId, params]; } /** * @method * @name coinbaseinternational#fetchAccounts * @description fetch all the accounts associated with a profile * @see https://docs.cloud.coinbase.com/intx/reference/getportfolios * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/#/?id=account-structure} indexed by the account type */ async fetchAccounts(params = {}) { await this.loadMarkets(); const response = await this.v1PrivateGetPortfolios(params); // // [ // { // "portfolio_id":"1ap32qsc-1-0", // "portfolio_uuid":"028d7f6c-b92c-7361-8b7e-2932711e5a22", // "name":"CCXT Portfolio 030624-17:16", // "user_uuid":"e6cf46b6-a32f-5fa7-addb-3324d4526fbd", // "maker_fee_rate":"0", // "taker_fee_rate":"0.0002", // "trading_lock":false, // "borrow_disabled":false, // "is_lsp":false, // "is_default":true, // "cross_collateral_enabled":false // } // ] // return this.parseAccounts(response, params); } parseAccount(account) { // // { // "portfolio_id":"1ap32qsc-1-0", // "portfolio_uuid":"028d7f6c-b92c-7361-8b7e-2932711e5a22", // "name":"CCXT Portfolio 030624-17:16", // "user_uuid":"e6cf46b6-a32f-5fa7-addb-3324d4526fbd", // "maker_fee_rate":"0", // "taker_fee_rate":"0.0002", // "trading_lock":false, // "borrow_disabled":false, // "is_lsp":false, // "is_default":true, // "cross_collateral_enabled":false // } // return { 'id': this.safeString2(account, 'portfolio_id', 'portfolio_uuid'), 'type': undefined, 'code': undefined, 'info': account, }; } /** * @method * @name coinbaseinternational#fetchOHLCV * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market * @see https://docs.cdp.coinbase.com/intx/reference/getinstrumentcandles * @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, default 100 max 10000 * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume * @param {int} [params.until] timestamp in ms of the latest candle to fetch * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) */ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = 100, params = {}) { await this.loadMarkets(); let paginate = false; [paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate'); if (paginate) { return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 10000); } const market = this.market(symbol); const request = { 'instrument': market['id'], 'granularity': this.safeString(this.timeframes, timeframe, timeframe), }; if (since !== undefined) { request['start'] = this.iso8601(since); } else { throw new errors.ArgumentsRequired(this.id + ' fetchOHLCV() requires a since argument'); } const unitl = this.safeInteger(params, 'until'); if (unitl !== undefined) { params = this.omit(params, 'until'); request['end'] = this.iso8601(unitl); } const response = await this.v1PublicGetInstrumentsInstrumentCandles(this.extend(request, params)); // // { // "aggregations": [ // { // "start": "2024-04-23T00:00:00Z", // "open": "62884.4", // "high": "64710.6", // "low": "62884.4", // "close": "63508.4", // "volume": "3253.9983" // } // ] // } // const candles = this.safeList(response, 'aggregations', []); return this.parseOHLCVs(candles, market, timeframe, since, limit); } parseOHLCV(ohlcv, market = undefined) { // // { // "start": "2024-04-23T00:00:00Z", // "open": "62884.4", // "high": "64710.6", // "low": "62884.4", // "close": "63508.4", // "volume": "3253.9983" // } // return [ this.parse8601(this.safeString2(ohlcv, 'start', 'time')), this.safeNumber(ohlcv, 'open'), this.safeNumber(ohlcv, 'high'), this.safeNumber(ohlcv, 'low'), this.safeNumber(ohlcv, 'close'), this.safeNumber(ohlcv, 'volume'), ]; } /** * @method * @name coinbaseinternational#fetchFundingRateHistory * @description fetches historical funding rate prices * @see https://docs.cloud.coinbase.com/intx/reference/getinstrumentfunding * @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 {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 {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(); let paginate = false; [paginate, params] = this.handleOptionAndParams(params, 'fetchFundingRateHistory', 'paginate'); let maxEntriesPerRequest = undefined; [maxEntriesPerRequest, params] = this.handleOptionAndParams(params, 'fetchFundingRateHistory', 'maxEntriesPerRequest', 100); const pageKey = 'ccxtPageKey'; if (paginate) { return await this.fetchPaginatedCallIncremental('fetchFundingRateHistory', symbol, since, limit, params, pageKey, maxEntriesPerRequest); } const market = this.market(symbol); const page = this.safeInteger(params, pageKey, 1) - 1; const request = { 'instrument': market['id'], 'result_offset': this.safeInteger2(params, 'offset', 'result_offset', page * maxEntriesPerRequest), }; if (limit !== undefined) { request['result_limit'] = limit; } const response = await this.v1PublicGetInstrumentsInstrumentFunding(this.extend(request, params)); // // { // "pagination":{ // "result_limit":"25", // "result_offset":"0" // }, // "results":[ // { // "instrument_id":"149264167780483072", // "funding_rate":"0.000011", // "mark_price":"47388.1", // "event_time":"2024-02-10T16:00:00Z" // }, // ... // ] // } // const rawRates = this.safeList(response, 'results', []); return this.parseFundingRateHistories(rawRates, market, since, limit); } parseFundingRateHistory(info, market = undefined) { return this.parseFundingRate(info, market); } parseFundingRate(contract, market = undefined) { // // { // "instrument_id":"149264167780483072", // "funding_rate":"0.000011", // "mark_price":"47388.1", // "event_time":"2024-02-10T16:00:00Z" // } // const fundingDatetime = this.safeString2(contract, 'event_time', 'time'); return { 'info': contract, 'symbol': this.safeSymbol(undefined, market), 'markPrice': this.safeNumber(contract, 'mark_price'), 'indexPrice': undefined, 'interestRate': undefined, 'estimatedSettlePrice': undefined, 'timestamp': this.parse8601(fundingDatetime), 'datetime': fundingDatetime, 'fundingRate': this.safeNumber(contract, 'funding_rate'), 'fundingTimestamp': this.parse8601(fundingDatetime), 'fundingDatetime': fundingDatetime, 'nextFundingRate': undefined, 'nextFundingTimestamp': undefined, 'nextFundingDatetime': undefined, 'previousFundingRate': undefined, 'previousFundingTimestamp': undefined, 'previousFundingDatetime': undefined, }; } /** * @method * @name coinbaseinternational#fetchFundingHistory * @description fetch the history of funding payments paid and received on this account * @see https://docs.cdp.coinbase.com/intx/reference/gettransfers * @param {string} [symbol] unified market symbol * @param {int} [since] the earliest time in ms to fetch funding history for * @param {int} [limit] the maximum number of funding history structures to retrieve * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [funding history structure]{@link https://docs.ccxt.com/#/?id=funding-history-structure} */ async fetchFundingHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const request = { 'type': 'FUNDING', }; let market = undefined; if (symbol !== undefined) { market = this.market(symbol); } let portfolios = undefined; [portfolios, params] = this.handleOptionAndParams(params, 'fetchFundingHistory', 'portfolios'); if (portfolios !== undefined) { request['portfolios'] = portfolios; } if (since !== undefined) { request['time_from'] = this.iso8601(since); } if (limit !== undefined) { request['result_limit'] = limit; } else { request['result_limit'] = 100; } const response = await this.v1PrivateGetTransfers(this.extend(request, params)); const fundings = this.safeList(response, 'results', []); return this.parseIncomes(fundings, market, since, limit); } parseIncome(income, market = undefined) { // // { // "amount":"0.0008", // "asset":"USDC", // "created_at":"2024-02-22T16:00:00Z", // "from_portfolio":{ // "id":"13yuk1fs-1-0", // "name":"Eng Test Portfolio - 2", // "uuid":"018712f2-5ff9-7de3-9010-xxxxxxxxx" // }, // "instrument_id":"149264164756389888", // "instrument_symbol":"ETH-PERP", // "position_id":"1xy4v51m-1-2", // "status":"PROCESSED", // "to_portfolio":{ // "name":"CB_FUND" // }, // "transfer_type":"FUNDING", // "transfer_uuid":"a6b708df-2c44-32c5-bb98-xxxxxxxxxx", // "updated_at":"2024-02-22T16:00:00Z" // } // const marketId = this.safeString(income, 'symbol'); market = this.safeMarket(marketId, market, undefined, 'contract'); const datetime = this.safeInteger(income, 'created_at'); const timestamp = this.parse8601(datetime); const currencyId = this.safeString(income, 'asset'); const code = this.safeCurrencyCode(currencyId); return { 'info': income, 'symbol': market['symbol'], 'code': code, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'id': this.safeString(income, 'transfer_uuid'), 'amount': this.safeNumber(income, 'amount'), 'rate': undefined, }; } /** * @method * @name coinbaseinternational#fetchTransfers * @description fetch a history of internal transfers made on an account * @see https://docs.cdp.coinbase.com/intx/reference/gettransfers * @param {string} code unified currency code of the currency transferred * @param {int} [since] the earliest time in ms to fetch transfers for * @param {int} [limit] the maximum number of transfers structures to retrieve * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/#/?id=transfer-structure} */ async fetchTransfers(code = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const request = { 'type': 'INTERNAL', }; let currency = undefined; if (code !== undefined) { currency = this.currency(code); } let portfolios = undefined; [portfolios, params] = this.handleOptionAndParams(params, 'fetchTransfers', 'portfolios'); if (portfolios !== undefined) { request['portfolios'] = portfolios; } if (since !== undefined) { request['time_from'] = this.iso8601(since); } if (limit !== undefined) { request['result_limit'] = limit; } else { request['result_limit'] = 100; } const response = await this.v1PrivateGetTransfers(this.extend(request, params)); const transfers = this.safeList(response, 'results', []); return this.parseTransfers(transfers, currency, since, limit); } parseTransfer(transfer, currency = undefined) { // // { // "amount":"0.0008", // "asset":"USDC", // "created_at":"2024-02-22T16:00:00Z", // "from_portfolio":{ // "id":"13yuk1fs-1-0", // "name":"Eng Test Portfolio - 2", // "uuid":"018712f2-5ff9-7de3-9010-xxxxxxxxx" // }, // "instrument_id":"149264164756389888", // "instrument_symbol":"ETH-PERP", // "position_id":"1xy4v51m-1-2", // "status":"PROCESSED", // "to_portfolio":{ // "name":"CB_FUND" // }, // "transfer_type":"FUNDING", // "transfer_uuid":"a6b708df-2c44-32c5-bb98-xxxxxxxxxx", // "updated_at":"2024-02-22T16:00:00Z" // } // const datetime = this.safeInteger(transfer, 'created_at'); const timestamp = this.parse8601(datetime); const currencyId = this.safeString(transfer, 'asset'); const code = this.safeCurrencyCode(currencyId); const fromPorfolio = this.safeDict(transfer, 'from_portfolio', {}); const fromId = this.safeString(fromPorfolio, 'id'); const toPorfolio = this.safeDict(transfer, 'to_portfolio', {}); const toId = this.safeString(toPorfolio, 'id'); return { 'info': transfer, 'id': this.safeString(transfer, 'transfer_uuid'), 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'currency': code, 'amount': this.safeNumber(transfer, 'amount'), 'fromAccount': fromId, 'toAccount': toId, 'status': this.parseTransferStatus(this.safeString(transfer, 'status')), }; } parseTransferStatus(status) { const statuses = { 'FAILED': 'failed', 'PROCESSED': 'ok', 'NEW': 'pending', 'STARTED': 'pending', }; return this.safeString(statuses, status, status); } /** * @method * @name coinbaseinternational#createDepositAddress * @description create a currency deposit address * @see https://docs.cloud.coinbase.com/intx/reference/createaddress * @see https://docs.cloud.coinbase.com/intx/reference/createcounterpartyid * @param {string} code unified currency code of the currency for the deposit address * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.network_arn_id] Identifies the blockchain network (e.g., networks/ethereum-mainnet/assets/313ef8a9-ae5a-5f2f-8a56-572c0e2a4d5a) if not provided will pick default * @param {string} [params.network] unified network code to identify the blockchain network * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure} */ async createDepositAddress(code, params = {}) { await this.loadMarkets(); let method = undefined; [method, params] = this.handleOptionAndParams(params, 'createDepositAddress', 'method', 'v1PrivatePostTransfersAddress'); let portfolio = undefined; [portfolio, params] = await this.handlePortfolioAndParams('createDepositAddress', params); const request = { 'portfolio': portfolio, }; if (method === 'v1PrivatePostTransfersAddress') { const currency = this.currency(code); request['asset'] = currency['id']; let networkId = undefined; [networkId, params] = await this.handleNetworkIdAndParams(code, 'createDepositAddress', params); request['network_arn_id'] = networkId; } const response = await this[method](this.extend(request, params)); // // v1PrivatePostTransfersAddress // { // address: "3LkwYscRyh6tUR1XTqXSJQoJnK7ucC1F4n", // network_arn_id: "networks/bitcoin-mainnet/assets/6ecc0dcc-10a2-500e-b315-a3b9abae19ce", // destination_tag: "", // } // v1PrivatePostTransfersCreateCounterpartyId // { // "portfolio_uuid":"018e0a8b-6b6b-70e0-9689-1e7926c2c8bc", // "counterparty_id":"CB2ZPUCZBE" // } // const tag = this.safeString(response, 'destination_tag'); const address = this.safeString2(response, 'address', 'counterparty_id'); return { 'currency': code, 'tag': tag, 'address': address, 'info': response, }; } findDefaultNetwork(networks) { const networksArray = this.toArray(networks); for (let i = 0; i < networksArray.length; i++) { const info = networksArray[i]['info']; const is_default = this.safeBool(info, 'is_default', false); if (is_default === true) { return networksArray[i]; } } return networksArray[0]; } async loadCurrencyNetworks(code, params = {}) { const currency = this.currency(code); const networks = this.safeDict(currency, 'networks'); if (networks !== undefined) { return false; } const request = { 'asset': currency['id'], }; const rawNetworks = await this.v1PublicGetAssetsAssetNetworks(request); // // [ // { // "asset_id":"1", // "asset_uuid":"2b92315d-eab7-5bef-84fa-089a131333f5", // "asset_name":"USDC", // "network_arn_id":"networks/ethereum-mainnet/assets/9bc140b4-69c3-5fc9-bd0d-b041bcf40039", // "min_withdrawal_amt":"1", // "max_withdrawal_amt":"100000000", // "network_confirms":35, // "processing_time":485, // "is_default":true, // "network_name":"ethereum", // "display_name":"Ethereum" // }, // .... // ] // currency['networks'] = this.parseNetworks(rawNetworks); return true; } parseNetworks(networks, params = {}) { const result = {}; for (let i = 0; i < networks.length; i++) { const network = this.extend(this.parseNetwork(networks[i]), params); result[network['network']] = network; } return result; } parseNetwork(network, params = {}) { // // { // "asset_id":"1", // "asset_uuid":"2b92315d-eab7-5bef-84fa-089a131333f5", // "asset_name":"USDC", // "network_arn_id":"networks/ethereum-mainnet/assets/9bc140b4-69c3-5fc9-bd0d-b041bcf40039", // "min_withdrawal_amt":"1", // "max_withdrawal_amt":"100000000", // "network_confirms":35, // "processing_time":485, // "is_default":true, // "network_name":"ethereum", // "display_name":"Ethereum" // } // const currencyId = this.safeString(network, 'asset_name'); const currencyCode = this.safeCurrencyCode(currencyId); const networkId = this.safeString(network, 'network_arn_id'); const networkIdForCode = this.safeStringN(network, ['network_name', 'display_name', 'network_arn_id'], ''); return this.safeNetwork({ 'info': network, 'id': networkId, 'name': this.safeString(network, 'display_name'), 'network': this.networkIdToCode(networkIdForCode, currencyCode), 'active': undefined, 'deposit': undefined, 'withdraw': undefined, 'precision': undefined, 'fee': undefined, 'limits': { 'withdraw': { 'min': this.safeNumber(network, 'min_withdrawal_amt'), 'max': this.safeNumber(network, 'max_withdrawal_amt'), }, 'deposit': { 'min': undefined, 'max': undefined, }, }, }); } /** * @method * @name coinbaseinternational#setMargin * @description Either adds or reduces margin in order to set the margin to a specific value * @see https://docs.cloud.coinbase.com/intx/reference/setportfoliomarginoverride * @param {string} symbol unified market symbol of the market to set margin in * @param {float} amount the amount to set the margin to * @param {object} [params] parameters specific to the exchange API endpoint * @returns {object} A [margin structure]{@link https://github.com/ccxt/ccxt/wiki/Manual#add-margin-structure} */ async setMargin(symbol, amount, params = {}) { let portfolio = undefined; [portfolio, params] = await this.handlePortfolioAndParams('setMargin', params); if (symbol !== undefined) { throw new errors.BadRequest(this.id + ' setMargin() only allows setting margin to full portfolio'); } const request = { 'portfolio': portfolio, 'margin_override': amount, }; return await this.v1PrivatePostPortfoliosMargin(this.extend(request, params)); } /** * @method * @name exchange#fetchDepositsWithdrawals * @description fetch history of deposits and withdrawals * @see https://docs.cloud.coinbase.com/intx/reference/gettransfers * @param {string} [code] unified currency code for the currency of the deposit/withdrawals, default is undefined * @param {int} [since] timestamp in ms of the earliest deposit/withdrawal, default is undefined * @param {int} [limit] max number of deposit/withdrawals to return, default is undefined * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.portfolios] Identifies the portfolios by UUID (e.g., 892e8c7c-e979-4cad-b61b-55a197932cf1) or portfolio ID (e.g., 5189861793641175). Can provide single or multiple portfolios to filter by or fetches transfers for all portfolios if none are provided. * @param {int} [params.until] Only find transfers updated before this time. Use timestamp format * @param {string} [params.status] The current status of transfer. Possible values: [PROCESSED, NEW, FAILED, STARTED] * @param {string} [params.type] The type of transfer Possible values: [DEPOSIT, WITHDRAW, REBATE, STIPEND, INTERNAL, FUNDING] * @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 {object} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure} */ async fetchDepositsWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); let paginate = undefined; [paginate, params] = this.handleOptionAndParams(params, 'fetchDepositsWithdrawals', 'paginate'); let maxEntriesPerRequest = undefined; [maxEntriesPerRequest, params] = this.handleOptionAndParams(params, 'fetchDepositsWithdrawals', 'maxEntriesPerRequest', 100); const pageKey = 'ccxtPageKey'; if (paginate) { return await this.fetchPaginatedCallIncremental('fetchDepositsWithdrawals', code, since, limit, params, pageKey, maxEntriesPerRequest); } const page = this.safeInteger(params, pageKey, 1) - 1; const request = { 'result_offset': this.safeInteger2(params, 'offset', 'result_offset', page * maxEntriesPerRequest), }; if (since !== undefined) { request['time_from'] = this.iso8601(since); } if (limit !== undefined) { const newLimit = Math.min(limit, 100); request['result_limit'] = newLimit; } let portfolios = undefined; [portfolios, params] = this.handleOptionAndParams(params, 'fetchDepositsWithdrawals', 'portfolios'); if (portfolios !== undefined) { request['portfolios'] = portfolios; } let until = undefined; [until, params] = this.handleOptionAndParams(params, 'fetchDepositsWithdrawals', 'until'); if (until !== undefined) { request['time_to'] = this.iso8601(until); } const response = await this.v1PrivateGetTransfers(this.extend(request, params)); // // { // "pagination":{ // "result_limit":25, // "result_offset":0 // }, // "results":[ // { // "transfer_uuid":"8e471d77-4208-45a8-9e5b-f3bd8a2c1fc3", // "transfer_type":"WITHDRAW", // "amount":"1.000000", // "asset":"USDC", // "status":"PROCESSED", // "network_name":"ethereum", // "created_at":"2024-03-14T02:32:18.497795Z", // "updated_at":"2024-03-14T02:35:38.514588Z", // "from_portfolio":{ // "id":"1yun54bb-1-6", // "uuid":"018e0a8b-6b6b-70e0-9689-1e7926c2c8bc", // "name":"fungus technology o?Portfolio" // }, // "to_address":"0xcdcE79F820BE9d6C5033db5c31d1AE3A8c2399bB" // } // ] // } // const rawTransactions = this.safeList(response, 'results', []); return this.parseTransactions(rawTransactions); } /** * @method * @name coinbaseinternational#fetchPosition * @see https://docs.cloud.coinbase.com/intx/reference/getportfolioposition * @description fetch data on an open position * @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 * @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure} */ async fetchPosition(symbol, params = {}) { await this.loadMarkets(); symbol = this.symbol(symbol); let portfolio = undefined; [portfolio, params] = await this.handlePortfolioAndParams('fetchPosition', params); const request = { 'portfolio': portfolio, 'instrument': this.marketId(symbol), }; const position = await this.v1PrivateGetPortfoliosPortfolioPositionsInstrument(this.extend(request, params)); // // { // "symbol":"BTC-PERP", // "instrument_id":"114jqr89-0-0", // "instrument_uuid":"b3469e0b-222c-4f8a-9f68-1f9e44d7e5e0", // "vwap":"52482.3", // "net_size":"0", // "buy_order_size":"0.001", // "sell_order_size":"0", // "im_contribution":"0.2", // "unrealized_pnl":"0", // "mark_price":"52406.8", // "entry_vwap":"52472.9" // } // return this.parsePosition(position); } parsePosition(position, market = undefined) { // // { // "symbol":"BTC-PERP", // "instrument_id":"114jqr89-0-0", // "instrument_uuid":"b3469e0b-222c-4f8a-9f68-1f9e44d7e5e0", // "vwap":"52482.3", // "net_size":"0", // "buy_order_size":"0.001", // "sell_order_size":"0", // "im_contribution":"0.2", // "unrealized_pnl":"0", // "mark_price":"52406.8", // "entry_vwap":"52472.9" // } // const marketId = this.safeString(position, 'symbol'); let quantity = this.safeString(position, 'net_size'); market = this.safeMarket(marketId, market, '-'); let side = 'long'; if (Precise["default"].stringLe(quantity, '0')) { side = 'short'; quantity = Precise["default"].stringMul('-1', quantity); } return this.safePosition({ 'info': position, 'id': this.safeString(position, 'id'), 'symbol': market['symbol'], 'entryPrice': undefined, 'markPrice': this.safeNumber(position, 'mark_price'), 'notional': undefined, 'collateral': undefined, 'unrealizedPnl': this.safeNumber(position, 'unrealized_pnl'), 'side': side, 'contracts': this.parseNumber(quantity), 'contractSize': this.safeNumber(market, 'contractSize'), 'timestamp': undefined, 'datetime': undefined, 'hedged': undefined, 'maintenanceMargin': undefined, 'maintenanceMarginPercentage': undefined, 'initialMargin': this.safeNumber(position, 'im_contribution'), 'initialMarginPercentage': undefined, 'leverage': undefined, 'liquidationPrice': undefined, 'marginRatio': undefined, 'marginMode': undefined, 'percentage': undefined, }); } /** * @method * @name coinbaseinternational#fetchPositions * @see https://docs.cloud.coinbase.com/intx/reference/getportfoliopositions * @description fetch all open positions * @param {string[]} [symbols] list of unified market symbols * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure} */ async fetchPositions(symbols = undefined, params = {}) { await this.loadMarkets(); let portfolio = undefined; [portfolio, params] = await this.handlePortfolioAndParams('fetchPositions', params); const request = { 'portfolio': portfolio, }; const response = await this.v1PrivateGetPortfoliosPortfolioPositions(this.extend(request, params)); // // [ // { // "symbol":"BTC-PERP", // "instrument_id":"114jqr89-0-0", // "instrument_uuid":"b3469e0b-222c-4f8a-9f68-1f9e44d7e5e0", // "vwap":"52482.3", // "net_size":"0", // "buy_order_size":"0.001", // "sell_order_size":"0", // "im_contribution":"0.2", // "unrealized_pnl":"0", // "mark_price":"52406.8", // "entry_vwap":"52472.9" //