UNPKG

ccxt

Version:

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

1,181 lines (1,178 loc) • 102 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/bitstamp.js'; import { AuthenticationError, BadRequest, ExchangeError, NotSupported, PermissionDenied, InvalidNonce, OrderNotFound, InsufficientFunds, InvalidAddress, InvalidOrder, OnMaintenance, ExchangeNotAvailable } from './base/errors.js'; import { Precise } from './base/Precise.js'; import { TICK_SIZE } from './base/functions/number.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; // --------------------------------------------------------------------------- /** * @class bitstamp * @augments Exchange */ export default class bitstamp extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'bitstamp', 'name': 'Bitstamp', 'countries': ['GB'], // 8000 requests per 10 minutes = 8000 / 600 = 13.33333333 requests per second => 1000ms / 13.33333333 = 75ms between requests on average 'rateLimit': 75, 'version': 'v2', 'userAgent': this.userAgents['chrome'], 'pro': true, 'has': { 'CORS': true, 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'addMargin': false, 'borrowCrossMargin': false, 'borrowIsolatedMargin': false, 'borrowMargin': false, 'cancelAllOrders': true, 'cancelOrder': true, 'closeAllPositions': false, 'closePosition': false, 'createOrder': true, 'createOrderWithTakeProfitAndStopLoss': false, 'createOrderWithTakeProfitAndStopLossWs': false, 'createReduceOnlyOrder': false, 'createStopLimitOrder': false, 'createStopMarketOrder': false, 'createStopOrder': false, 'fetchBalance': true, 'fetchBorrowInterest': false, 'fetchBorrowRate': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchBorrowRates': false, 'fetchBorrowRatesPerSymbol': false, 'fetchCrossBorrowRate': false, 'fetchCrossBorrowRates': false, 'fetchCurrencies': true, 'fetchDepositAddress': true, 'fetchDepositAddresses': false, 'fetchDepositAddressesByNetwork': false, 'fetchDepositsWithdrawals': true, 'fetchDepositWithdrawFee': 'emulated', 'fetchDepositWithdrawFees': true, 'fetchFundingHistory': false, 'fetchFundingInterval': false, 'fetchFundingIntervals': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': false, 'fetchFundingRates': false, 'fetchGreeks': false, 'fetchIndexOHLCV': false, 'fetchIsolatedBorrowRate': false, 'fetchIsolatedBorrowRates': false, 'fetchIsolatedPositions': false, 'fetchLedger': true, 'fetchLeverage': false, 'fetchLeverages': false, 'fetchLeverageTiers': false, 'fetchLiquidations': false, 'fetchLongShortRatio': false, 'fetchLongShortRatioHistory': false, 'fetchMarginAdjustmentHistory': false, 'fetchMarginMode': false, 'fetchMarginModes': false, 'fetchMarketLeverageTiers': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMarkPrices': false, 'fetchMyLiquidations': false, 'fetchMySettlementHistory': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenInterest': false, 'fetchOpenInterestHistory': false, 'fetchOpenInterests': false, 'fetchOpenOrders': true, 'fetchOption': false, 'fetchOptionChain': false, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchPosition': false, 'fetchPositionHistory': false, 'fetchPositionMode': false, 'fetchPositions': false, 'fetchPositionsForSymbol': false, 'fetchPositionsHistory': false, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchSettlementHistory': false, 'fetchTicker': true, 'fetchTickers': true, 'fetchTrades': true, 'fetchTradingFee': true, 'fetchTradingFees': true, 'fetchTransactionFees': true, 'fetchTransactions': 'emulated', 'fetchVolatilityHistory': false, 'fetchWithdrawals': true, 'reduceMargin': false, 'repayCrossMargin': false, 'repayIsolatedMargin': false, 'setLeverage': false, 'setMargin': false, 'setMarginMode': false, 'setPositionMode': false, 'transfer': true, 'withdraw': true, }, 'urls': { 'logo': 'https://github.com/user-attachments/assets/d5480572-1fee-43cb-b900-d38c522d0024', 'api': { 'public': 'https://www.bitstamp.net/api', 'private': 'https://www.bitstamp.net/api', }, 'www': 'https://www.bitstamp.net', 'doc': 'https://www.bitstamp.net/api', }, 'timeframes': { '1m': '60', '3m': '180', '5m': '300', '15m': '900', '30m': '1800', '1h': '3600', '2h': '7200', '4h': '14400', '6h': '21600', '12h': '43200', '1d': '86400', '1w': '259200', }, 'requiredCredentials': { 'apiKey': true, 'secret': true, }, 'api': { 'public': { 'get': { 'ohlc/{pair}/': 1, 'order_book/{pair}/': 1, 'ticker/': 1, 'ticker_hour/{pair}/': 1, 'ticker/{pair}/': 1, 'transactions/{pair}/': 1, 'trading-pairs-info/': 1, 'currencies/': 1, 'eur_usd/': 1, 'travel_rule/vasps/': 1, }, }, 'private': { 'get': { 'travel_rule/contacts/': 1, 'contacts/{contact_uuid}/': 1, 'earn/subscriptions/': 1, 'earn/transactions/': 1, }, 'post': { 'account_balances/': 1, 'account_balances/{currency}/': 1, 'balance/': 1, 'balance/{pair}/': 1, 'bch_withdrawal/': 1, 'bch_address/': 1, 'user_transactions/': 1, 'user_transactions/{pair}/': 1, 'crypto-transactions/': 1, 'open_order': 1, 'open_orders/all/': 1, 'open_orders/{pair}/': 1, 'order_status/': 1, 'cancel_order/': 1, 'cancel_all_orders/': 1, 'cancel_all_orders/{pair}/': 1, 'buy/{pair}/': 1, 'buy/market/{pair}/': 1, 'buy/instant/{pair}/': 1, 'sell/{pair}/': 1, 'sell/market/{pair}/': 1, 'sell/instant/{pair}/': 1, 'transfer-to-main/': 1, 'transfer-from-main/': 1, 'my_trading_pairs/': 1, 'fees/trading/': 1, 'fees/trading/{market_symbol}': 1, 'fees/withdrawal/': 1, 'fees/withdrawal/{currency}/': 1, 'withdrawal-requests/': 1, 'withdrawal/open/': 1, 'withdrawal/status/': 1, 'withdrawal/cancel/': 1, 'liquidation_address/new/': 1, 'liquidation_address/info/': 1, 'btc_unconfirmed/': 1, 'websockets_token/': 1, // individual coins 'btc_withdrawal/': 1, 'btc_address/': 1, 'ripple_withdrawal/': 1, 'ripple_address/': 1, 'ltc_withdrawal/': 1, 'ltc_address/': 1, 'eth_withdrawal/': 1, 'eth_address/': 1, 'xrp_withdrawal/': 1, 'xrp_address/': 1, 'xlm_withdrawal/': 1, 'xlm_address/': 1, 'pax_withdrawal/': 1, 'pax_address/': 1, 'link_withdrawal/': 1, 'link_address/': 1, 'usdc_withdrawal/': 1, 'usdc_address/': 1, 'omg_withdrawal/': 1, 'omg_address/': 1, 'dai_withdrawal/': 1, 'dai_address/': 1, 'knc_withdrawal/': 1, 'knc_address/': 1, 'mkr_withdrawal/': 1, 'mkr_address/': 1, 'zrx_withdrawal/': 1, 'zrx_address/': 1, 'gusd_withdrawal/': 1, 'gusd_address/': 1, 'aave_withdrawal/': 1, 'aave_address/': 1, 'bat_withdrawal/': 1, 'bat_address/': 1, 'uma_withdrawal/': 1, 'uma_address/': 1, 'snx_withdrawal/': 1, 'snx_address/': 1, 'uni_withdrawal/': 1, 'uni_address/': 1, 'yfi_withdrawal/': 1, 'yfi_address/': 1, 'audio_withdrawal/': 1, 'audio_address/': 1, 'crv_withdrawal/': 1, 'crv_address/': 1, 'algo_withdrawal/': 1, 'algo_address/': 1, 'comp_withdrawal/': 1, 'comp_address/': 1, 'grt_withdrawal/': 1, 'grt_address/': 1, 'usdt_withdrawal/': 1, 'usdt_address/': 1, 'eurt_withdrawal/': 1, 'eurt_address/': 1, 'matic_withdrawal/': 1, 'matic_address/': 1, 'sushi_withdrawal/': 1, 'sushi_address/': 1, 'chz_withdrawal/': 1, 'chz_address/': 1, 'enj_withdrawal/': 1, 'enj_address/': 1, 'alpha_withdrawal/': 1, 'alpha_address/': 1, 'ftt_withdrawal/': 1, 'ftt_address/': 1, 'storj_withdrawal/': 1, 'storj_address/': 1, 'axs_withdrawal/': 1, 'axs_address/': 1, 'sand_withdrawal/': 1, 'sand_address/': 1, 'hbar_withdrawal/': 1, 'hbar_address/': 1, 'rgt_withdrawal/': 1, 'rgt_address/': 1, 'fet_withdrawal/': 1, 'fet_address/': 1, 'skl_withdrawal/': 1, 'skl_address/': 1, 'cel_withdrawal/': 1, 'cel_address/': 1, 'sxp_withdrawal/': 1, 'sxp_address/': 1, 'ada_withdrawal/': 1, 'ada_address/': 1, 'slp_withdrawal/': 1, 'slp_address/': 1, 'ftm_withdrawal/': 1, 'ftm_address/': 1, 'perp_withdrawal/': 1, 'perp_address/': 1, 'dydx_withdrawal/': 1, 'dydx_address/': 1, 'gala_withdrawal/': 1, 'gala_address/': 1, 'shib_withdrawal/': 1, 'shib_address/': 1, 'amp_withdrawal/': 1, 'amp_address/': 1, 'sgb_withdrawal/': 1, 'sgb_address/': 1, 'avax_withdrawal/': 1, 'avax_address/': 1, 'wbtc_withdrawal/': 1, 'wbtc_address/': 1, 'ctsi_withdrawal/': 1, 'ctsi_address/': 1, 'cvx_withdrawal/': 1, 'cvx_address/': 1, 'imx_withdrawal/': 1, 'imx_address/': 1, 'nexo_withdrawal/': 1, 'nexo_address/': 1, 'ust_withdrawal/': 1, 'ust_address/': 1, 'ant_withdrawal/': 1, 'ant_address/': 1, 'gods_withdrawal/': 1, 'gods_address/': 1, 'rad_withdrawal/': 1, 'rad_address/': 1, 'band_withdrawal/': 1, 'band_address/': 1, 'inj_withdrawal/': 1, 'inj_address/': 1, 'rly_withdrawal/': 1, 'rly_address/': 1, 'rndr_withdrawal/': 1, 'rndr_address/': 1, 'vega_withdrawal/': 1, 'vega_address/': 1, '1inch_withdrawal/': 1, '1inch_address/': 1, 'ens_withdrawal/': 1, 'ens_address/': 1, 'mana_withdrawal/': 1, 'mana_address/': 1, 'lrc_withdrawal/': 1, 'lrc_address/': 1, 'ape_withdrawal/': 1, 'ape_address/': 1, 'mpl_withdrawal/': 1, 'mpl_address/': 1, 'euroc_withdrawal/': 1, 'euroc_address/': 1, 'sol_withdrawal/': 1, 'sol_address/': 1, 'dot_withdrawal/': 1, 'dot_address/': 1, 'near_withdrawal/': 1, 'near_address/': 1, 'doge_withdrawal/': 1, 'doge_address/': 1, 'flr_withdrawal/': 1, 'flr_address/': 1, 'dgld_withdrawal/': 1, 'dgld_address/': 1, 'ldo_withdrawal/': 1, 'ldo_address/': 1, 'travel_rule/contacts/': 1, 'earn/subscribe/': 1, 'earn/subscriptions/setting/': 1, 'earn/unsubscribe': 1, 'wecan_withdrawal/': 1, 'wecan_address/': 1, 'trac_withdrawal/': 1, 'trac_address/': 1, 'eurcv_withdrawal/': 1, 'eurcv_address/': 1, 'pyusd_withdrawal/': 1, 'pyusd_address/': 1, 'lmwr_withdrawal/': 1, 'lmwr_address/': 1, 'pepe_withdrawal/': 1, 'pepe_address/': 1, 'blur_withdrawal/': 1, 'blur_address/': 1, 'vext_withdrawal/': 1, 'vext_address/': 1, 'cspr_withdrawal/': 1, 'cspr_address/': 1, 'vchf_withdrawal/': 1, 'vchf_address/': 1, 'veur_withdrawal/': 1, 'veur_address/': 1, 'truf_withdrawal/': 1, 'truf_address/': 1, 'wif_withdrawal/': 1, 'wif_address/': 1, 'smt_withdrawal/': 1, 'smt_address/': 1, 'sui_withdrawal/': 1, 'sui_address/': 1, 'jup_withdrawal/': 1, 'jup_address/': 1, 'ondo_withdrawal/': 1, 'ondo_address/': 1, 'boba_withdrawal/': 1, 'boba_address/': 1, 'pyth_withdrawal/': 1, 'pyth_address/': 1, }, }, }, 'fees': { 'trading': { 'tierBased': true, 'percentage': true, 'taker': this.parseNumber('0.004'), 'maker': this.parseNumber('0.004'), 'tiers': { 'taker': [ [this.parseNumber('0'), this.parseNumber('0.004')], [this.parseNumber('10000'), this.parseNumber('0.003')], [this.parseNumber('100000'), this.parseNumber('0.002')], [this.parseNumber('500000'), this.parseNumber('0.0018')], [this.parseNumber('1500000'), this.parseNumber('0.0016')], [this.parseNumber('5000000'), this.parseNumber('0.0012')], [this.parseNumber('20000000'), this.parseNumber('0.001')], [this.parseNumber('50000000'), this.parseNumber('0.0008')], [this.parseNumber('100000000'), this.parseNumber('0.0006')], [this.parseNumber('250000000'), this.parseNumber('0.0005')], [this.parseNumber('1000000000'), this.parseNumber('0.0003')], ], 'maker': [ [this.parseNumber('0'), this.parseNumber('0.003')], [this.parseNumber('10000'), this.parseNumber('0.002')], [this.parseNumber('100000'), this.parseNumber('0.001')], [this.parseNumber('500000'), this.parseNumber('0.0008')], [this.parseNumber('1500000'), this.parseNumber('0.0006')], [this.parseNumber('5000000'), this.parseNumber('0.0003')], [this.parseNumber('20000000'), this.parseNumber('0.002')], [this.parseNumber('50000000'), this.parseNumber('0.0001')], [this.parseNumber('100000000'), this.parseNumber('0')], [this.parseNumber('250000000'), this.parseNumber('0')], [this.parseNumber('1000000000'), this.parseNumber('0')], ], }, }, 'funding': { 'tierBased': false, 'percentage': false, 'withdraw': {}, 'deposit': { 'BTC': 0, 'BCH': 0, 'LTC': 0, 'ETH': 0, 'XRP': 0, 'XLM': 0, 'PAX': 0, 'USD': 7.5, 'EUR': 0, }, }, }, 'precisionMode': TICK_SIZE, 'commonCurrencies': { 'UST': 'USTC', }, // exchange-specific options 'options': { 'networksById': { 'bitcoin-cash': 'BCH', 'bitcoin': 'BTC', 'ethereum': 'ERC20', 'litecoin': 'LTC', 'stellar': 'XLM', 'xrpl': 'XRP', 'tron': 'TRC20', 'algorand': 'ALGO', 'flare': 'FLR', 'hedera': 'HBAR', 'cardana': 'ADA', 'songbird': 'FLR', 'avalanche-c-chain': 'AVAX', 'solana': 'SOL', 'polkadot': 'DOT', 'near': 'NEAR', 'doge': 'DOGE', 'sui': 'SUI', 'casper': 'CSRP', }, }, 'exceptions': { 'exact': { 'No permission found': PermissionDenied, 'API key not found': AuthenticationError, 'IP address not allowed': PermissionDenied, 'Invalid nonce': InvalidNonce, 'Invalid signature': AuthenticationError, 'Authentication failed': AuthenticationError, 'Missing key, signature and nonce parameters': AuthenticationError, 'Wrong API key format': AuthenticationError, 'Your account is frozen': PermissionDenied, 'Please update your profile with your FATCA information, before using API.': PermissionDenied, 'Order not found.': OrderNotFound, 'Price is more than 20% below market price.': InvalidOrder, "Bitstamp.net is under scheduled maintenance. We'll be back soon.": OnMaintenance, 'Order could not be placed.': ExchangeNotAvailable, 'Invalid offset.': BadRequest, }, 'broad': { 'Minimum order size is': InvalidOrder, 'Check your account balance for details.': InsufficientFunds, 'Ensure this value has at least': InvalidAddress, 'Ensure that there are no more than': InvalidOrder, // {"status": "error", "reason": {"amount": ["Ensure that there are no more than 0 decimal places."], "__all__": [""]}} }, }, 'features': { 'spot': { 'sandbox': false, 'createOrder': { 'marginMode': false, 'triggerPrice': false, 'triggerPriceType': undefined, 'triggerDirection': false, 'stopLossPrice': false, 'takeProfitPrice': false, 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': true, 'FOK': true, 'PO': true, 'GTD': true, }, 'hedged': false, 'trailing': false, 'leverage': false, 'marketBuyByCost': false, 'marketBuyRequiresPrice': false, 'selfTradePrevention': false, 'iceberg': false, }, 'createOrders': undefined, 'fetchMyTrades': { 'marginMode': false, 'limit': 1000, 'daysBack': undefined, 'untilDays': 30, 'symbolRequired': false, }, 'fetchOrder': { 'marginMode': false, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOpenOrders': { 'marginMode': false, 'limit': undefined, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOrders': undefined, 'fetchClosedOrders': undefined, 'fetchOHLCV': { 'limit': 1000, }, }, 'swap': { 'linear': undefined, 'inverse': undefined, }, 'future': { 'linear': undefined, 'inverse': undefined, }, }, }); } /** * @method * @name bitstamp#fetchMarkets * @description retrieves data on all markets for bitstamp * @see https://www.bitstamp.net/api/#tag/Market-info/operation/GetTradingPairsInfo * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} an array of objects representing market data */ async fetchMarkets(params = {}) { const response = await this.fetchMarketsFromCache(params); // // [ // { // "trading": "Enabled", // "base_decimals": 8, // "url_symbol": "btcusd", // "name": "BTC/USD", // "instant_and_market_orders": "Enabled", // "minimum_order": "20.0 USD", // "counter_decimals": 2, // "description": "Bitcoin / U.S. dollar" // } // ] // const result = []; for (let i = 0; i < response.length; i++) { const market = response[i]; const name = this.safeString(market, 'name'); let [base, quote] = name.split('/'); const baseId = base.toLowerCase(); const quoteId = quote.toLowerCase(); base = this.safeCurrencyCode(base); quote = this.safeCurrencyCode(quote); const minimumOrder = this.safeString(market, 'minimum_order'); const parts = minimumOrder.split(' '); const status = this.safeString(market, 'trading'); result.push({ 'id': this.safeString(market, 'url_symbol'), 'marketId': baseId + '_' + quoteId, 'symbol': base + '/' + quote, 'base': base, 'quote': quote, 'settle': undefined, 'baseId': baseId, 'quoteId': quoteId, 'settleId': undefined, 'type': 'spot', 'spot': true, 'margin': false, 'future': false, 'swap': false, 'option': false, 'active': (status === 'Enabled'), 'contract': false, 'linear': undefined, 'inverse': undefined, 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.parseNumber(this.parsePrecision(this.safeString(market, 'base_decimals'))), 'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'counter_decimals'))), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': undefined, 'max': undefined, }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': this.safeNumber(parts, 0), 'max': undefined, }, }, 'created': undefined, 'info': market, }); } return result; } constructCurrencyObject(id, code, name, precision, minCost, originalPayload) { let currencyType = 'crypto'; const description = this.describe(); if (this.isFiat(code)) { currencyType = 'fiat'; } const tickSize = this.parseNumber(this.parsePrecision(this.numberToString(precision))); return { 'id': id, 'code': code, 'info': originalPayload, 'type': currencyType, 'name': name, 'active': true, 'deposit': undefined, 'withdraw': undefined, 'fee': this.safeNumber(description['fees']['funding']['withdraw'], code), 'precision': tickSize, 'limits': { 'amount': { 'min': tickSize, 'max': undefined, }, 'price': { 'min': tickSize, 'max': undefined, }, 'cost': { 'min': minCost, 'max': undefined, }, 'withdraw': { 'min': undefined, 'max': undefined, }, }, 'networks': {}, }; } async fetchMarketsFromCache(params = {}) { // this method is now redundant // currencies are now fetched before markets const options = this.safeValue(this.options, 'fetchMarkets', {}); const timestamp = this.safeInteger(options, 'timestamp'); const expires = this.safeInteger(options, 'expires', 1000); const now = this.milliseconds(); if ((timestamp === undefined) || ((now - timestamp) > expires)) { const response = await this.publicGetTradingPairsInfo(params); this.options['fetchMarkets'] = this.extend(options, { 'response': response, 'timestamp': now, }); } return this.safeValue(this.options['fetchMarkets'], 'response'); } /** * @method * @name bitstamp#fetchCurrencies * @description fetches all available currencies on an exchange * @see https://www.bitstamp.net/api/#tag/Market-info/operation/GetTradingPairsInfo * @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.fetchMarketsFromCache(params); // // [ // { // "trading": "Enabled", // "base_decimals": 8, // "url_symbol": "btcusd", // "name": "BTC/USD", // "instant_and_market_orders": "Enabled", // "minimum_order": "20.0 USD", // "counter_decimals": 2, // "description": "Bitcoin / U.S. dollar" // }, // ] // const result = {}; for (let i = 0; i < response.length; i++) { const market = response[i]; const name = this.safeString(market, 'name'); let [base, quote] = name.split('/'); const baseId = base.toLowerCase(); const quoteId = quote.toLowerCase(); base = this.safeCurrencyCode(base); quote = this.safeCurrencyCode(quote); const description = this.safeString(market, 'description'); const [baseDescription, quoteDescription] = description.split(' / '); const minimumOrder = this.safeString(market, 'minimum_order'); const parts = minimumOrder.split(' '); const cost = parts[0]; if (!(base in result)) { const baseDecimals = this.safeInteger(market, 'base_decimals'); result[base] = this.constructCurrencyObject(baseId, base, baseDescription, baseDecimals, undefined, market); } if (!(quote in result)) { const counterDecimals = this.safeInteger(market, 'counter_decimals'); result[quote] = this.constructCurrencyObject(quoteId, quote, quoteDescription, counterDecimals, this.parseNumber(cost), market); } } return result; } /** * @method * @name bitstamp#fetchOrderBook * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @see https://www.bitstamp.net/api/#tag/Order-book/operation/GetOrderBook * @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 * @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 = { 'pair': market['id'], }; const response = await this.publicGetOrderBookPair(this.extend(request, params)); // // { // "timestamp": "1583652948", // "microtimestamp": "1583652948955826", // "bids": [ // [ "8750.00", "1.33685271" ], // [ "8749.39", "0.07700000" ], // [ "8746.98", "0.07400000" ], // ] // "asks": [ // [ "8754.10", "1.51995636" ], // [ "8754.71", "1.40000000" ], // [ "8754.72", "2.50000000" ], // ] // } // const microtimestamp = this.safeInteger(response, 'microtimestamp'); const timestamp = this.parseToInt(microtimestamp / 1000); const orderbook = this.parseOrderBook(response, market['symbol'], timestamp); orderbook['nonce'] = microtimestamp; return orderbook; } parseTicker(ticker, market = undefined) { // // { // "timestamp": "1686068944", // "high": "26252", // "last": "26216", // "bid": "26208", // "vwap": "25681", // "volume": "3563.13819902", // "low": "25350", // "ask": "26211", // "open": "25730", // "open_24": "25895", // "percent_change_24": "1.24", // "pair": "BTC/USD" // } // const marketId = this.safeString(ticker, 'pair'); const symbol = this.safeSymbol(marketId, market, undefined); const timestamp = this.safeTimestamp(ticker, 'timestamp'); const vwap = this.safeString(ticker, 'vwap'); const baseVolume = this.safeString(ticker, 'volume'); const quoteVolume = Precise.stringMul(baseVolume, vwap); const last = this.safeString(ticker, 'last'); return this.safeTicker({ 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'high': this.safeString(ticker, 'high'), 'low': this.safeString(ticker, 'low'), 'bid': this.safeString(ticker, 'bid'), 'bidVolume': undefined, 'ask': this.safeString(ticker, 'ask'), 'askVolume': undefined, 'vwap': vwap, 'open': this.safeString(ticker, 'open'), 'close': last, 'last': last, 'previousClose': undefined, 'change': undefined, 'percentage': undefined, 'average': undefined, 'baseVolume': baseVolume, 'quoteVolume': quoteVolume, 'info': ticker, }, market); } /** * @method * @name bitstamp#fetchTicker * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market * @see https://www.bitstamp.net/api/#tag/Tickers/operation/GetMarketTicker * @param {string} symbol unified symbol of the market to fetch the ticker for * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ async fetchTicker(symbol, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'pair': market['id'], }; const ticker = await this.publicGetTickerPair(this.extend(request, params)); // // { // "timestamp": "1686068944", // "high": "26252", // "last": "26216", // "bid": "26208", // "vwap": "25681", // "volume": "3563.13819902", // "low": "25350", // "ask": "26211", // "open": "25730", // "open_24": "25895", // "percent_change_24": "1.24" // } // return this.parseTicker(ticker, market); } /** * @method * @name bitstamp#fetchTickers * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market * @see https://www.bitstamp.net/api/#tag/Tickers/operation/GetCurrencyPairTickers * @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ async fetchTickers(symbols = undefined, params = {}) { await this.loadMarkets(); const response = await this.publicGetTicker(params); // // { // "timestamp": "1686068944", // "high": "26252", // "last": "26216", // "bid": "26208", // "vwap": "25681", // "volume": "3563.13819902", // "low": "25350", // "ask": "26211", // "open": "25730", // "open_24": "25895", // "percent_change_24": "1.24", // "pair": "BTC/USD" // } // return this.parseTickers(response, symbols); } getCurrencyIdFromTransaction(transaction) { // // { // "fee": "0.00000000", // "btc_usd": "0.00", // "datetime": XXX, // "usd": 0.0, // "btc": 0.0, // "eth": "0.05000000", // "type": "0", // "id": XXX, // "eur": 0.0 // } // const currencyId = this.safeStringLower(transaction, 'currency'); if (currencyId !== undefined) { return currencyId; } transaction = this.omit(transaction, [ 'fee', 'price', 'datetime', 'type', 'status', 'id', ]); const ids = Object.keys(transaction); for (let i = 0; i < ids.length; i++) { const id = ids[i]; if (id.indexOf('_') < 0) { const value = this.safeInteger(transaction, id); if ((value !== undefined) && (value !== 0)) { return id; } } } return undefined; } getMarketFromTrade(trade) { trade = this.omit(trade, [ 'fee', 'price', 'datetime', 'tid', 'type', 'order_id', 'side', ]); const currencyIds = Object.keys(trade); const numCurrencyIds = currencyIds.length; if (numCurrencyIds > 2) { throw new ExchangeError(this.id + ' getMarketFromTrade() too many keys: ' + this.json(currencyIds) + ' in the trade: ' + this.json(trade)); } if (numCurrencyIds === 2) { let marketId = currencyIds[0] + currencyIds[1]; if (marketId in this.markets_by_id) { return this.safeMarket(marketId); } marketId = currencyIds[1] + currencyIds[0]; if (marketId in this.markets_by_id) { return this.safeMarket(marketId); } } return undefined; } parseTrade(trade, market = undefined) { // // fetchTrades (public) // // { // "date": "1637845199", // "tid": "209895701", // "amount": "0.00500000", // "type": "0", // Transaction type: 0 - buy; 1 - sell // "price": "4451.25" // } // // fetchMyTrades, trades returned within fetchOrder (private) // // { // "fee": "0.11128", // "eth_usdt": 4451.25, // "datetime": "2021-11-25 12:59:59.322000", // "usdt": "-22.26", // "order_id": 1429545880227846, // "usd": 0, // "btc": 0, // "eth": "0.00500000", // "type": "2", // Transaction type: 0 - deposit; 1 - withdrawal; 2 - market trade; 14 - sub account transfer; 25 - credited with staked assets; 26 - sent assets to staking; 27 - staking reward; 32 - referral reward; 35 - inter account transfer. // "id": 209895701, // "eur": 0 // } // // from fetchOrder (private) // // { // "fee": "0.11128", // "price": "4451.25000000", // "datetime": "2021-11-25 12:59:59.322000", // "usdt": "22.25625000", // "tid": 209895701, // "eth": "0.00500000", // "type": 2 // Transaction type: 0 - deposit; 1 - withdrawal; 2 - market trade // } // const id = this.safeString2(trade, 'id', 'tid'); let symbol = undefined; let side = undefined; let priceString = this.safeString(trade, 'price'); let amountString = this.safeString(trade, 'amount'); const orderId = this.safeString(trade, 'order_id'); const type = undefined; let costString = this.safeString(trade, 'cost'); let rawMarketId = undefined; if (market === undefined) { const keys = Object.keys(trade); for (let i = 0; i < keys.length; i++) { const currentKey = keys[i]; if (currentKey !== 'order_id' && currentKey.indexOf('_') >= 0) { rawMarketId = currentKey; market = this.safeMarket(rawMarketId, market, '_'); } } } // if the market is still not defined // try to deduce it from used keys if (market === undefined) { market = this.getMarketFromTrade(trade); } const feeCostString = this.safeString(trade, 'fee'); const feeCurrency = market['quote']; const priceId = (rawMarketId !== undefined) ? rawMarketId : market['marketId']; priceString = this.safeString(trade, priceId, priceString); amountString = this.safeString(trade, market['baseId'], amountString); costString = this.safeString(trade, market['quoteId'], costString); symbol = market['symbol']; const datetimeString = this.safeString2(trade, 'date', 'datetime'); let timestamp = undefined; if (datetimeString !== undefined) { if (datetimeString.indexOf(' ') >= 0) { // iso8601 timestamp = this.parse8601(datetimeString); } else { // string unix epoch in seconds timestamp = parseInt(datetimeString); timestamp = timestamp * 1000; } } // if it is a private trade if ('id' in trade) { if (amountString !== undefined) { const isAmountNeg = Precise.stringLt(amountString, '0'); if (isAmountNeg) { side = 'sell'; amountString = Precise.stringNeg(amountString); } else { side = 'buy'; } } } else { side = this.safeString(trade, 'type'); if (side === '1') { side = 'sell'; } else if (side === '0') { side = 'buy'; } else { side = undefined; } } if (costString !== undefined) { costString = Precise.stringAbs(costString); } let fee = undefined; if (feeCostString !== undefined) { fee = { 'cost': feeCostString, 'currency': feeCurrency, }; } return this.safeTrade({ 'id': id, 'info': trade, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': symbol, 'order': orderId, 'type': type, 'side': side, 'takerOrMaker': undefined, 'price': priceString, 'amount': amountString, 'cost': costString, 'fee': fee, }, market); } /** * @method * @name bitstamp#fetchTrades * @description get the list of most recent trades for a particular symbol * @see https://www.bitstamp.net/api/#tag/Transactions-public/operation/GetTransactions * @param {string} symbol unified symbol of the market to fetch trades for * @param {int} [since] timestamp in ms of the earliest trade to fetch * @param {int} [limit] the maximum amount of trades to fetch * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades} */ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'pair': market['id'], 'time': 'hour', }; const response = await this.publicGetTransactionsPair(this.extend(request, params)); // // [ // { // "date": "1551814435", // "tid": "83581898", // "price": "0.03532850", // "type": "1", // "amount": "0.85945907" // }, // { // "date": "1551814434", // "tid": "83581896", // "price": "0.03532851", // "type": "1", // "amount": "11.34130961" // }, // ] // return this.parseTrades(response, market, since, limit); } parseOHLCV(ohlcv, market = undefined) { // // { // "high": "9064.77", // "timestamp": "1593961440",