UNPKG

ccxt

Version:

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

1,129 lines (1,127 loc) • 135 kB
// ---------------------------------------------------------------------------- // PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN: // https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code // EDIT THE CORRESPONDENT .ts FILE INSTEAD // --------------------------------------------------------------------------- import Exchange from './abstract/bullish.js'; import { AuthenticationError, ArgumentsRequired, BadRequest, BadSymbol, DuplicateOrderId, ExchangeError, InvalidAddress, InvalidNonce, InvalidOrder, InsufficientFunds, MarketClosed, NotSupported, OperationRejected, OrderNotFillable, OrderNotFound, PermissionDenied, RateLimitExceeded } from './base/errors.js'; import { TICK_SIZE } from './base/functions/number.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; // --------------------------------------------------------------------------- /** * @class bullish * @augments Exchange */ export default class bullish extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'bullish', 'name': 'Bullish', 'countries': ['DE'], 'version': 'v3', 'rateLimit': 20, 'pro': true, 'has': { 'CORS': undefined, 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'addMargin': false, 'borrowMargin': false, 'cancelAllOrders': true, 'cancelOrder': true, 'cancelOrders': false, 'createDepositAddress': false, 'createLimitBuyOrder': true, 'createLimitOrder': true, 'createLimitSellOrder': true, 'createMarketBuyOrder': true, 'createMarketOrder': true, 'createMarketSellOrder': true, 'createOrder': true, 'createPostOnlyOrder': true, 'createTriggerOrder': true, 'deposit': false, 'editOrder': true, 'fetchAccounts': true, 'fetchBalance': true, 'fetchBidsAsks': false, 'fetchBorrowInterest': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': true, 'fetchCanceledAndClosedOrders': true, 'fetchCanceledOrders': true, 'fetchClosedOrder': false, 'fetchClosedOrders': true, 'fetchCrossBorrowRate': false, 'fetchCrossBorrowRates': false, 'fetchCurrencies': true, 'fetchDeposit': false, 'fetchDepositAddress': true, 'fetchDepositAddresses': false, 'fetchDepositAddressesByNetwork': false, 'fetchDeposits': false, 'fetchDepositsWithdrawals': true, 'fetchDepositWithdrawFee': false, 'fetchDepositWithdrawFees': false, 'fetchFundingHistory': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': true, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchIsolatedBorrowRate': false, 'fetchIsolatedBorrowRates': false, 'fetchL3OrderBook': false, 'fetchLedger': false, 'fetchLeverage': false, 'fetchLeverageTiers': false, 'fetchMarketLeverageTiers': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenInterestHistory': false, 'fetchOpenOrder': false, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrderBooks': false, 'fetchOrders': true, 'fetchOrderTrades': true, 'fetchPosition': false, 'fetchPositionHistory': false, 'fetchPositionMode': false, 'fetchPositions': true, 'fetchPositionsForSymbol': false, 'fetchPositionsHistory': false, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchStatus': false, 'fetchTicker': true, 'fetchTickers': false, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': false, 'fetchTradingLimits': false, 'fetchTransactionFee': false, 'fetchTransactionFees': false, 'fetchTransactions': false, 'fetchTransfers': true, 'fetchWithdrawal': false, 'fetchWithdrawals': false, 'fetchWithdrawalWhitelist': false, 'reduceMargin': false, 'repayMargin': false, 'setLeverage': false, 'setMargin': false, 'setMarginMode': false, 'setPositionMode': false, 'signIn': true, 'transfer': true, 'withdraw': true, 'ws': true, }, 'timeframes': { '1m': '1m', '5m': '5m', '30m': '30m', '1h': '1h', '6h': '6h', '12h': '12h', '1d': '1d', }, 'urls': { 'logo': 'https://github.com/user-attachments/assets/68f0686b-84f0-4da9-a751-f7089af3a9ed', 'api': { 'public': 'https://api.exchange.bullish.com/trading-api', 'private': 'https://api.exchange.bullish.com/trading-api', }, 'test': { 'public': 'https://api.simnext.bullish-test.com/trading-api', 'private': 'https://api.simnext.bullish-test.com/trading-api', }, 'www': 'https://bullish.com/', 'referral': '', 'doc': [ 'https://api.exchange.bullish.com/docs/api/rest/', ], }, 'api': { 'public': { 'get': { 'v1/nonce': 1, 'v1/time': 1, 'v1/assets': 1, 'v1/assets/{symbol}': 1, 'v1/markets': 1, 'v1/markets/{symbol}': 1, 'v1/history/markets/{symbol}': 1, 'v1/markets/{symbol}/orderbook/hybrid': 1, 'v1/markets/{symbol}/trades': 1, 'v1/markets/{symbol}/tick': 1, 'v1/markets/{symbol}/candle': 1, 'v1/history/markets/{symbol}/trades': 1, 'v1/history/markets/{symbol}/funding-rate': 1, 'v1/index-prices': 1, 'v1/index-prices/{assetSymbol}': 1, 'v1/expiry-prices/{symbol}': 1, 'v1/option-ladder': 1, 'v1/option-ladder/{symbol}': 1, }, }, 'private': { 'get': { 'v2/orders': 1, 'v2/history/orders': 1, 'v2/orders/{orderId}': 1, 'v2/amm-instructions': 1, 'v2/amm-instructions/{instructionId}': 1, 'v1/wallets/transactions': 1, 'v1/wallets/limits/{symbol}': 1, 'v1/wallets/deposit-instructions/crypto/{symbol}': 1, 'v1/wallets/withdrawal-instructions/crypto/{symbol}': 1, 'v1/wallets/deposit-instructions/fiat/{symbol}': 1, 'v1/wallets/withdrawal-instructions/fiat/{symbol}': 1, 'v1/wallets/self-hosted/verification-attempts': 1, 'v1/trades': 5, 'v1/history/trades': 5, 'v1/trades/{tradeId}': 5, 'v1/trades/client-order-id/{clientOrderId}': 1, 'v1/accounts/asset': 1, 'v1/accounts/asset/{symbol}': 1, 'v1/users/logout': 1, 'v1/users/hmac/login': 1, 'v1/accounts/trading-accounts': 1, 'v1/accounts/trading-accounts/{tradingAccountId}': 1, 'v1/derivatives-positions': 1, 'v1/history/derivatives-settlement': 1, 'v1/history/transfer': 1, 'v1/history/borrow-interest': 1, 'v2/mmp-configuration': 1, 'v2/otc-trades': 1, 'v2/otc-trades/{otcTradeId}': 1, 'v2/otc-trades/unconfirmed-trade': 1, }, 'post': { 'v2/orders': 5, 'v2/command': 5, 'v2/amm-instructions': 1, 'v1/wallets/withdrawal': 1, 'v2/users/login': 1, 'v1/simulate-portfolio-margin': 1, 'v1/wallets/self-hosted/initiate': 1, 'v2/mmp-configuration': 1, 'v2/otc-trades': 1, 'v2/otc-command': 1, }, }, }, 'fees': { 'trading': { 'tierBased': false, 'percentage': true, // todo check fees 'taker': this.parseNumber('0.001'), 'maker': this.parseNumber('0.001'), }, }, 'precisionMode': TICK_SIZE, // exchange-specific options 'options': { 'timeDifference': 0, 'adjustForTimeDifference': false, 'networks': { 'BTC': 'BTC', 'EOS': 'EOS', 'ERC20': 'ETH', }, 'defaultNetwork': 'ERC20', 'defaultNetworks': { 'USDC': 'ERC20', }, 'tradingAccountId': undefined, }, 'features': { 'default': { 'sandbox': true, 'createOrder': { 'marginMode': false, 'triggerPrice': true, 'triggerPriceType': undefined, 'triggerDirection': false, 'stopLossPrice': false, 'takeProfitPrice': false, 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': true, 'FOK': true, 'PO': true, 'GTD': false, }, 'hedged': false, 'trailing': false, 'leverage': false, 'marketBuyByCost': false, 'marketBuyRequiresPrice': false, 'selfTradePrevention': false, 'iceberg': false, }, 'createOrders': undefined, 'fetchMyTrades': { 'marginMode': false, 'limit': 100, 'daysBack': 90, 'symbolRequired': false, 'untilDays': 90, }, 'fetchOrder': { 'marginMode': false, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOrders': { 'marginMode': false, 'limit': 100, 'daysBack': 90, 'untilDays': 90, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOpenOrders': { 'marginMode': false, 'limit': 100, 'daysBack': 90, 'untilDays': 90, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchCanceledAndClosedOrders': { 'marginMode': false, 'limit': 100, 'daysBack': 90, 'untilDays': 90, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchClosedOrders': { 'marginMode': false, 'limit': 100, 'daysBack': 1, 'daysBackCanceled': 1, 'untilDays': 1, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchCanceledOrders': { 'marginMode': false, 'limit': 100, 'daysBack': 1, 'untilDays': 1, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOHLCV': { 'limit': 1000, }, }, 'spot': { 'extends': 'default', }, 'swap': { 'linear': { 'extends': 'default', }, 'inverse': undefined, }, 'future': { 'linear': { 'extends': 'default', }, 'inverse': undefined, }, }, 'exceptions': { 'exact': { '1': BadRequest, '5': InvalidOrder, '6': DuplicateOrderId, '13': BadRequest, '15': BadRequest, '18': BadRequest, '1002': BadRequest, '2001': BadRequest, '2002': BadRequest, '2003': BadRequest, '2004': BadRequest, '2005': ExchangeError, '2006': BadRequest, '2007': BadRequest, '2008': BadRequest, '2009': BadSymbol, '2010': AuthenticationError, '2011': AuthenticationError, '2012': BadRequest, '2013': InvalidOrder, '2015': OperationRejected, '2016': BadRequest, '2017': BadRequest, '2018': BadRequest, '2020': PermissionDenied, '2021': OperationRejected, '2029': InvalidNonce, '2035': InvalidNonce, '3001': InsufficientFunds, '3002': OrderNotFound, '3003': PermissionDenied, '3004': InsufficientFunds, '3005': InsufficientFunds, '3006': InsufficientFunds, '3007': DuplicateOrderId, '3031': BadRequest, '3032': BadRequest, '3033': PermissionDenied, '3034': RateLimitExceeded, '3035': RateLimitExceeded, '3047': OperationRejected, '3048': OperationRejected, '3049': OperationRejected, '3051': InsufficientFunds, '3052': InsufficientFunds, '3063': BadRequest, '3064': OrderNotFillable, '3065': MarketClosed, '3066': ExchangeError, '3067': MarketClosed, '6007': InvalidOrder, '6011': InvalidOrder, '6012': InvalidOrder, '6013': InvalidOrder, '8301': ExchangeError, '8305': ExchangeError, '8306': ExchangeError, '8307': ExchangeError, '8310': InvalidAddress, '8311': BadRequest, '8313': BadRequest, '8315': OperationRejected, '8316': OperationRejected, '8317': OperationRejected, '8318': NotSupported, '8319': NotSupported, '8320': InvalidAddress, '8322': BadRequest, '8327': AuthenticationError, '8329': ExchangeError, '8331': InvalidAddress, '8332': BadRequest, '8333': BadRequest, '8334': BadRequest, '8335': InvalidAddress, '8336': InvalidAddress, '8399': ExchangeError, // Unknown error }, 'broad': { 'HttpInvalidParameterException': BadRequest, 'UNAUTHORIZED_COMMAND': AuthenticationError, 'QUERY_FILTER_ERROR': BadRequest, 'INVALID_SYMBOL': BadSymbol, // {"message":"Invalid symbol provided","errorCode":28004,"errorCodeName":"INVALID_SYMBOL"} }, }, }); } /** * @method * @name bullish#fetchTime * @description fetches the current integer timestamp in milliseconds from the exchange server * @see https://api.exchange.bullish.com/docs/api/rest/trading-api/v2/#tag--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.publicGetV1Time(params); // // { // "datetime": "2025-05-05T20:05:50.999Z", // "timestamp": 1746475550999 // } // return this.safeInteger(response, 'timestamp'); } /** * @method * @name bullish#fetchCurrencies * @description fetches all available currencies on an exchange * @see https://api.exchange.bullish.com/docs/api/rest/trading-api/v2/#get-/v1/assets * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} an associative dictionary of currencies */ async fetchCurrencies(params = {}) { const response = await this.publicGetV1Assets(params); // // [ // { // "assetId": "72", // "symbol": "BTT1M", // "name": "BitTorrent (millions)", // "precision": "5", // "minBalanceInterest": "0.00000", // "apr": "10.00", // "minFee": "0.00000", // "maxBorrow": "0.00000", // "totalOfferedLoanQuantity": "0.00000", // "loanBorrowedQuantity": "0.00000", // "collateralBands": // [ // { // "collateralPercentage": "90.00", // "bandLimitUSD": "100000.0000" // }, // { // "collateralPercentage": "68.00", // "bandLimitUSD": "300000.0000" // }, // { // "collateralPercentage": "25.00", // "bandLimitUSD": "600000.0000" // } // ], // "underlyingAsset": // { // "symbol": "BTT1M", // "assetId": "72", // "bpmMinReturnStart": "0.9200", // "bpmMinReturnEnd": "0.9300", // "bpmMaxReturnStart": "1.0800", // "bpmMaxReturnEnd": "1.0800", // "marketRiskFloorPctStart": "2.60", // "marketRiskFloorPctEnd": "2.50", // "bpmTransitionDateTimeStart": "2025-05-05T08:00:00.000Z", // "bpmTransitionDateTimeEnd": "2025-05-08T08:00:00.000Z" // } // }, ... // ] // const result = {}; for (let i = 0; i < response.length; i++) { const currency = response[i]; const id = this.safeString(currency, 'symbol'); const code = this.safeCurrencyCode(id); const name = this.safeString(currency, 'name'); const precision = this.safeString(currency, 'precision'); result[code] = { 'id': id, 'code': code, 'name': name, 'active': undefined, 'deposit': undefined, 'withdraw': undefined, 'fee': this.safeNumber(currency, 'minFee'), 'precision': this.parseNumber(this.parsePrecision(precision)), 'limits': { 'amount': { 'min': undefined, 'max': undefined }, 'withdraw': { 'min': undefined, 'max': undefined }, }, 'networks': {}, 'type': 'crypto', 'info': currency, }; } return result; } /** * @method * @name bullish#fetchMarkets * @description retrieves data on all markets for ace * @see https://api.exchange.bullish.com/docs/api/rest/trading-api/v2/#get-/v1/markets * @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.options['adjustForTimeDifference']) { await this.loadTimeDifference(); } const response = await this.publicGetV1Markets(params); return this.parseMarkets(response); } parseMarket(market) { // // { // "marketId": "20069", // "symbol": "BTC-USDC-20250516", // "quoteAssetId": "5", // "baseAssetId": "1", // "quoteSymbol": "USDC", // "baseSymbol": "BTC", // "quotePrecision": "4", // "basePrecision": "8", // "pricePrecision": "4", // "quantityPrecision": "8", // "costPrecision": "4", // "minQuantityLimit": "0.00050000", // "maxQuantityLimit": "200.00000000", // "maxPriceLimit": null, // "minPriceLimit": null, // "maxCostLimit": null, // "minCostLimit": null, // "timeZone": "Etc/UTC", // "tickSize": "0.1000", // "liquidityTickSize": "100.0000", // "liquidityPrecision": "4", // "makerFee": "0", // "takerFee": "2", // "roundingCorrectionFactor": "0.00000100", // "makerMinLiquidityAddition": "1000000", // "orderTypes": // [ // "LMT", // "MKT", // "STOP_LIMIT", // "POST_ONLY" // ], // "spotTradingEnabled": true, // "marginTradingEnabled": true, // "marketEnabled": true, // "createOrderEnabled": true, // "cancelOrderEnabled": true, // "liquidityInvestEnabled": true, // "liquidityWithdrawEnabled": true, // "feeTiers": // [ // { // "feeTierId": "1", // "staticSpreadFee": "0.00000000", // "isDislocationEnabled": false // }, // { // "feeTierId": "10", // "staticSpreadFee": "0.00100000", // "isDislocationEnabled": true // }, // { // "feeTierId": "11", // "staticSpreadFee": "0.00150000", // "isDislocationEnabled": false // }, // { // "feeTierId": "12", // "staticSpreadFee": "0.00150000", // "isDislocationEnabled": true // }, // { // "feeTierId": "13", // "staticSpreadFee": "0.00300000", // "isDislocationEnabled": false // }, // { // "feeTierId": "14", // "staticSpreadFee": "0.00300000", // "isDislocationEnabled": true // }, // { // "feeTierId": "15", // "staticSpreadFee": "0.00500000", // "isDislocationEnabled": false // }, // { // "feeTierId": "16", // "staticSpreadFee": "0.00500000", // "isDislocationEnabled": true // }, // { // "feeTierId": "17", // "staticSpreadFee": "0.01000000", // "isDislocationEnabled": false // }, // { // "feeTierId": "18", // "staticSpreadFee": "0.01000000", // "isDislocationEnabled": true // }, // { // "feeTierId": "19", // "staticSpreadFee": "0.01500000", // "isDislocationEnabled": false // }, // { // "feeTierId": "2", // "staticSpreadFee": "0.00000000", // "isDislocationEnabled": true // }, // { // "feeTierId": "20", // "staticSpreadFee": "0.01500000", // "isDislocationEnabled": true // }, // { // "feeTierId": "21", // "staticSpreadFee": "0.02000000", // "isDislocationEnabled": false // }, // { // "feeTierId": "22", // "staticSpreadFee": "0.02000000", // "isDislocationEnabled": true // }, // { // "feeTierId": "3", // "staticSpreadFee": "0.00010000", // "isDislocationEnabled": false // }, // { // "feeTierId": "4", // "staticSpreadFee": "0.00010000", // "isDislocationEnabled": true // }, // { // "feeTierId": "5", // "staticSpreadFee": "0.00020000", // "isDislocationEnabled": false // }, // { // "feeTierId": "6", // "staticSpreadFee": "0.00020000", // "isDislocationEnabled": true // }, // { // "feeTierId": "7", // "staticSpreadFee": "0.00060000", // "isDislocationEnabled": false // }, // { // "feeTierId": "8", // "staticSpreadFee": "0.00060000", // "isDislocationEnabled": true // }, // { // "feeTierId": "9", // "staticSpreadFee": "0.00100000", // "isDislocationEnabled": false // } // ], // "marketType": "DATED_FUTURE", // "contractMultiplier": "1", // "settlementAssetSymbol": "USDC", // "underlyingQuoteSymbol": "USDC", // "underlyingBaseSymbol": "BTC", // "openInterestLimitUSD": "100000000.0000", // "concentrationRiskPercentage": "100.00", // "concentrationRiskThresholdUSD": "30000000.0000", // "expiryDatetime": "2025-05-16T08:00:00.000Z", // "priceBuffer": "0.1", // "feeGroupId": "4" // } // // option // { // "marketId": "20997", // "symbol": "BTC-USDC-20260130-160000-P", // "quoteAssetId": "5", // "baseAssetId": "1", // "quoteSymbol": "USDC", // "baseSymbol": "BTC", // "quotePrecision": "4", // "basePrecision": "8", // "pricePrecision": "4", // "quantityPrecision": "8", // "costPrecision": "4", // "minQuantityLimit": "0.00050000", // "maxQuantityLimit": "200.00000000", // "maxPriceLimit": null, // "minPriceLimit": null, // "maxCostLimit": null, // "minCostLimit": null, // "timeZone": "Etc/UTC", // "tickSize": "10.0000", // "makerFee": "0", // "takerFee": "2", // "roundingCorrectionFactor": "0.00000100", // "makerMinLiquidityAddition": "-1", // "orderTypes": [ "LMT", "MKT", "STOP_LIMIT", "POST_ONLY" ], // "spotTradingEnabled": true, // "marginTradingEnabled": true, // "marketEnabled": true, // "createOrderEnabled": true, // "cancelOrderEnabled": true, // "amendOrderEnabled": true, // "marketType": "OPTION", // "contractMultiplier": "1", // "settlementAssetSymbol": "USDC", // "underlyingQuoteSymbol": "USDC", // "underlyingBaseSymbol": "BTC", // "openInterestLimitUSD": "100000000.0000", // "concentrationRiskPercentage": "100.00", // "concentrationRiskThresholdUSD": "30000000.0000", // "expiryDatetime": "2026-01-30T08:00:00.000Z", // "priceBuffer": "0", // "feeGroupId": "10", // "optionStrikePrice": "160000.0000", // "optionType": "PUT", // "premiumCapRatio": "0.1000" // } // const id = this.safeString(market, 'symbol'); const baseId = this.safeString(market, 'baseSymbol'); const quoteId = this.safeString(market, 'quoteSymbol'); const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); let symbol = base + '/' + quote; const basePrecision = this.safeString(market, 'basePrecision'); const quotePrecision = this.safeString(market, 'quotePrecision'); const amountPrecision = this.safeString(market, 'quantityPrecision'); const pricePrecision = this.safeString(market, 'pricePrecision'); const costPrecision = this.safeString(market, 'costPrecision'); const minQuantityLimit = this.safeString(market, 'minQuantityLimit'); const maxQuantityLimit = this.safeString(market, 'maxQuantityLimit'); const minPriceLimit = this.safeString(market, 'minPriceLimit'); const maxPriceLimit = this.safeString(market, 'maxPriceLimit'); const minCostLimit = this.safeString(market, 'minCostLimit'); const maxCostLimit = this.safeString(market, 'maxCostLimit'); const settleId = this.safeString(market, 'settlementAssetSymbol'); const settle = this.safeCurrencyCode(settleId); const type = this.parseMarketType(this.safeString(market, 'marketType'), 'spot'); let spot = false; let swap = false; let future = false; let option = false; let contract = true; let linear = undefined; let inverse = undefined; let expiryDatetime = undefined; let contractSize = undefined; let optionType = undefined; let strike = undefined; let margin = false; if (type === 'spot') { spot = true; contract = false; margin = this.safeBool(market, 'marginTradingEnabled'); } else { contractSize = this.safeNumber(market, 'contractMultiplier'); symbol += ':' + settle; linear = settle === quote; inverse = !linear; if (type === 'swap') { swap = true; } else { expiryDatetime = this.safeString(market, 'expiryDatetime'); const idParts = id.split('-'); const datePart = this.safeString(idParts, 2); symbol += '-' + datePart; if (type === 'future') { future = true; } else if (type === 'option') { option = true; optionType = this.safeStringLower(market, 'optionType'); strike = this.parseToNumeric(this.safeString(market, 'optionStrikePrice')); symbol += '-' + this.numberToString(strike) + '-' + this.safeString(idParts, 4); } } } return this.safeMarketStructure({ 'id': id, 'symbol': symbol, 'base': base, 'baseId': baseId, 'quote': quote, 'quoteId': quoteId, 'settle': settle, 'settleId': settleId, 'type': type, 'spot': spot, 'margin': margin, 'swap': swap, 'future': future, 'option': option, 'contract': contract, 'linear': linear, 'inverse': inverse, 'taker': this.fees['trading']['taker'], 'maker': this.fees['trading']['maker'], 'contractSize': contractSize, 'expiry': this.parse8601(expiryDatetime), 'expiryDatetime': expiryDatetime, 'strike': strike, 'optionType': optionType, 'limits': { 'amount': { 'min': this.parseNumber(minQuantityLimit), 'max': this.parseNumber(maxQuantityLimit), }, 'price': { 'min': this.parseNumber(minPriceLimit), 'max': this.parseNumber(maxPriceLimit), }, 'cost': { 'min': this.parseNumber(minCostLimit), 'max': this.parseNumber(maxCostLimit), }, 'leverage': { 'min': undefined, 'max': undefined, }, }, 'precision': { 'amount': this.parseNumber(this.parsePrecision(amountPrecision)), 'price': this.parseNumber(this.parsePrecision(pricePrecision)), 'cost': this.parseNumber(this.parsePrecision(costPrecision)), 'base': this.parseNumber(this.parsePrecision(basePrecision)), 'quote': this.parseNumber(this.parsePrecision(quotePrecision)), }, 'active': this.safeBool(market, 'marketEnabled'), 'created': undefined, 'info': market, }); } parseMarketType(type, defaultType = undefined) { const types = { 'SPOT': 'spot', 'PERPETUAL': 'swap', 'DATED_FUTURE': 'future', 'OPTION': 'option', }; return this.safeString(types, type, defaultType); } /** * @method * @name bullish#fetchOrderBook * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @see https://api.exchange.bullish.com/docs/api/rest/trading-api/v2/#get-/v1/markets/-symbol-/orderbook/hybrid * @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 (not used by bullish) * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/?id=order-book-structure} indexed by market symbols */ async fetchOrderBook(symbol, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], }; const response = await this.publicGetV1MarketsSymbolOrderbookHybrid(this.extend(request, params)); // // { // "bids": [ // { // "price": "1.00000000", // "priceLevelQuantity": "1.00000000" // } // ], // "asks": [ // { // "price": "1.00000000", // "priceLevelQuantity": "1.00000000" // } // ], // "datetime": "2021-05-20T01:01:01.000Z", // "timestamp": "1621490985000", // "sequenceNumber": 999 // } // const timestamp = this.safeInteger(response, 'timestamp'); return this.parseOrderBook(response, symbol, timestamp, 'bids', 'asks', 'price', 'priceLevelQuantity'); } /** * @method * @name bullish#fetchTrades * @description get the list of most recent trades for a particular symbol * @see https://api.exchange.bullish.com/docs/api/rest/trading-api/v2/#get-/v1/markets/-symbol-/trades * @see https://api.exchange.bullish.com/docs/api/rest/trading-api/v2/#get-/v1/history/markets/-symbol-/trades * @param {string} symbol unified symbol of the market to fetch trades for * @param {int} [since] timestamp in ms of the earliest trade to fetch * @param {int} [limit] the maximum amount of trades to fetch (max 100) * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {int} [params.until] timestamp in ms of the latest trade 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 [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) * @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 maxLimit = 100; let paginate = false; [paginate, params] = this.handleOptionAndParams(params, 'fetchFundingRateHistory', 'paginate'); if (paginate) { params = this.handlePaginationParams('fetchTrades', since, params); return await this.fetchPaginatedCallDynamic('fetchTrades', symbol, since, limit, params, maxLimit); } const market = this.market(symbol); const request = { 'symbol': market['id'], }; params = this.handleSinceAndUntil(since, params); if (limit !== undefined) { request['_pageSize'] = this.getClosestLimit(limit); } const response = await this.publicGetV1HistoryMarketsSymbolTrades(this.extend(request, params)); // // [ // { // "tradeId": "100178000000367159", // "symbol": "BTCUSDC", // "price": "103891.8977", // "quantity": "0.00029411", // "quoteAmount": "30.5556", // "side": "BUY", // "isTaker": true, // "createdAtTimestamp": "1747768055826", // "createdAtDatetime": "2025-05-20T19:07:35.826Z" // }, ... // ] // return this.parseTrades(response, market, since, limit); } /** * @method * @name bullish#fetchMyTrades * @description fetch all trades made by the user * @see https://api.exchange.bullish.com/docs/api/rest/trading-api/v2/#get-/v1/history/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 * @param {int} [params.until] the latest time in ms to fetch trades for * @param {string} [params.orderId] the order id to fetch trades for * @param {string} [params.clientOrderId] the client order id to fetch trades for * @param {string} [params.tradingAccountId] the trading account id to fetch trades for * @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 Promise.all([this.loadMarkets(), this.handleToken()]); const tradingAccountId = await this.loadAccount(params); const request = { 'tradingAccountId': tradingAccountId, }; let market = undefined; if (symbol !== undefined) { market = this.market(symbol); request['symbol'] = market['id']; } const clientOrderId = this.safeString(params, 'clientOrderId'); let response = undefined; if (clientOrderId !== undefined) { response = await this.privateGetV1TradesClientOrderIdClientOrderId(this.extend(request, params)); } else { let paginate = false; [paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate'); if (paginate) { params = this.handlePaginationParams('fetchMyTrades', since, params); return await this.fetchPaginatedCallDynamic('fetchMyTrades', symbol, since, limit, params, 100); } params = this.handleSinceAndUntil(since, params); if (limit !== undefined) { request['_pageSize'] = this.getClosestLimit(limit); } // // [ // { // "baseFee": "0.00000000", // "createdAtDatetime": "2025-05-18T15:57:28.132Z", // "createdAtTimestamp": "1747583848132", // "handle": null, // "isTaker": true, // "orderId": "844242293909618689", // "price": "103942.7048", // "publishedAtTimestamp": "1747769786131", // "quantity": "1.00000000", // "quoteAmount": "103942.7048", // "quoteFee": "0.0000", // "side": "BUY", // "symbol": "BTCUSDC", // "tradeId": "100178000000288892" // }, ... // ] // response = await this.privateGetV1HistoryTrades(this.extend(request, params)); } return this.parseTrades(response, market, since, limit); } /** * @method * @name bullish#fetchOrderTrades * @description fetch all the trades made from a single order * @see https://api.exchange.bullish.com/docs/api/rest/trading-api/v2/#get-/v1/history/trades * @param {string} id order id * @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 to retrieve * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.clientOrderId] the client order id to fetch trades for * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=trade-structure} */ async fetchOrderTrades(id, symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const clientOrderId = this.safeString(params, 'clientOrderId'); if (clientOrderId === undefined) { params = this.extend({ 'orderId': id }, params); } return await this.fetchMyTrades(symbol, since, limit, params); } parseTrade(trade, market = undefined) { // // fetchTrades // [ // { // "tradeId": "100178000000367159", // "symbol": "BTCUSDC", // "price": "103891.8977", // "quantity": "0.00029411", // "quoteAmount": "30.5556", // "side": "BUY", // "isTaker": true, // "createdAtTimestamp": "1747768055826", // "createdAtDatetime": "2025-05-20T19:07:35.826Z" // }, ... // ] // // [ // { // "tradeId": "100020000000000060", // "symbol": "BTCUSDC", // "price": "1.00000000", // "quantity": "1.00000000", // "side": "BUY", // "isTaker": true, // "createdAtDatetime": "2021-05-20T01:01:01.000Z", // "createdAtTimestamp": "1621490985000" // } // ] // // fetchMyTrades // [ // { // "baseFee": "0.00000000", // "createdAtDatetime": "2025-05-18T15:57:28.132Z", // "createdAtTimestamp": "1747583848132", // "handle": null, // "isTaker": true, // "orderId": "844242293909618689", // "price": "103942.7048", // "publishedAtTimestamp": "1747769786131", // "quantity": "1.00000000", // "quoteAmount": "103942.7048", // "quoteFee": "0.0000", // "side": "BUY", // "symbol": "BTCUSDC", // "tradeId": "100178000000288892" // }, ... // ] // const marketId = this.safeString(trade, 'symbol'); market = this.safeMarket(marketId, market); const symbol = market['symbol']; const timestamp = this.safeInteger(trade, 'createdAtTimestamp'); const price = this.safeString(trade, 'price'); const amount = this.safeString(trade, 'quantity'); cons