ccxt
Version:
1,115 lines (1,113 loc) • 78.7 kB
JavaScript
// ----------------------------------------------------------------------------
// 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 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,
'watchLiquidations': true,
'watchLiquidationsForSymbols': true,
'watchMyLiquidations': undefined,
'watchMyLiquidationsForSymbols': undefined,
'watchMyTrades': true,
'watchOHLCV': true,
'watchOrderBook': true,
'watchOrderBookForSymbols': true,
'watchOrders': true,
'watchPostions': true,
'watchTicker': true,
'watchTickers': true,
'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,
},
},
},
});
}
/**
* @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
* @see https://www.bitmex.com/app/wsAPI#Subscriptions
* @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();
symbol = this.symbol(symbol);
const tickers = await this.watchTickers([symbol], params);
return tickers[symbol];
}
/**
* @method
* @name bitmex#watchTickers
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
* @see https://www.bitmex.com/app/wsAPI#Subscriptions
* @param {string[]} symbols 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 watchTickers(symbols = undefined, params = {}) {
await this.loadMarkets();
symbols = this.marketSymbols(symbols, undefined, true);
const name = 'instrument';
const url = this.urls['api']['ws'];
const messageHashes = [];
const rawSubscriptions = [];
if (symbols !== undefined) {
for (let i = 0; i < symbols.length; i++) {
const symbol = symbols[i];
const market = this.market(symbol);
const subscription = name + ':' + market['id'];
rawSubscriptions.push(subscription);
const messageHash = 'ticker:' + symbol;
messageHashes.push(messageHash);
}
}
else {
rawSubscriptions.push(name);
messageHashes.push('alltickers');
}
const request = {
'op': 'subscribe',
'args': rawSubscriptions,
};
const ticker = await this.watchMultiple(url, messageHashes, this.extend(request, params), rawSubscriptions);
if (this.newUpdates) {
const result = {};
result[ticker['symbol']] = ticker;
return result;
}
return this.filterByArray(this.tickers, 'symbol', symbols);
}
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 data = this.safeList(message, 'data', []);
const tickers = {};
for (let i = 0; i < data.length; i++) {
const update = data[i];
const marketId = this.safeString(update, 'symbol');
const symbol = this.safeSymbol(marketId);
if (!(symbol in this.tickers)) {
this.tickers[symbol] = this.parseTicker({});
}
const updatedTicker = this.parseTicker(update);
const fullParsedTicker = this.deepExtend(this.tickers[symbol], updatedTicker);
tickers[symbol] = fullParsedTicker;
this.tickers[symbol] = fullParsedTicker;
const messageHash = 'ticker:' + symbol;
client.resolve(fullParsedTicker, messageHash);
client.resolve(fullParsedTicker, 'alltickers');
}
return message;
}
/**
* @method
* @name bitmex#watchLiquidations
* @description watch the public liquidations of a trading pair
* @see https://www.bitmex.com/app/wsAPI#Liquidation
* @param {string} symbol unified CCXT market symbol
* @param {int} [since] the earliest time in ms to fetch liquidations for
* @param {int} [limit] the maximum number of liquidation structures to retrieve
* @param {object} [params] exchange specific parameters for the bitmex api endpoint
* @returns {object} an array of [liquidation structures]{@link https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure}
*/
async watchLiquidations(symbol, since = undefined, limit = undefined, params = {}) {
return this.watchLiquidationsForSymbols([symbol], since, limit, params);
}
/**
* @method
* @name bitmex#watchLiquidationsForSymbols
* @description watch the public liquidations of a trading pair
* @see https://www.bitmex.com/app/wsAPI#Liquidation
* @param {string[]} symbols
* @param {int} [since] the earliest time in ms to fetch liquidations for
* @param {int} [limit] the maximum number of liquidation structures to retrieve
* @param {object} [params] exchange specific parameters for the bitmex api endpoint
* @returns {object} an array of [liquidation structures]{@link https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure}
*/
async watchLiquidationsForSymbols(symbols = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
symbols = this.marketSymbols(symbols, undefined, true, true);
const messageHashes = [];
const subscriptionHashes = [];
if (this.isEmpty(symbols)) {
subscriptionHashes.push('liquidation');
messageHashes.push('liquidations');
}
else {
for (let i = 0; i < symbols.length; i++) {
const symbol = symbols[i];
const market = this.market(symbol);
subscriptionHashes.push('liquidation:' + market['id']);
messageHashes.push('liquidations::' + symbol);
}
}
const url = this.urls['api']['ws'];
const request = {
'op': 'subscribe',
'args': subscriptionHashes,
};
const newLiquidations = await this.watchMultiple(url, messageHashes, this.deepExtend(request, params), subscriptionHashes);
if (this.newUpdates) {
return newLiquidations;
}
return this.filterBySymbolsSinceLimit(this.liquidations, symbols, since, limit, true);
}
handleLiquidation(client, message) {
//
// {
// "table":"liquidation",
// "action":"partial",
// "keys":[
// "orderID"
// ],
// "types":{
// "orderID":"guid",
// "symbol":"symbol",
// "side":"symbol",
// "price":"float",
// "leavesQty":"long"
// },
// "filter":{},
// "data":[
// {
// "orderID":"e0a568ee-7830-4428-92c3-73e82b9576ce",
// "symbol":"XPLAUSDT",
// "side":"Sell",
// "price":0.206,
// "leavesQty":340
// }
// ]
// }
//
const rawLiquidations = this.safeValue(message, 'data', []);
const newLiquidations = [];
for (let i = 0; i < rawLiquidations.length; i++) {
const rawLiquidation = rawLiquidations[i];
const liquidation = this.parseLiquidation(rawLiquidation);
const symbol = liquidation['symbol'];
let liquidations = this.safeValue(this.liquidations, symbol);
if (liquidations === undefined) {
const limit = this.safeInteger(this.options, 'liquidationsLimit', 1000);
liquidations = new ArrayCache(limit);
}
liquidations.append(liquidation);
this.liquidations[symbol] = liquidations;
newLiquidations.push(liquidation);
}
client.resolve(newLiquidations, 'liquidations');
const liquidationsBySymbol = this.indexBy(newLiquidations, 'symbol');
const symbols = Object.keys(liquidationsBySymbol);
for (let i = 0; i < symbols.length; i++) {
const symbol = symbols[i];
client.resolve(liquidationsBySymbol[symbol], 'liquidations::' + symbol);
}
}
/**
* @method
* @name bitmex#watchBalance
* @description watch balance and get the amount of funds available for trading or funds locked in orders
* @see https://www.bitmex.com/app/wsAPI#Subscriptions
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
*/
async watchBalance(params = {}) {
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 symbol = market['symbol'];
const messageHash = table + ':' + 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);
}
}
/**
* @method
* @name bitmex#watchTrades
* @description get the list of most recent trades for a particular symbol
* @see https://www.bitmex.com/app/wsAPI#Subscriptions
* @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 = {}) {
return await this.watchTradesForSymbols([symbol], since, limit, params);
}
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 await future;
}
handleAuthenticationMessage(client, message) {
const authenticated = this.safeBool(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];
}
}
}
/**
* @method
* @name bitmex#watchPositions
* @description watch all open positions
* @see https://www.bitmex.com/app/wsAPI#Subscriptions
* @param {string[]|undefined} symbols list of unified market symbols
* @param {int} [since] the earliest time in ms to watch positions for
* @param {int} [limit] the maximum number of positions to retrieve
* @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}
*/
async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
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');
}
/**
* @method
* @name bitmex#watchOrders
* @description watches information on multiple orders made by the user
* @see https://www.bitmex.com/app/wsAPI#Subscriptions
* @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();
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"
// }
//