UNPKG

ccxt

Version:

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

1,136 lines (1,134 loc) • 67.4 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 phemexRest from '../phemex.js'; import { Precise } from '../base/Precise.js'; import { ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById } from '../base/ws/Cache.js'; import { sha256 } from '../static_dependencies/noble-hashes/sha256.js'; import { AuthenticationError } from '../base/errors.js'; // --------------------------------------------------------------------------- export default class phemex extends phemexRest { describe() { return this.deepExtend(super.describe(), { 'has': { 'ws': true, 'watchTicker': true, 'watchTickers': true, 'watchTrades': true, 'watchMyTrades': true, 'watchOrders': true, 'watchOrderBook': true, 'watchOHLCV': true, 'watchPositions': undefined, // mutli-endpoints are not supported: https://github.com/ccxt/ccxt/pull/21490 'watchOrderBookForSymbols': false, 'watchTradesForSymbols': false, 'watchOHLCVForSymbols': false, 'watchBalance': true, }, 'urls': { 'test': { 'ws': 'wss://testnet-api.phemex.com/ws', }, 'api': { 'ws': 'wss://ws.phemex.com', }, }, 'options': { 'tradesLimit': 1000, 'OHLCVLimit': 1000, }, 'streaming': { 'keepAlive': 9000, }, }); } fromEn(en, scale) { if (en === undefined) { return undefined; } const precise = new Precise(en); precise.decimals = this.sum(precise.decimals, scale); precise.reduce(); return precise.toString(); } fromEp(ep, market = undefined) { if ((ep === undefined) || (market === undefined)) { return ep; } return this.fromEn(ep, this.safeInteger(market, 'priceScale')); } fromEv(ev, market = undefined) { if ((ev === undefined) || (market === undefined)) { return ev; } return this.fromEn(ev, this.safeInteger(market, 'valueScale')); } fromEr(er, market = undefined) { if ((er === undefined) || (market === undefined)) { return er; } return this.fromEn(er, this.safeInteger(market, 'ratioScale')); } requestId() { const requestId = this.sum(this.safeInteger(this.options, 'requestId', 0), 1); this.options['requestId'] = requestId; return requestId; } parseSwapTicker(ticker, market = undefined) { // // { // "close": 442800, // "fundingRate": 10000, // "high": 445400, // "indexPrice": 442621, // "low": 428400, // "markPrice": 442659, // "open": 432200, // "openInterest": 744183, // "predFundingRate": 10000, // "symbol": "LTCUSD", // "turnover": 8133238294, // "volume": 934292 // } // const marketId = this.safeString(ticker, 'symbol'); market = this.safeMarket(marketId, market); const symbol = market['symbol']; const timestamp = this.safeIntegerProduct(ticker, 'timestamp', 0.000001); const lastString = this.fromEp(this.safeString(ticker, 'close'), market); const last = this.parseNumber(lastString); const quoteVolume = this.parseNumber(this.fromEv(this.safeString(ticker, 'turnover'), market)); const baseVolume = this.parseNumber(this.fromEv(this.safeString(ticker, 'volume'), market)); let change = undefined; let percentage = undefined; let average = undefined; const openString = this.omitZero(this.fromEp(this.safeString(ticker, 'open'), market)); const open = this.parseNumber(openString); if ((openString !== undefined) && (lastString !== undefined)) { change = this.parseNumber(Precise.stringSub(lastString, openString)); average = this.parseNumber(Precise.stringDiv(Precise.stringAdd(lastString, openString), '2')); percentage = this.parseNumber(Precise.stringMul(Precise.stringSub(Precise.stringDiv(lastString, openString), '1'), '100')); } const result = { 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'high': this.parseNumber(this.fromEp(this.safeString(ticker, 'high'), market)), 'low': this.parseNumber(this.fromEp(this.safeString(ticker, 'low'), market)), 'bid': undefined, 'bidVolume': undefined, 'ask': undefined, 'askVolume': undefined, 'vwap': undefined, 'open': open, 'close': last, 'last': last, 'previousClose': undefined, 'change': change, 'percentage': percentage, 'average': average, 'baseVolume': baseVolume, 'quoteVolume': quoteVolume, 'markPrice': this.parseNumber(this.fromEp(this.safeString(ticker, 'markPrice'), market)), 'indexPrice': this.parseNumber(this.fromEp(this.safeString(ticker, 'indexPrice'), market)), 'info': ticker, }; return result; } parsePerpetualTicker(ticker, market = undefined) { // // [ // "STXUSDT", // "0.64649", // "0.8628", // "0.61215", // "0.71737", // "4519387", // "3210827.98166", // "697635", // "0.71720205", // "0.71720205", // "0.0001", // "0.0001", // ] // const marketId = this.safeString(ticker, 0); market = this.safeMarket(marketId, market); const symbol = market['symbol']; const lastString = this.fromEp(this.safeString(ticker, 4), market); const last = this.parseNumber(lastString); const quoteVolume = this.parseNumber(this.fromEv(this.safeString(ticker, 6), market)); const baseVolume = this.parseNumber(this.fromEv(this.safeString(ticker, 5), market)); let change = undefined; let percentage = undefined; let average = undefined; const openString = this.omitZero(this.fromEp(this.safeString(ticker, 1), market)); const open = this.parseNumber(openString); if ((openString !== undefined) && (lastString !== undefined)) { change = this.parseNumber(Precise.stringSub(lastString, openString)); average = this.parseNumber(Precise.stringDiv(Precise.stringAdd(lastString, openString), '2')); percentage = this.parseNumber(Precise.stringMul(Precise.stringSub(Precise.stringDiv(lastString, openString), '1'), '100')); } const result = { 'symbol': symbol, 'timestamp': undefined, 'datetime': undefined, 'high': this.parseNumber(this.fromEp(this.safeString(ticker, 2), market)), 'low': this.parseNumber(this.fromEp(this.safeString(ticker, 3), market)), 'bid': undefined, 'bidVolume': undefined, 'ask': undefined, 'askVolume': undefined, 'vwap': undefined, 'open': open, 'close': last, 'last': last, 'previousClose': undefined, 'change': change, 'percentage': percentage, 'average': average, 'baseVolume': baseVolume, 'quoteVolume': quoteVolume, 'info': ticker, }; return result; } handleTicker(client, message) { // // { // "spot_market24h": { // "askEp": 958148000000, // "bidEp": 957884000000, // "highEp": 962000000000, // "lastEp": 958220000000, // "lowEp": 928049000000, // "openEp": 935597000000, // "symbol": "sBTCUSDT", // "turnoverEv": 146074214388978, // "volumeEv": 15492228900 // }, // "timestamp": 1592847265888272100 // } // // swap // // { // "market24h": { // "close": 442800, // "fundingRate": 10000, // "high": 445400, // "indexPrice": 442621, // "low": 428400, // "markPrice": 442659, // "open": 432200, // "openInterest": 744183, // "predFundingRate": 10000, // "symbol": "LTCUSD", // "turnover": 8133238294, // "volume": 934292 // }, // "timestamp": 1592845585373374500 // } // // perpetual // // { // "data": [ // [ // "STXUSDT", // "0.64649", // "0.8628", // "0.61215", // "0.71737", // "4519387", // "3210827.98166", // "697635", // "0.71720205", // "0.71720205", // "0.0001", // "0.0001", // ], // ... // ], // "fields": [ // "symbol", // "openRp", // "highRp", // "lowRp", // "lastRp", // "volumeRq", // "turnoverRv", // "openInterestRv", // "indexRp", // "markRp", // "fundingRateRr", // "predFundingRateRr", // ], // "method": "perp_market24h_pack_p.update", // "timestamp": "1677094918686806209", // "type": "snapshot", // } // const tickers = []; if ('market24h' in message) { const ticker = this.safeValue(message, 'market24h'); tickers.push(this.parseSwapTicker(ticker)); } else if ('spot_market24h' in message) { const ticker = this.safeValue(message, 'spot_market24h'); tickers.push(this.parseTicker(ticker)); } else if ('data' in message) { const data = this.safeValue(message, 'data', []); for (let i = 0; i < data.length; i++) { tickers.push(this.parsePerpetualTicker(data[i])); } } for (let i = 0; i < tickers.length; i++) { const ticker = tickers[i]; const symbol = ticker['symbol']; const messageHash = 'ticker:' + symbol; const timestamp = this.safeIntegerProduct(message, 'timestamp', 0.000001); ticker['timestamp'] = timestamp; ticker['datetime'] = this.iso8601(timestamp); this.tickers[symbol] = ticker; client.resolve(ticker, messageHash); } } /** * @method * @name phemex#watchBalance * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#subscribe-account-order-position-aop * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#subscribe-account-order-position-aop * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#subscribe-wallet-order-messages * @description watch balance and get the amount of funds available for trading or funds locked in orders * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.settle] set to USDT to use hedged perpetual api * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure} */ async watchBalance(params = {}) { await this.loadMarkets(); let type = undefined; [type, params] = this.handleMarketTypeAndParams('watchBalance', undefined, params); const usePerpetualApi = this.safeString(params, 'settle') === 'USDT'; let messageHash = ':balance'; messageHash = usePerpetualApi ? 'perpetual' + messageHash : type + messageHash; return await this.subscribePrivate(type, messageHash, params); } handleBalance(type, client, message) { // spot // [ // { // "balanceEv": 0, // "currency": "BTC", // "lastUpdateTimeNs": "1650442638722099092", // "lockedTradingBalanceEv": 0, // "lockedWithdrawEv": 0, // "userID": 2647224 // }, // { // "balanceEv": 1154232337, // "currency": "USDT", // "lastUpdateTimeNs": "1650442617610017597", // "lockedTradingBalanceEv": 0, // "lockedWithdrawEv": 0, // "userID": 2647224 // } // ] // swap // [ // { // "accountBalanceEv": 0, // "accountID": 26472240001, // "bonusBalanceEv": 0, // "currency": "BTC", // "totalUsedBalanceEv": 0, // "userID": 2647224 // } // ] // perpetual // [ // { // "accountBalanceRv": "1508.452588802237", // "accountID": 9328670003, // "bonusBalanceRv": "0", // "currency": "USDT", // "totalUsedBalanceRv": "343.132599666883", // "userID": 932867 // } // ] // this.balance['info'] = message; for (let i = 0; i < message.length; i++) { const balance = message[i]; const currencyId = this.safeString(balance, 'currency'); const code = this.safeCurrencyCode(currencyId); const currency = this.safeValue(this.currencies, code, {}); const scale = this.safeInteger(currency, 'valueScale', 8); const account = this.account(); let used = this.safeString(balance, 'totalUsedBalanceRv'); if (used === undefined) { let usedEv = this.safeString(balance, 'totalUsedBalanceEv'); if (usedEv === undefined) { const lockedTradingBalanceEv = this.safeString(balance, 'lockedTradingBalanceEv'); const lockedWithdrawEv = this.safeString2(balance, 'lockedWithdrawEv', 'lockedWithdrawRv'); usedEv = Precise.stringAdd(lockedTradingBalanceEv, lockedWithdrawEv); } used = this.fromEn(usedEv, scale); } let total = this.safeString(balance, 'accountBalanceRv'); if (total === undefined) { const totalEv = this.safeString2(balance, 'accountBalanceEv', 'balanceEv'); total = this.fromEn(totalEv, scale); } account['used'] = used; account['total'] = total; this.balance[code] = account; this.balance = this.safeBalance(this.balance); } const messageHash = type + ':balance'; client.resolve(this.balance, messageHash); } handleTrades(client, message) { // // { // "sequence": 1795484727, // "symbol": "sBTCUSDT", // "trades": [ // [ 1592891002064516600, "Buy", 964020000000, 1431000 ], // [ 1592890978987934500, "Sell", 963704000000, 1401800 ], // [ 1592890972918701800, "Buy", 963938000000, 2018600 ], // ], // "type": "snapshot" // } // perpetual // { // "sequence": 1230197759, // "symbol": "BTCUSDT", // "trades_p": [ // [ // 1677094244729433000, // "Buy", // "23800.4", // "2.455", // ], // ], // "type": "snapshot", // } // const name = 'trade'; const marketId = this.safeString(message, 'symbol'); const market = this.safeMarket(marketId); const symbol = market['symbol']; const messageHash = name + ':' + symbol; let stored = this.safeValue(this.trades, symbol); if (stored === undefined) { const limit = this.safeInteger(this.options, 'tradesLimit', 1000); stored = new ArrayCache(limit); this.trades[symbol] = stored; } const trades = this.safeValue2(message, 'trades', 'trades_p', []); const parsed = this.parseTrades(trades, market); for (let i = 0; i < parsed.length; i++) { stored.append(parsed[i]); } client.resolve(stored, messageHash); } handleOHLCV(client, message) { // // { // "kline": [ // [ 1592905200, 60, 960688000000, 960709000000, 960709000000, 960400000000, 960400000000, 848100, 8146756046 ], // [ 1592905140, 60, 960718000000, 960716000000, 960717000000, 960560000000, 960688000000, 4284900, 41163743512 ], // [ 1592905080, 60, 960513000000, 960684000000, 960718000000, 960684000000, 960718000000, 4880500, 46887494349 ], // ], // "sequence": 1804401474, // "symbol": "sBTCUSDT", // "type": "snapshot" // } // perpetual // { // "kline_p": [ // [ // 1677094560, // 60, // "23746.2", // "23746.1", // "23757.6", // "23736.9", // "23754.8", // "34.273", // "813910.208", // ], // ], // "sequence": 1230786017, // "symbol": "BTCUSDT", // "type": "incremental", // } // const marketId = this.safeString(message, 'symbol'); const market = this.safeMarket(marketId); const symbol = market['symbol']; const candles = this.safeValue2(message, 'kline', 'kline_p', []); const first = this.safeValue(candles, 0, []); const interval = this.safeString(first, 1); const timeframe = this.findTimeframe(interval); if (timeframe !== undefined) { const messageHash = 'kline:' + timeframe + ':' + symbol; const ohlcvs = this.parseOHLCVs(candles, market); this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {}); let stored = this.safeValue(this.ohlcvs[symbol], timeframe); if (stored === undefined) { const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000); stored = new ArrayCacheByTimestamp(limit); this.ohlcvs[symbol][timeframe] = stored; } for (let i = 0; i < ohlcvs.length; i++) { const candle = ohlcvs[i]; stored.append(candle); } client.resolve(stored, messageHash); } } /** * @method * @name phemex#watchTicker * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#subscribe-24-hours-ticker * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#subscribe-24-hours-ticker * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#subscribe-24-hours-ticker * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market * @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 watchTicker(symbol, params = {}) { await this.loadMarkets(); const market = this.market(symbol); symbol = market['symbol']; const isSwap = market['swap']; const settleIsUSDT = market['settle'] === 'USDT'; let name = 'spot_market24h'; if (isSwap) { name = settleIsUSDT ? 'perp_market24h_pack_p' : 'market24h'; } const url = this.urls['api']['ws']; const requestId = this.requestId(); const subscriptionHash = name + '.subscribe'; const messageHash = 'ticker:' + symbol; const subscribe = { 'method': subscriptionHash, 'id': requestId, 'params': [], }; const request = this.deepExtend(subscribe, params); return await this.watch(url, messageHash, request, subscriptionHash); } /** * @method * @name phemex#watchTickers * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#subscribe-24-hours-ticker * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#subscribe-24-hours-ticker * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#subscribe-24-hours-ticker * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list * @param {string[]} [symbols] unified symbol of the market to fetch the ticker for * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.channel] the channel to subscribe to, tickers by default. Can be tickers, sprd-tickers, index-tickers, block-tickers * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ async watchTickers(symbols = undefined, params = {}) { await this.loadMarkets(); symbols = this.marketSymbols(symbols, undefined, false); const first = symbols[0]; const market = this.market(first); const isSwap = market['swap']; const settleIsUSDT = market['settle'] === 'USDT'; let name = 'spot_market24h'; if (isSwap) { name = settleIsUSDT ? 'perp_market24h_pack_p' : 'market24h'; } const url = this.urls['api']['ws']; const requestId = this.requestId(); const subscriptionHash = name + '.subscribe'; const messageHashes = []; for (let i = 0; i < symbols.length; i++) { messageHashes.push('ticker:' + symbols[i]); } const subscribe = { 'method': subscriptionHash, 'id': requestId, 'params': [], }; const request = this.deepExtend(subscribe, params); const ticker = await this.watchMultiple(url, messageHashes, request, messageHashes); if (this.newUpdates) { const result = {}; result[ticker['symbol']] = ticker; return result; } return this.filterByArray(this.tickers, 'symbol', symbols); } /** * @method * @name phemex#watchTrades * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#subscribe-trade * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#subscribe-trade * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#subscribe-trade * @description get the list of most recent trades for a particular symbol * @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 {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades} */ async watchTrades(symbol, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); symbol = market['symbol']; const url = this.urls['api']['ws']; const requestId = this.requestId(); const isSwap = market['swap']; const settleIsUSDT = market['settle'] === 'USDT'; const name = (isSwap && settleIsUSDT) ? 'trade_p' : 'trade'; const messageHash = 'trade:' + symbol; const method = name + '.subscribe'; const subscribe = { 'method': method, 'id': requestId, 'params': [ market['id'], ], }; const request = this.deepExtend(subscribe, params); const trades = await this.watch(url, messageHash, request, messageHash); if (this.newUpdates) { limit = trades.getLimit(symbol, limit); } return this.filterBySinceLimit(trades, since, limit, 'timestamp', true); } /** * @method * @name phemex#watchOrderBook * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#subscribe-orderbook * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#subscribe-orderbook-for-new-model * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#subscribe-30-levels-orderbook * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#subscribe-full-orderbook * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @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 watchOrderBook(symbol, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); symbol = market['symbol']; const url = this.urls['api']['ws']; const requestId = this.requestId(); const isSwap = market['swap']; const settleIsUSDT = market['settle'] === 'USDT'; const name = (isSwap && settleIsUSDT) ? 'orderbook_p' : 'orderbook'; const messageHash = 'orderbook:' + symbol; const method = name + '.subscribe'; const subscribe = { 'method': method, 'id': requestId, 'params': [ market['id'], ], }; const request = this.deepExtend(subscribe, params); const orderbook = await this.watch(url, messageHash, request, messageHash); return orderbook.limit(); } /** * @method * @name phemex#watchOHLCV * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#subscribe-kline * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#subscribe-kline * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#subscribe-kline * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market * @param {string} symbol unified symbol of the market to fetch OHLCV data for * @param {string} timeframe the length of time each candle represents * @param {int} [since] timestamp in ms of the earliest candle to fetch * @param {int} [limit] the maximum amount of candles to fetch * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume */ async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); symbol = market['symbol']; const url = this.urls['api']['ws']; const requestId = this.requestId(); const isSwap = market['swap']; const settleIsUSDT = market['settle'] === 'USDT'; const name = (isSwap && settleIsUSDT) ? 'kline_p' : 'kline'; const messageHash = 'kline:' + timeframe + ':' + symbol; const method = name + '.subscribe'; const subscribe = { 'method': method, 'id': requestId, 'params': [ market['id'], this.safeInteger(this.timeframes, timeframe), ], }; const request = this.deepExtend(subscribe, params); const ohlcv = await this.watch(url, messageHash, request, messageHash); if (this.newUpdates) { limit = ohlcv.getLimit(symbol, limit); } return this.filterBySinceLimit(ohlcv, since, limit, 0, true); } customHandleDelta(bookside, delta, market = undefined) { const bidAsk = this.customParseBidAsk(delta, 0, 1, market); bookside.storeArray(bidAsk); } customHandleDeltas(bookside, deltas, market = undefined) { for (let i = 0; i < deltas.length; i++) { this.customHandleDelta(bookside, deltas[i], market); } } handleOrderBook(client, message) { // // { // "book": { // "asks": [ // [ 960316000000, 6993800 ], // [ 960318000000, 13183000 ], // [ 960319000000, 9170200 ], // ], // "bids": [ // [ 959941000000, 8385300 ], // [ 959939000000, 10296600 ], // [ 959930000000, 3672400 ], // ] // }, // "depth": 30, // "sequence": 1805784701, // "symbol": "sBTCUSDT", // "timestamp": 1592908460404461600, // "type": "snapshot" // } // perpetual // { // "depth": 30, // "orderbook_p": { // "asks": [ // [ // "23788.5", // "0.13", // ], // ], // "bids": [ // [ // "23787.8", // "1.836", // ], // ], // }, // "sequence": 1230347368, // "symbol": "BTCUSDT", // "timestamp": "1677093457306978852", // "type": "snapshot", // } // const marketId = this.safeString(message, 'symbol'); const market = this.safeMarket(marketId); const symbol = market['symbol']; const type = this.safeString(message, 'type'); const depth = this.safeInteger(message, 'depth'); const name = 'orderbook'; const messageHash = name + ':' + symbol; const nonce = this.safeInteger(message, 'sequence'); const timestamp = this.safeIntegerProduct(message, 'timestamp', 0.000001); if (type === 'snapshot') { const book = this.safeValue2(message, 'book', 'orderbook_p', {}); const snapshot = this.customParseOrderBook(book, symbol, timestamp, 'bids', 'asks', 0, 1, market); snapshot['nonce'] = nonce; const orderbook = this.orderBook(snapshot, depth); this.orderbooks[symbol] = orderbook; client.resolve(orderbook, messageHash); } else { if (symbol in this.orderbooks) { const orderbook = this.orderbooks[symbol]; const changes = this.safeDict2(message, 'book', 'orderbook_p', {}); const asks = this.safeList(changes, 'asks', []); const bids = this.safeList(changes, 'bids', []); this.customHandleDeltas(orderbook['asks'], asks, market); this.customHandleDeltas(orderbook['bids'], bids, market); orderbook['nonce'] = nonce; orderbook['timestamp'] = timestamp; orderbook['datetime'] = this.iso8601(timestamp); this.orderbooks[symbol] = orderbook; client.resolve(orderbook, messageHash); } } } /** * @method * @name phemex#watchMyTrades * @description watches information on multiple trades made by the user * @param {string} symbol unified market symbol of the market trades were made in * @param {int} [since] the earliest time in ms to fetch trades for * @param {int} [limit] the maximum number of trade structures to retrieve * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} */ async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); let market = undefined; let type = undefined; let messageHash = 'trades:'; if (symbol !== undefined) { market = this.market(symbol); symbol = market['symbol']; messageHash = messageHash + market['symbol']; if (market['settle'] === 'USDT') { params = this.extend(params); params['settle'] = 'USDT'; } } [type, params] = this.handleMarketTypeAndParams('watchMyTrades', market, params); if (symbol === undefined) { const settle = this.safeString(params, 'settle'); messageHash = (settle === 'USDT') ? (messageHash + 'perpetual') : (messageHash + type); } const trades = await this.subscribePrivate(type, messageHash, params); if (this.newUpdates) { limit = trades.getLimit(symbol, limit); } return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true); } handleMyTrades(client, message) { // // swap // [ // { // "avgPriceEp":4138763000000, // "baseCurrency":"BTC", // "baseQtyEv":0, // "clOrdID":"7956e0be-e8be-93a0-2887-ca504d85cda2", // "execBaseQtyEv":30100, // "execFeeEv":31, // "execID":"d3b10cfa-84e3-5752-828e-78a79617e598", // "execPriceEp":4138763000000, // "execQuoteQtyEv":1245767663, // "feeCurrency":"BTC", // "lastLiquidityInd":"RemovedLiquidity", // "ordType":"Market", // "orderID":"34a4b1a8-ac3a-4580-b3e6-a6d039f27195", // "priceEp":4549022000000, // "qtyType":"ByQuote", // "quoteCurrency":"USDT", // "quoteQtyEv":1248000000, // "side":"Buy", // "symbol":"sBTCUSDT", // "tradeType":"Trade", // "transactTimeNs":"1650442617609928764", // "userID":2647224 // } // ] // perpetual // [ // { // "accountID": 9328670003, // "action": "New", // "actionBy": "ByUser", // "actionTimeNs": 1666858780876924611, // "addedSeq": 77751555, // "apRp": "0", // "bonusChangedAmountRv": "0", // "bpRp": "0", // "clOrdID": "c0327a7d-9064-62a9-28f6-2db9aaaa04e0", // "closedPnlRv": "0", // "closedSize": "0", // "code": 0, // "cumFeeRv": "0", // "cumQty": "0", // "cumValueRv": "0", // "curAccBalanceRv": "1508.489893982237", // "curAssignedPosBalanceRv": "24.62786650928", // "curBonusBalanceRv": "0", // "curLeverageRr": "-10", // "curPosSide": "Buy", // "curPosSize": "0.043", // "curPosTerm": 1, // "curPosValueRv": "894.0689", // "curRiskLimitRv": "1000000", // "currency": "USDT", // "cxlRejReason": 0, // "displayQty": "0.003", // "execFeeRv": "0", // "execID": "00000000-0000-0000-0000-000000000000", // "execPriceRp": "20723.7", // "execQty": "0", // "execSeq": 77751555, // "execStatus": "New", // "execValueRv": "0", // "feeRateRr": "0", // "leavesQty": "0.003", // "leavesValueRv": "63.4503", // "message": "No error", // "ordStatus": "New", // "ordType": "Market", // "orderID": "fa64c6f2-47a4-4929-aab4-b7fa9bbc4323", // "orderQty": "0.003", // "pegOffsetValueRp": "0", // "posSide": "Long", // "priceRp": "21150.1", // "relatedPosTerm": 1, // "relatedReqNum": 11, // "side": "Buy", // "slTrigger": "ByMarkPrice", // "stopLossRp": "0", // "stopPxRp": "0", // "symbol": "BTCUSDT", // "takeProfitRp": "0", // "timeInForce": "ImmediateOrCancel", // "tpTrigger": "ByLastPrice", // "tradeType": "Amend", // "transactTimeNs": 1666858780881545305, // "userID": 932867 // }, // ... // ] // const channel = 'trades'; const tradesLength = message.length; if (tradesLength === 0) { return; } let cachedTrades = this.myTrades; if (cachedTrades === undefined) { const limit = this.safeInteger(this.options, 'tradesLimit', 1000); cachedTrades = new ArrayCacheBySymbolById(limit); } const marketIds = {}; let type = undefined; for (let i = 0; i < message.length; i++) { const rawTrade = message[i]; const marketId = this.safeString(rawTrade, 'symbol'); const market = this.safeMarket(marketId); const parsed = this.parseTrade(rawTrade); cachedTrades.append(parsed); const symbol = parsed['symbol']; if (type === undefined) { type = (market['settle'] === 'USDT') ? 'perpetual' : market['type']; } marketIds[symbol] = true; } const keys = Object.keys(marketIds); for (let i = 0; i < keys.length; i++) { const market = keys[i]; const hash = channel + ':' + market; client.resolve(cachedTrades, hash); } // generic subscription const messageHash = channel + ':' + type; client.resolve(cachedTrades, messageHash); } /** * @method * @name phemex#watchOrders * @description watches information on multiple orders made by the user * @param {string} symbol unified market symbol of the market orders were made in * @param {int} [since] the earliest time in ms to fetch orders for * @param {int} [limit] the maximum number of order structures to retrieve * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); let messageHash = 'orders:'; let market = undefined; let type = undefined; if (symbol !== undefined) { market = this.market(symbol); symbol = market['symbol']; messageHash = messageHash + market['symbol']; if (market['settle'] === 'USDT') { params = this.extend(params); params['settle'] = 'USDT'; } } [type, params] = this.handleMarketTypeAndParams('watchOrders', market, params); const isUSDTSettled = this.safeString(params, 'settle') === 'USDT'; if (symbol === undefined) { messageHash = (isUSDTSettled) ? (messageHash + 'perpetual') : (messageHash + type); } const orders = await this.subscribePrivate(type, messageHash, params); if (this.newUpdates) { limit = orders.getLimit(symbol, limit); } return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true); } handleOrders(client, message) { // spot update // { // "closed":[ // { // "action":"New", // "avgPriceEp":4138763000000, // "baseCurrency":"BTC", // "baseQtyEv":0, // "bizError":0, // "clOrdID":"7956e0be-e8be-93a0-2887-ca504d85cda2", // "createTimeNs":"1650442617606017583", // "cumBaseQtyEv":30100, // "cumFeeEv":31, // "cumQuoteQtyEv":1245767663, // "cxlRejReason":0, // "feeCurrency":"BTC", // "leavesBaseQtyEv":0, // "leavesQuoteQtyEv":0, // "ordStatus":"Filled", // "ordType":"Market", // "orderID":"34a4b1a8-ac3a-4580-b3e6-a6d039f27195", // "pegOffsetValueEp":0, // "priceEp":4549022000000, // "qtyType":"ByQuote", // "quoteCurrency":"USDT", // "quoteQtyEv":1248000000, // "side":"Buy", // "stopPxEp":0, // "symbol":"sBTCUSDT", // "timeInForce":"ImmediateOrCancel", // "tradeType":"Trade", // "transactTimeNs":"1650442617609928764", // "triggerTimeNs":0, // "userID":2647224 // } // ], // "fills":[ // { // "avgPriceEp":4138763000000, // "baseCurrency":"BTC", // "baseQtyEv":0, // "clOrdID":"7956e0be-e8be-93a0-2887-ca504d85cda2", // "execBaseQtyEv":30100, // "execFeeEv":31, // "execID":"d3b10cfa-84e3-5752-828e-78a79617e598", // "execPriceEp":4138763000000, // "execQuoteQtyEv":1245767663, // "feeCurrency":"BTC", // "lastLiquidityInd":"RemovedLiquidity", // "ordType":"Market", // "orderID":"34a4b1a8-ac3a-4580-b3e6-a6d039f27195", // "priceEp":4549022000000, // "qtyType":"ByQuote", // "quoteCurrency":"USDT", // "quoteQtyEv":1248000000, // "side":"Buy", // "symbol":"sBTCUSDT", // "tradeType":"Trade", // "transactTimeNs":"1650442617609928764", // "userID":2647224 // } // ], // "open":[ // { // "action":"New", // "avgPriceEp":0, // "baseCurrency":"LTC", // "baseQtyEv":0, // "bizError":0, // "clOrdID":"2c0e5eb5-efb7-60d3-2e5f-df175df412ef", // "createTimeNs":"1650446670073853755", // "cumBaseQtyEv":0, // "cumFeeEv":0, // "cumQuoteQtyEv":0, // "cxlRejReason":0, // "feeCurrency":"LTC", // "leavesBaseQtyEv":0, // "leavesQuoteQtyEv":1000000000, // "ordStatus":"New", // "ordType":"Limit", // "orderID":"d2aad92f-50f5-441a-957b-8184b146e3fb", // "pegOffsetValueEp":0, // "priceEp":5000000000, // "qtyType":"ByQuote", // "quoteCurrency":"USDT", // "quoteQtyEv":1000000000, // "side":"Buy", // } // ] // }, // perpetual // [ // { // "accountID": 40183400003, // "action": "New", // "actionBy": "ByUser", // "actionTimeNs": "1674110665380190869", // "addedSeq": 678760103, // "apRp": "0", // "bonusChangedAmountRv": "0", // "bpRp": "0", // "clOrdID": '', // "cl_req_code": 0, // "closedPnlRv": "0", // "closedSize": "0", // "code": 0, // "cumFeeRv": "0", // "cumQty": "0.001", // "cumValueRv": "20.849", // "curAccBalanceRv": "19.9874906", // "curAssignedPosBalanceRv": "0", // "curBonusBalanceRv": "0", // "curLeverageRr": "-10", // "curPosSide": "Buy", // "curPosSize": "0.001", // "curPosTerm": 1, // "curPosValueRv": "20.849", // "curRiskLimitRv": "1000000", // "currency": "USDT", // "cxlRejReason": 0, // "displayQty": "0.001", // "execFeeRv": "0.0125094", // "execID": "b88d2950-04a2-52d8-8927-346059900242", // "execPriceRp": "20849", // "execQty": "0.001", // "execSeq": 678760103, // "execStatus": "TakerFill", // "execValueRv": "20.849", // "feeRateRr": "0.0006", // "lastLiquidityInd": "RemovedLiquidity", // "leavesQty": "0", // "leavesValueRv": "0", // "message": "No error", // "ordStatus": "Filled", // "ordType": "Market", // "orderID": "79620ed2-54c6-4645-a35c-7057e687c576", // "orderQty": "0.001", // "pegOffsetProportionRr": "0", // "pegOffsetValueRp": "0", // "posSide": "Long", // "priceRp": "21476.3", // "relatedPosTerm": 1, // "relatedReqNum": 4, // "side": "Buy", // "slTrigger": "ByMarkPrice", // "stopLossRp": "0", // "stopPxRp": "0", // "symbol": "BTCUSDT", // "takeProfitRp": "0", // "timeInForce": "ImmediateOrCancel", // "tpTrigger": "ByLastPrice", // "tradeType": "Trade", // "transactTimeNs": "1674110665387882268", // "userID": 4018340 // }, // ... // ] // let trades = []; const parsedOrders = []; if (('closed' in message) || ('fills' in message) || ('open' in message)) { const closed = this.safeValue(message, 'closed', []); const open = this.safeValue(message, 'open', []); const orders = this.