UNPKG

@jalmonter/ccxt

Version:

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

1,122 lines 70 kB
// --------------------------------------------------------------------------- import bitmexRest from '../bitmex.js'; import { AuthenticationError, ExchangeError, RateLimitExceeded } from '../base/errors.js'; import { ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide } from '../base/ws/Cache.js'; import { sha256 } from '../static_dependencies/noble-hashes/sha256.js'; // --------------------------------------------------------------------------- export default class bitmex extends bitmexRest { describe() { return this.deepExtend(super.describe(), { 'has': { 'ws': true, 'watchBalance': true, 'watchMyTrades': true, 'watchOHLCV': true, 'watchOrderBook': true, 'watchOrderBookForSymbols': true, 'watchOrders': true, 'watchPostions': true, 'watchTicker': true, 'watchTickers': false, 'watchTrades': true, 'watchTradesForSymbols': true, }, 'urls': { 'test': { 'ws': 'wss://ws.testnet.bitmex.com/realtime', }, 'api': { 'ws': 'wss://ws.bitmex.com/realtime', }, }, // 'versions': { // 'ws': '0.2.0', // }, 'options': { 'watchOrderBookLevel': 'orderBookL2', 'tradesLimit': 1000, 'OHLCVLimit': 1000, }, 'exceptions': { 'ws': { 'exact': {}, 'broad': { 'Rate limit exceeded': RateLimitExceeded, }, }, }, }); } async watchTicker(symbol, params = {}) { /** * @method * @name bitmex#watchTicker * @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} */ await this.loadMarkets(); const market = this.market(symbol); const name = 'instrument'; const messageHash = name + ':' + market['id']; const url = this.urls['api']['ws']; const request = { 'op': 'subscribe', 'args': [ messageHash, ], }; return await this.watch(url, messageHash, this.extend(request, params), messageHash); } handleTicker(client, message) { // // { // "table": "instrument", // "action": "partial", // "keys": [ "symbol" ], // "types": { // "symbol": "symbol", // "rootSymbol": "symbol", // "state": "symbol", // "typ": "symbol", // "listing": "timestamp", // "front": "timestamp", // "expiry": "timestamp", // "settle": "timestamp", // "relistInterval": "timespan", // "inverseLeg": "symbol", // "sellLeg": "symbol", // "buyLeg": "symbol", // "optionStrikePcnt": "float", // "optionStrikeRound": "float", // "optionStrikePrice": "float", // "optionMultiplier": "float", // "positionCurrency": "symbol", // "underlying": "symbol", // "quoteCurrency": "symbol", // "underlyingSymbol": "symbol", // "reference": "symbol", // "referenceSymbol": "symbol", // "calcInterval": "timespan", // "publishInterval": "timespan", // "publishTime": "timespan", // "maxOrderQty": "long", // "maxPrice": "float", // "lotSize": "long", // "tickSize": "float", // "multiplier": "long", // "settlCurrency": "symbol", // "underlyingToPositionMultiplier": "long", // "underlyingToSettleMultiplier": "long", // "quoteToSettleMultiplier": "long", // "isQuanto": "boolean", // "isInverse": "boolean", // "initMargin": "float", // "maintMargin": "float", // "riskLimit": "long", // "riskStep": "long", // "limit": "float", // "capped": "boolean", // "taxed": "boolean", // "deleverage": "boolean", // "makerFee": "float", // "takerFee": "float", // "settlementFee": "float", // "insuranceFee": "float", // "fundingBaseSymbol": "symbol", // "fundingQuoteSymbol": "symbol", // "fundingPremiumSymbol": "symbol", // "fundingTimestamp": "timestamp", // "fundingInterval": "timespan", // "fundingRate": "float", // "indicativeFundingRate": "float", // "rebalanceTimestamp": "timestamp", // "rebalanceInterval": "timespan", // "openingTimestamp": "timestamp", // "closingTimestamp": "timestamp", // "sessionInterval": "timespan", // "prevClosePrice": "float", // "limitDownPrice": "float", // "limitUpPrice": "float", // "bankruptLimitDownPrice": "float", // "bankruptLimitUpPrice": "float", // "prevTotalVolume": "long", // "totalVolume": "long", // "volume": "long", // "volume24h": "long", // "prevTotalTurnover": "long", // "totalTurnover": "long", // "turnover": "long", // "turnover24h": "long", // "homeNotional24h": "float", // "foreignNotional24h": "float", // "prevPrice24h": "float", // "vwap": "float", // "highPrice": "float", // "lowPrice": "float", // "lastPrice": "float", // "lastPriceProtected": "float", // "lastTickDirection": "symbol", // "lastChangePcnt": "float", // "bidPrice": "float", // "midPrice": "float", // "askPrice": "float", // "impactBidPrice": "float", // "impactMidPrice": "float", // "impactAskPrice": "float", // "hasLiquidity": "boolean", // "openInterest": "long", // "openValue": "long", // "fairMethod": "symbol", // "fairBasisRate": "float", // "fairBasis": "float", // "fairPrice": "float", // "markMethod": "symbol", // "markPrice": "float", // "indicativeTaxRate": "float", // "indicativeSettlePrice": "float", // "optionUnderlyingPrice": "float", // "settledPrice": "float", // "timestamp": "timestamp" // }, // "foreignKeys": { // "inverseLeg": "instrument", // "sellLeg": "instrument", // "buyLeg": "instrument" // }, // "attributes": { symbol: "unique" }, // "filter": { symbol: "XBTUSD" }, // "data": [ // { // "symbol": "XBTUSD", // "rootSymbol": "XBT", // "state": "Open", // "typ": "FFWCSX", // "listing": "2016-05-13T12:00:00.000Z", // "front": "2016-05-13T12:00:00.000Z", // "expiry": null, // "settle": null, // "relistInterval": null, // "inverseLeg": '', // "sellLeg": '', // "buyLeg": '', // "optionStrikePcnt": null, // "optionStrikeRound": null, // "optionStrikePrice": null, // "optionMultiplier": null, // "positionCurrency": "USD", // "underlying": "XBT", // "quoteCurrency": "USD", // "underlyingSymbol": "XBT=", // "reference": "BMEX", // "referenceSymbol": ".BXBT", // "calcInterval": null, // "publishInterval": null, // "publishTime": null, // "maxOrderQty": 10000000, // "maxPrice": 1000000, // "lotSize": 1, // "tickSize": 0.5, // "multiplier": -100000000, // "settlCurrency": "XBt", // "underlyingToPositionMultiplier": null, // "underlyingToSettleMultiplier": -100000000, // "quoteToSettleMultiplier": null, // "isQuanto": false, // "isInverse": true, // "initMargin": 0.01, // "maintMargin": 0.005, // "riskLimit": 20000000000, // "riskStep": 10000000000, // "limit": null, // "capped": false, // "taxed": true, // "deleverage": true, // "makerFee": -0.00025, // "takerFee": 0.00075, // "settlementFee": 0, // "insuranceFee": 0, // "fundingBaseSymbol": ".XBTBON8H", // "fundingQuoteSymbol": ".USDBON8H", // "fundingPremiumSymbol": ".XBTUSDPI8H", // "fundingTimestamp": "2020-01-29T12:00:00.000Z", // "fundingInterval": "2000-01-01T08:00:00.000Z", // "fundingRate": 0.000597, // "indicativeFundingRate": 0.000652, // "rebalanceTimestamp": null, // "rebalanceInterval": null, // "openingTimestamp": "2020-01-29T11:00:00.000Z", // "closingTimestamp": "2020-01-29T12:00:00.000Z", // "sessionInterval": "2000-01-01T01:00:00.000Z", // "prevClosePrice": 9063.96, // "limitDownPrice": null, // "limitUpPrice": null, // "bankruptLimitDownPrice": null, // "bankruptLimitUpPrice": null, // "prevTotalVolume": 1989881049026, // "totalVolume": 1990196740950, // "volume": 315691924, // "volume24h": 4491824765, // "prevTotalTurnover": 27865497128425564, // "totalTurnover": 27868891594857150, // "turnover": 3394466431587, // "turnover24h": 48863390064843, // "homeNotional24h": 488633.9006484273, // "foreignNotional24h": 4491824765, // "prevPrice24h": 9091, // "vwap": 9192.8663, // "highPrice": 9440, // "lowPrice": 8886, // "lastPrice": 9287, // "lastPriceProtected": 9287, // "lastTickDirection": "PlusTick", // "lastChangePcnt": 0.0216, // "bidPrice": 9286, // "midPrice": 9286.25, // "askPrice": 9286.5, // "impactBidPrice": 9285.9133, // "impactMidPrice": 9286.75, // "impactAskPrice": 9287.6382, // "hasLiquidity": true, // "openInterest": 967826984, // "openValue": 10432207060536, // "fairMethod": "FundingRate", // "fairBasisRate": 0.6537149999999999, // "fairBasis": 0.33, // "fairPrice": 9277.2, // "markMethod": "FairPrice", // "markPrice": 9277.2, // "indicativeTaxRate": 0, // "indicativeSettlePrice": 9276.87, // "optionUnderlyingPrice": null, // "settledPrice": null, // "timestamp": "2020-01-29T11:31:37.114Z" // } // ] // } // const table = this.safeString(message, 'table'); const data = this.safeValue(message, 'data', []); for (let i = 0; i < data.length; i++) { const update = data[i]; const marketId = this.safeValue(update, 'symbol'); const market = this.safeMarket(marketId); const symbol = market['symbol']; const messageHash = table + ':' + marketId; let ticker = this.safeValue(this.tickers, symbol, {}); const info = this.safeValue(ticker, 'info', {}); ticker = this.parseTicker(this.extend(info, update), market); this.tickers[symbol] = ticker; client.resolve(ticker, messageHash); } return message; } async watchBalance(params = {}) { /** * @method * @name bitmex#watchBalance * @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 * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure} */ await this.loadMarkets(); await this.authenticate(); const messageHash = 'margin'; const url = this.urls['api']['ws']; const request = { 'op': 'subscribe', 'args': [ messageHash, ], }; return await this.watch(url, messageHash, this.extend(request, params), messageHash); } handleBalance(client, message) { // // { // "table": "margin", // "action": "partial", // "keys": [ "account" ], // "types": { // "account": "long", // "currency": "symbol", // "riskLimit": "long", // "prevState": "symbol", // "state": "symbol", // "action": "symbol", // "amount": "long", // "pendingCredit": "long", // "pendingDebit": "long", // "confirmedDebit": "long", // "prevRealisedPnl": "long", // "prevUnrealisedPnl": "long", // "grossComm": "long", // "grossOpenCost": "long", // "grossOpenPremium": "long", // "grossExecCost": "long", // "grossMarkValue": "long", // "riskValue": "long", // "taxableMargin": "long", // "initMargin": "long", // "maintMargin": "long", // "sessionMargin": "long", // "targetExcessMargin": "long", // "varMargin": "long", // "realisedPnl": "long", // "unrealisedPnl": "long", // "indicativeTax": "long", // "unrealisedProfit": "long", // "syntheticMargin": "long", // "walletBalance": "long", // "marginBalance": "long", // "marginBalancePcnt": "float", // "marginLeverage": "float", // "marginUsedPcnt": "float", // "excessMargin": "long", // "excessMarginPcnt": "float", // "availableMargin": "long", // "withdrawableMargin": "long", // "timestamp": "timestamp", // "grossLastValue": "long", // "commission": "float" // }, // "foreignKeys": {}, // "attributes": { account: "sorted" }, // "filter": { account: 1455728 }, // "data": [ // { // "account": 1455728, // "currency": "XBt", // "riskLimit": 1000000000000, // "prevState": '', // "state": '', // "action": '', // "amount": 263542, // "pendingCredit": 0, // "pendingDebit": 0, // "confirmedDebit": 0, // "prevRealisedPnl": 0, // "prevUnrealisedPnl": 0, // "grossComm": 0, // "grossOpenCost": 0, // "grossOpenPremium": 0, // "grossExecCost": 0, // "grossMarkValue": 0, // "riskValue": 0, // "taxableMargin": 0, // "initMargin": 0, // "maintMargin": 0, // "sessionMargin": 0, // "targetExcessMargin": 0, // "varMargin": 0, // "realisedPnl": 0, // "unrealisedPnl": 0, // "indicativeTax": 0, // "unrealisedProfit": 0, // "syntheticMargin": null, // "walletBalance": 263542, // "marginBalance": 263542, // "marginBalancePcnt": 1, // "marginLeverage": 0, // "marginUsedPcnt": 0, // "excessMargin": 263542, // "excessMarginPcnt": 1, // "availableMargin": 263542, // "withdrawableMargin": 263542, // "timestamp": "2020-08-03T12:01:01.246Z", // "grossLastValue": 0, // "commission": null // } // ] // } // const data = this.safeValue(message, 'data'); const balance = this.parseBalance(data); this.balance = this.extend(this.balance, balance); const messageHash = this.safeString(message, 'table'); client.resolve(this.balance, messageHash); } handleTrades(client, message) { // // initial snapshot // // { // "table": "trade", // "action": "partial", // "keys": [], // "types": { // "timestamp": "timestamp", // "symbol": "symbol", // "side": "symbol", // "size": "long", // "price": "float", // "tickDirection": "symbol", // "trdMatchID": "guid", // "grossValue": "long", // "homeNotional": "float", // "foreignNotional": "float" // }, // "foreignKeys": { symbol: "instrument", side: "side" }, // "attributes": { timestamp: "sorted", symbol: "grouped" }, // "filter": { symbol: "XBTUSD" }, // "data": [ // { // "timestamp": "2020-01-30T17:03:07.854Z", // "symbol": "XBTUSD", // "side": "Buy", // "size": 15000, // "price": 9378, // "tickDirection": "ZeroPlusTick", // "trdMatchID": "5b426e7f-83d1-2c80-295d-ee995b8ceb4a", // "grossValue": 159945000, // "homeNotional": 1.59945, // "foreignNotional": 15000 // } // ] // } // // updates // // { // "table": "trade", // "action": "insert", // "data": [ // { // "timestamp": "2020-01-30T17:31:40.160Z", // "symbol": "XBTUSD", // "side": "Sell", // "size": 37412, // "price": 9521.5, // "tickDirection": "ZeroMinusTick", // "trdMatchID": "a4bfc6bc-6cf1-1a11-622e-270eef8ca5c7", // "grossValue": 392938236, // "homeNotional": 3.92938236, // "foreignNotional": 37412 // } // ] // } // const table = 'trade'; const data = this.safeValue(message, 'data', []); const dataByMarketIds = this.groupBy(data, 'symbol'); const marketIds = Object.keys(dataByMarketIds); for (let i = 0; i < marketIds.length; i++) { const marketId = marketIds[i]; const market = this.safeMarket(marketId); const messageHash = table + ':' + marketId; const symbol = market['symbol']; const trades = this.parseTrades(dataByMarketIds[marketId], market); 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; } for (let j = 0; j < trades.length; j++) { stored.append(trades[j]); } client.resolve(stored, messageHash); } } async watchTrades(symbol, since = undefined, limit = undefined, params = {}) { /** * @method * @name bitmex#watchTrades * @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} */ await this.loadMarkets(); const market = this.market(symbol); symbol = market['symbol']; const table = 'trade'; const messageHash = table + ':' + market['id']; const url = this.urls['api']['ws']; const request = { 'op': 'subscribe', 'args': [ messageHash, ], }; const trades = await this.watch(url, messageHash, this.extend(request, params), messageHash); if (this.newUpdates) { limit = trades.getLimit(symbol, limit); } return this.filterBySinceLimit(trades, since, limit, 'timestamp', true); } async authenticate(params = {}) { const url = this.urls['api']['ws']; const client = this.client(url); const messageHash = 'authenticated'; const future = client.future(messageHash); const authenticated = this.safeValue(client.subscriptions, messageHash); if (authenticated === undefined) { this.checkRequiredCredentials(); const timestamp = this.milliseconds(); const payload = 'GET' + '/realtime' + timestamp.toString(); const signature = this.hmac(this.encode(payload), this.encode(this.secret), sha256); const request = { 'op': 'authKeyExpires', 'args': [ this.apiKey, timestamp, signature, ], }; const message = this.extend(request, params); this.watch(url, messageHash, message, messageHash); } return future; } handleAuthenticationMessage(client, message) { const authenticated = this.safeValue(message, 'success', false); const messageHash = 'authenticated'; if (authenticated) { // we resolve the future here permanently so authentication only happens once const future = this.safeValue(client.futures, messageHash); future.resolve(true); } else { const error = new AuthenticationError(this.json(message)); client.reject(error, messageHash); if (messageHash in client.subscriptions) { delete client.subscriptions[messageHash]; } } } async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name bitmex#watchPositions * @see https://www.bitmex.com/app/wsAPI * @description watch all open positions * @param {string[]|undefined} symbols list of unified market symbols * @param {object} params extra parameters specific to the exchange API endpoint * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure} */ await this.loadMarkets(); await this.authenticate(); const subscriptionHash = 'position'; let messageHash = 'positions'; if (!this.isEmpty(symbols)) { messageHash = '::' + symbols.join(','); } const url = this.urls['api']['ws']; const request = { 'op': 'subscribe', 'args': [ subscriptionHash, ], }; const newPositions = await this.watch(url, messageHash, request, subscriptionHash); if (this.newUpdates) { return newPositions; } return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true); } handlePositions(client, message) { // // partial // { // table: 'position', // action: 'partial', // keys: [ 'account', 'symbol' ], // types: { // account: 'long', // symbol: 'symbol', // currency: 'symbol', // underlying: 'symbol', // quoteCurrency: 'symbol', // commission: 'float', // initMarginReq: 'float', // maintMarginReq: 'float', // riskLimit: 'long', // leverage: 'float', // crossMargin: 'boolean', // deleveragePercentile: 'float', // rebalancedPnl: 'long', // prevRealisedPnl: 'long', // prevUnrealisedPnl: 'long', // openingQty: 'long', // openOrderBuyQty: 'long', // openOrderBuyCost: 'long', // openOrderBuyPremium: 'long', // openOrderSellQty: 'long', // openOrderSellCost: 'long', // openOrderSellPremium: 'long', // currentQty: 'long', // currentCost: 'long', // currentComm: 'long', // realisedCost: 'long', // unrealisedCost: 'long', // grossOpenPremium: 'long', // isOpen: 'boolean', // markPrice: 'float', // markValue: 'long', // riskValue: 'long', // homeNotional: 'float', // foreignNotional: 'float', // posState: 'symbol', // posCost: 'long', // posCross: 'long', // posComm: 'long', // posLoss: 'long', // posMargin: 'long', // posMaint: 'long', // initMargin: 'long', // maintMargin: 'long', // realisedPnl: 'long', // unrealisedPnl: 'long', // unrealisedPnlPcnt: 'float', // unrealisedRoePcnt: 'float', // avgCostPrice: 'float', // avgEntryPrice: 'float', // breakEvenPrice: 'float', // marginCallPrice: 'float', // liquidationPrice: 'float', // bankruptPrice: 'float', // timestamp: 'timestamp' // }, // filter: { account: 412475 }, // data: [ // { // account: 412475, // symbol: 'XBTUSD', // currency: 'XBt', // underlying: 'XBT', // quoteCurrency: 'USD', // commission: 0.00075, // initMarginReq: 0.01, // maintMarginReq: 0.0035, // riskLimit: 20000000000, // leverage: 100, // crossMargin: true, // deleveragePercentile: 1, // rebalancedPnl: 0, // prevRealisedPnl: 0, // prevUnrealisedPnl: 0, // openingQty: 400, // openOrderBuyQty: 0, // openOrderBuyCost: 0, // openOrderBuyPremium: 0, // openOrderSellQty: 0, // openOrderSellCost: 0, // openOrderSellPremium: 0, // currentQty: 400, // currentCost: -912269, // currentComm: 684, // realisedCost: 0, // unrealisedCost: -912269, // grossOpenPremium: 0, // isOpen: true, // markPrice: 43772, // markValue: -913828, // riskValue: 913828, // homeNotional: 0.00913828, // foreignNotional: -400, // posCost: -912269, // posCross: 1559, // posComm: 694, // posLoss: 0, // posMargin: 11376, // posMaint: 3887, // initMargin: 0, // maintMargin: 9817, // realisedPnl: -684, // unrealisedPnl: -1559, // unrealisedPnlPcnt: -0.0017, // unrealisedRoePcnt: -0.1709, // avgCostPrice: 43846.7643, // avgEntryPrice: 43846.7643, // breakEvenPrice: 43880, // marginCallPrice: 20976, // liquidationPrice: 20976, // bankruptPrice: 20941, // timestamp: '2023-12-07T00:09:00.709Z' // } // ] // } // update // { // table: 'position', // action: 'update', // data: [ // { // account: 412475, // symbol: 'XBTUSD', // currency: 'XBt', // currentQty: 400, // markPrice: 43772.75, // markValue: -913812, // riskValue: 913812, // homeNotional: 0.00913812, // posCross: 1543, // posComm: 693, // posMargin: 11359, // posMaint: 3886, // maintMargin: 9816, // unrealisedPnl: -1543, // unrealisedRoePcnt: -0.1691, // liquidationPrice: 20976, // timestamp: '2023-12-07T00:09:10.760Z' // } // ] // } // if (this.positions === undefined) { this.positions = new ArrayCacheBySymbolBySide(); } const cache = this.positions; const rawPositions = this.safeValue(message, 'data', []); const newPositions = []; for (let i = 0; i < rawPositions.length; i++) { const rawPosition = rawPositions[i]; const position = this.parsePosition(rawPosition); newPositions.push(position); cache.append(position); } const messageHashes = this.findMessageHashes(client, 'positions::'); for (let i = 0; i < messageHashes.length; i++) { const messageHash = messageHashes[i]; const parts = messageHash.split('::'); const symbolsString = parts[1]; const symbols = symbolsString.split(','); const positions = this.filterByArray(newPositions, 'symbol', symbols, false); if (!this.isEmpty(positions)) { client.resolve(positions, messageHash); } } client.resolve(newPositions, 'positions'); } async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name bitmex#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 orde 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} */ await this.loadMarkets(); await this.authenticate(); const name = 'order'; const subscriptionHash = name; let messageHash = name; if (symbol !== undefined) { symbol = this.symbol(symbol); messageHash += ':' + symbol; } const url = this.urls['api']['ws']; const request = { 'op': 'subscribe', 'args': [ subscriptionHash, ], }; const orders = await this.watch(url, messageHash, request, subscriptionHash); if (this.newUpdates) { limit = orders.getLimit(symbol, limit); } return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true); } handleOrders(client, message) { // // { // "table": "order", // "action": "partial", // "keys": [ "orderID" ], // "types": { // "orderID": "guid", // "clOrdID": "string", // "clOrdLinkID": "symbol", // "account": "long", // "symbol": "symbol", // "side": "symbol", // "simpleOrderQty": "float", // "orderQty": "long", // "price": "float", // "displayQty": "long", // "stopPx": "float", // "pegOffsetValue": "float", // "pegPriceType": "symbol", // "currency": "symbol", // "settlCurrency": "symbol", // "ordType": "symbol", // "timeInForce": "symbol", // "execInst": "symbol", // "contingencyType": "symbol", // "exDestination": "symbol", // "ordStatus": "symbol", // "triggered": "symbol", // "workingIndicator": "boolean", // "ordRejReason": "symbol", // "simpleLeavesQty": "float", // "leavesQty": "long", // "simpleCumQty": "float", // "cumQty": "long", // "avgPx": "float", // "multiLegReportingType": "symbol", // "text": "string", // "transactTime": "timestamp", // "timestamp": "timestamp" // }, // "foreignKeys": { symbol: 'instrument', side: "side", ordStatus: "ordStatus" }, // "attributes": { // "orderID": "grouped", // "account": "grouped", // "ordStatus": "grouped", // "workingIndicator": "grouped" // }, // "filter": { account: 1455728 }, // "data": [ // { // "orderID": "56222c7a-9956-413a-82cf-99f4812c214b", // "clOrdID": '', // "clOrdLinkID": '', // "account": 1455728, // "symbol": "XBTUSD", // "side": "Sell", // "simpleOrderQty": null, // "orderQty": 1, // "price": 40000, // "displayQty": null, // "stopPx": null, // "pegOffsetValue": null, // "pegPriceType": '', // "currency": "USD", // "settlCurrency": "XBt", // "ordType": "Limit", // "timeInForce": "GoodTillCancel", // "execInst": '', // "contingencyType": '', // "exDestination": "XBME", // "ordStatus": "New", // "triggered": '', // "workingIndicator": true, // "ordRejReason": '', // "simpleLeavesQty": null, // "leavesQty": 1, // "simpleCumQty": null, // "cumQty": 0, // "avgPx": null, // "multiLegReportingType": "SingleSecurity", // "text": "Submitted via API.", // "transactTime": "2021-01-02T21:38:49.246Z", // "timestamp": "2021-01-02T21:38:49.246Z" // } // ] // } // // { // "table": "order", // "action": "insert", // "data": [ // { // "orderID": "fa993d8e-f7e4-46ed-8097-04f8e9393585", // "clOrdID": '', // "clOrdLinkID": '', // "account": 1455728, // "symbol": "XBTUSD", // "side": "Sell", // "simpleOrderQty": null, // "orderQty": 1, // "price": 40000, // "displayQty": null, // "stopPx": null, // "pegOffsetValue": null, // "pegPriceType": '', // "currency": "USD", // "settlCurrency": "XBt", // "ordType": "Limit", // "timeInForce": "GoodTillCancel", // "execInst": '', // "contingencyType": '', // "exDestination": "XBME", // "ordStatus": "New", // "triggered": '', // "workingIndicator": true, // "ordRejReason": '', // "simpleLeavesQty": null, // "leavesQty": 1, // "simpleCumQty": null, // "cumQty": 0, // "avgPx": null, // "multiLegReportingType": "SingleSecurity", // "text": "Submitted via API.", // "transactTime": "2021-01-02T23:49:02.286Z", // "timestamp": "2021-01-02T23:49:02.286Z" // } // ] // } // // // // { // "table": "order", // "action": "update", // "data": [ // { // "orderID": "fa993d8e-f7e4-46ed-8097-04f8e9393585", // "ordStatus": "Canceled", // "workingIndicator": false, // "leavesQty": 0, // "text": "Canceled: Canceled via API.\nSubmitted via API.", // "timestamp": "2021-01-02T23:50:51.272Z", // "clOrdID": '', // "account": 1455728, // "symbol": "XBTUSD" // } // ] // } // const data = this.safeValue(message, 'data', []); const messageHash = 'order'; // initial subscription response with multiple orders const dataLength = data.length; if (dataLength > 0) { if (this.orders === undefined) { const limit = this.safeInteger(this.options, 'ordersLimit', 1000); this.orders = new ArrayCacheBySymbolById(limit); } const stored = this.orders; const symbols = {}; for (let i = 0; i < dataLength; i++) { const currentOrder = data[i]; const orderId = this.safeString(currentOrder, 'orderID'); const previousOrder = this.safeValue(stored.hashmap, orderId); let rawOrder = currentOrder; if (previousOrder !== undefined) { rawOrder = this.extend(previousOrder['info'], currentOrder); } const order = this.parseOrder(rawOrder); stored.append(order); const symbol = order['symbol']; symbols[symbol] = true; } client.resolve(this.orders, messageHash); const keys = Object.keys(symbols); for (let i = 0; i < keys.length; i++) { const symbol = keys[i]; client.resolve(this.orders, messageHash + ':' + symbol); } } } async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name bitmex#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 */ await this.loadMarkets(); await this.authenticate(); const name = 'execution'; const subscriptionHash = name; let messageHash = name; if (symbol !== undefined) { symbol = this.symbol(symbol); messageHash += ':' + symbol; } const url = this.urls['api']['ws']; const request = { 'op': 'subscribe', 'args': [ subscriptionHash, ], }; const trades = await this.watch(url, messageHash, request, subscriptionHash); if (this.newUpdates) { limit = trades.getLimit(symbol, limit); } return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true); } handleMyTrades(client, message) { // // { // "table":"execution", // "action":"insert", // "data":[ // { // "execID":"0193e879-cb6f-2891-d099-2c4eb40fee21", // "orderID":"00000000-0000-0000-0000-000000000000", // "clOrdID":"", // "clOrdLinkID":"", // "account":2, // "symbol":"XBTUSD", // "side":"Sell", // "lastQty":1, // "lastPx":1134.37, // "underlyingLastPx":null, // "lastMkt":"XBME", // "lastLiquidityInd":"RemovedLiquidity", // "simpleOrderQty":null, // "orderQty":1, // "price":1134.37, // "displayQty":null, // "stopPx":null, // "pegOffsetValue":null, // "pegPriceType":"", // "currency":"USD", // "settlCurrency":"XBt", // "execType":"Trade", // "ordType":"Limit", // "timeInForce":"ImmediateOrCancel", // "execInst":"", // "contingencyType":"", // "exDestination":"XBME", // "ordStatus":"Filled", // "triggered":"", // "workingIndicator":false, // "ordRejReason":"", // "simpleLeavesQty":0, // "leavesQty":0, // "simpleCumQty":0.001, // "cumQty":1, // "avgPx":1134.37, // "commission":0.00075, // "tradePublishIndicator":"DoNotPublishTrade", // "multiLegReportingType":"SingleSecurity", // "text":"Liquidation", // "trdMatchID":"7f4ab7f6-0006-3234-76f4-ae1385aad00f", // "execCost":88155, // "execComm":66, // "homeNotional":-0.00088155, // "foreignNotional":1, // "transactTime":"2017-04-04T22:07:46.035Z", // "timestamp":"2017-04-04T22:07:46.035Z" // } // ] // } // const messageHash = this.safeString(message, 'table'); const data = this.safeValue(message, 'data', []); const dataByExecType = this.groupBy(data, 'execType'); const rawTrades = this.safeValue(dataByExecType, 'Trade', []); const trades = this.parseTrades(rawTrades); if (this.myTrades === undefined) { const limit = this.safeInteger(this.options, 'tradesLimit', 1000); this.myTrades = new ArrayCacheBySymbolById(limit); } const stored = this.myTrades; const symbols = {}; for (let j = 0; j < trades.length; j++) { const trade = trades[j]; const symbol = trade['symbol']; stored.append(trade); symbols[symbol] = trade; } const numTrades = trades.length; if (numTrades > 0) { client.resolve(stored, messageHash); } c