sfccxt
Version:
A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges
844 lines (818 loc) • 36.3 kB
JavaScript
'use strict';
// ---------------------------------------------------------------------------
const deribitRest = require ('../deribit');
const { NotSupported, ExchangeError } = require ('../base/errors');
const { ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp } = require ('./base/Cache');
// ---------------------------------------------------------------------------
module.exports = class deribit extends deribitRest {
describe () {
return this.deepExtend (super.describe (), {
'has': {
'ws': true,
'watchBalance': true,
'watchTicker': true,
'watchTickers': false,
'watchTrades': true,
'watchMyTrades': true,
'watchOrders': true,
'watchOrderBook': true,
'watchOHLCV': true,
},
'urls': {
'test': {
'ws': 'wss://test.deribit.com/ws/api/v2',
},
'api': {
'ws': 'wss://www.deribit.com/ws/api/v2',
},
},
'options': {
'timeframes': {
'1m': 1,
'3m': 3,
'5m': 5,
'15m': 15,
'30m': 30,
'1h': 60,
'2h': 120,
'4h': 180,
'6h': 360,
'12h': 720,
'1d': '1D',
},
'currencies': [ 'BTC', 'ETH', 'SOL', 'USDC' ],
},
'streaming': {
},
'exceptions': {
},
});
}
requestId () {
const requestId = this.sum (this.safeInteger (this.options, 'requestId', 0), 1);
this.options['requestId'] = requestId;
return requestId;
}
async watchBalance (params = {}) {
/**
* @method
* @name deribit#watchBalance
* @see https://docs.deribit.com/#user-portfolio-currency
* @description query for balance and get the amount of funds available for trading or funds locked in orders
* @param {object} params extra parameters specific to the deribit api endpoint
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure}
*/
await this.authenticate (params);
const messageHash = 'balance';
const url = this.urls['api']['ws'];
const currencies = this.safeValue (this.options, 'currencies', []);
const channels = [];
for (let i = 0; i < currencies.length; i++) {
const currencyCode = currencies[i];
channels.push ('user.portfolio.' + currencyCode);
}
const subscribe = {
'jsonrpc': '2.0',
'method': 'private/subscribe',
'params': {
'channels': channels,
},
'id': this.requestId (),
};
const request = this.deepExtend (subscribe, params);
return await this.watch (url, messageHash, request, messageHash, request);
}
handleBalance (client, message) {
//
// subscription
// {
// jsonrpc: '2.0',
// method: 'subscription',
// params: {
// channel: 'user.portfolio.btc',
// data: {
// total_pl: 0,
// session_upl: 0,
// session_rpl: 0,
// projected_maintenance_margin: 0,
// projected_initial_margin: 0,
// projected_delta_total: 0,
// portfolio_margining_enabled: false,
// options_vega: 0,
// options_value: 0,
// options_theta: 0,
// options_session_upl: 0,
// options_session_rpl: 0,
// options_pl: 0,
// options_gamma: 0,
// options_delta: 0,
// margin_balance: 0.0015,
// maintenance_margin: 0,
// initial_margin: 0,
// futures_session_upl: 0,
// futures_session_rpl: 0,
// futures_pl: 0,
// fee_balance: 0,
// estimated_liquidation_ratio_map: {},
// estimated_liquidation_ratio: 0,
// equity: 0.0015,
// delta_total_map: {},
// delta_total: 0,
// currency: 'BTC',
// balance: 0.0015,
// available_withdrawal_funds: 0.0015,
// available_funds: 0.0015
// }
// }
// }
//
const params = this.safeValue (message, 'params', {});
const data = this.safeValue (params, 'data', {});
const currencyId = this.safeString (data, 'currency');
const currencyCode = this.safeCurrencyCode (currencyId);
const balance = this.parseBalance (data);
this.balance[currencyCode] = balance;
const messageHash = 'balance';
client.resolve (this.balance, messageHash);
}
async watchTicker (symbol, params = {}) {
/**
* @method
* @name deribit#watchTicker
* @see https://docs.deribit.com/#ticker-instrument_name-interval
* @description watches a price ticker, a statistical calculation with the information 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 deribit api endpoint
* @param {str|undefined} params.interval specify aggregation and frequency of notifications. Possible values: 100ms, raw
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure}
*/
const market = this.market (symbol);
const url = this.urls['api']['ws'];
const interval = this.safeString (params, 'interval', '100ms');
params = this.omit (params, 'interval');
await this.loadMarkets ();
if (interval === 'raw') {
await this.authenticate ();
}
const channel = 'ticker.' + market['id'] + '.' + interval;
const message = {
'jsonrpc': '2.0',
'method': 'public/subscribe',
'params': {
'channels': [ 'ticker.' + market['id'] + '.' + interval ],
},
'id': this.requestId (),
};
const request = this.deepExtend (message, params);
return await this.watch (url, channel, request, channel, request);
}
handleTicker (client, message) {
//
// {
// jsonrpc: '2.0',
// method: 'subscription',
// params: {
// channel: 'ticker.BTC_USDC-PERPETUAL.raw',
// data: {
// timestamp: 1655393725041,
// stats: [Object],
// state: 'open',
// settlement_price: 21729.5891,
// open_interest: 164.501,
// min_price: 20792.9376,
// max_price: 21426.225,
// mark_price: 21109.555,
// last_price: 21132,
// instrument_name: 'BTC_USDC-PERPETUAL',
// index_price: 21122.3937,
// funding_8h: -0.00022427,
// estimated_delivery_price: 21122.3937,
// current_funding: -0.00010782,
// best_bid_price: 21106,
// best_bid_amount: 1.143,
// best_ask_price: 21113,
// best_ask_amount: 0.327
// }
// }
// }
//
const params = this.safeValue (message, 'params', {});
const data = this.safeValue (params, 'data', {});
const marketId = this.safeString (data, 'instrument_name');
const symbol = this.safeSymbol (marketId);
const ticker = this.parseTicker (data);
const messageHash = this.safeString (params, 'channel');
this.tickers[symbol] = ticker;
client.resolve (ticker, messageHash);
}
async watchTrades (symbol, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name deribit#watchTrades
* @description get the list of most recent trades for a particular symbol
* @see https://docs.deribit.com/#trades-instrument_name-interval
* @param {string} symbol unified symbol of the market to fetch trades for
* @param {int|undefined} since timestamp in ms of the earliest trade to fetch
* @param {int|undefined} limit the maximum amount of trades to fetch
* @param {object} params extra parameters specific to the deribit api endpoint
* @param {str|undefined} params.interval specify aggregation and frequency of notifications. Possible values: 100ms, raw
* @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
*/
await this.loadMarkets ();
const market = this.market (symbol);
const url = this.urls['api']['ws'];
const interval = this.safeString (params, 'interval', '100ms');
params = this.omit (params, 'interval');
const channel = 'trades.' + market['id'] + '.' + interval;
if (interval === 'raw') {
await this.authenticate ();
}
const message = {
'jsonrpc': '2.0',
'method': 'public/subscribe',
'params': {
'channels': [ channel ],
},
'id': this.requestId (),
};
const request = this.deepExtend (message, params);
const trades = await this.watch (url, channel, request, channel, request);
return this.filterBySinceLimit (trades, since, limit, 'timestamp', true);
}
handleTrades (client, message) {
//
// {
// "jsonrpc": "2.0",
// "method": "subscription",
// "params": {
// "channel": "trades.BTC_USDC-PERPETUAL.100ms",
// "data": [{
// "trade_seq": 501899,
// "trade_id": "USDC-2436803",
// "timestamp": 1655397355998,
// "tick_direction": 2,
// "price": 21026,
// "mark_price": 21019.9719,
// "instrument_name": "BTC_USDC-PERPETUAL",
// "index_price": 21031.7847,
// "direction": "buy",
// "amount": 0.049
// }]
// }
// }
//
const params = this.safeValue (message, 'params', {});
const channel = this.safeString (params, 'channel', '');
const parts = channel.split ('.');
const marketId = this.safeString (parts, 1);
const symbol = this.safeSymbol (marketId);
const market = this.safeMarket (marketId);
const trades = this.safeValue (params, 'data', []);
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 i = 0; i < trades.length; i++) {
const trade = trades[i];
const parsed = this.parseTrade (trade, market);
stored.append (parsed);
}
this.trades[symbol] = stored;
client.resolve (this.trades[symbol], channel);
}
async watchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name deribit#watchMyTrades
* @description get the list of trades associated with the user
* @see https://docs.deribit.com/#user-trades-instrument_name-interval
* @param {string} symbol unified symbol of the market to fetch trades for. Use 'any' to watch all trades
* @param {int|undefined} since timestamp in ms of the earliest trade to fetch
* @param {int|undefined} limit the maximum amount of trades to fetch
* @param {object} params extra parameters specific to the deribit api endpoint
* @param {str|undefined} params.interval specify aggregation and frequency of notifications. Possible values: 100ms, raw
* @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
*/
await this.authenticate (params);
if (symbol !== undefined) {
await this.loadMarkets ();
symbol = this.symbol (symbol);
}
const url = this.urls['api']['ws'];
const interval = this.safeString (params, 'interval', 'raw');
params = this.omit (params, 'interval');
const channel = 'user.trades.any.any.' + interval;
const message = {
'jsonrpc': '2.0',
'method': 'private/subscribe',
'params': {
'channels': [ channel ],
},
'id': this.requestId (),
};
const request = this.deepExtend (message, params);
const trades = await this.watch (url, channel, request, channel, request);
return this.filterBySymbolSinceLimit (trades, symbol, since, limit, true);
}
handleMyTrades (client, message) {
//
// {
// "jsonrpc": "2.0",
// "method": "subscription",
// "params": {
// "channel": "user.trades.any.any.raw",
// "data": [{
// "trade_seq": 149546319,
// "trade_id": "219381310",
// "timestamp": 1655421193564,
// "tick_direction": 0,
// "state": "filled",
// "self_trade": false,
// "reduce_only": false,
// "profit_loss": 0,
// "price": 20236.5,
// "post_only": false,
// "order_type": "market",
// "order_id": "46108941243",
// "matching_id": null,
// "mark_price": 20233.96,
// "liquidity": "T",
// "instrument_name": "BTC-PERPETUAL",
// "index_price": 20253.31,
// "fee_currency": "BTC",
// "fee": 2.5e-7,
// "direction": "buy",
// "amount": 10
// }]
// }
// }
//
const params = this.safeValue (message, 'params', {});
const channel = this.safeString (params, 'channel', '');
const trades = this.safeValue (params, 'data', []);
let cachedTrades = this.myTrades;
if (cachedTrades === undefined) {
const limit = this.safeInteger (this.options, 'tradesLimit', 1000);
cachedTrades = new ArrayCacheBySymbolById (limit);
}
const parsed = this.parseTrades (trades);
const marketIds = {};
for (let i = 0; i < parsed.length; i++) {
const trade = parsed[i];
cachedTrades.append (trade);
const symbol = trade['symbol'];
marketIds[symbol] = true;
}
client.resolve (cachedTrades, channel);
}
async watchOrderBook (symbol, limit = undefined, params = {}) {
/**
* @method
* @name deribit#watchOrderBook
* @see https://docs.deribit.com/#public-get_book_summary_by_instrument
* @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|undefined} limit the maximum amount of order book entries to return
* @param {object} params extra parameters specific to the deribit api endpoint
* @param {string} params.interval Frequency of notifications. Events will be aggregated over this interval. Possible values: 100ms, raw
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-book-structure} indexed by market symbols
*/
await this.loadMarkets ();
const market = this.market (symbol);
const url = this.urls['api']['ws'];
const interval = this.safeString (params, 'interval', '100ms');
params = this.omit (params, 'interval');
if (interval === 'raw') {
await this.authenticate ();
}
const channel = 'book.' + market['id'] + '.' + interval;
const subscribe = {
'jsonrpc': '2.0',
'method': 'public/subscribe',
'params': {
'channels': [ channel ],
},
'id': this.requestId (),
};
const request = this.deepExtend (subscribe, params);
const orderbook = await this.watch (url, channel, request, channel);
return orderbook.limit ();
}
handleOrderBook (client, message) {
//
// snapshot
// {
// "jsonrpc": "2.0",
// "method": "subscription",
// "params": {
// "channel": "book.BTC_USDC-PERPETUAL.raw",
// "data": {
// "type": "snapshot",
// "timestamp": 1655395057025,
// "instrument_name": "BTC_USDC-PERPETUAL",
// "change_id": 1550694837,
// "bids": [
// ["new", 20987, 0.487],
// ["new", 20986, 0.238],
// ],
// "asks": [
// ["new", 20999, 0.092],
// ["new", 21000, 1.238],
// ]
// }
// }
// }
//
// change
// {
// "jsonrpc": "2.0",
// "method": "subscription",
// "params": {
// "channel": "book.BTC_USDC-PERPETUAL.raw",
// "data": {
// "type": "change",
// "timestamp": 1655395168086,
// "prev_change_id": 1550724481,
// "instrument_name": "BTC_USDC-PERPETUAL",
// "change_id": 1550724483,
// "bids": [
// ["new", 20977, 0.109],
// ["delete", 20975, 0]
// ],
// "asks": []
// }
// }
// }
//
const params = this.safeValue (message, 'params', {});
const data = this.safeValue (params, 'data', {});
const channel = this.safeString (params, 'channel');
const marketId = this.safeString (data, 'instrument_name');
const symbol = this.safeSymbol (marketId);
const timestamp = this.safeNumber (data, 'timestamp');
let storedOrderBook = this.safeValue (this.orderbooks, symbol);
if (storedOrderBook === undefined) {
storedOrderBook = this.countedOrderBook ();
}
const asks = this.safeValue (data, 'asks', []);
const bids = this.safeValue (data, 'bids', []);
this.handleDeltas (storedOrderBook['asks'], asks);
this.handleDeltas (storedOrderBook['bids'], bids);
storedOrderBook['nonce'] = timestamp;
storedOrderBook['timestamp'] = timestamp;
storedOrderBook['datetime'] = this.iso8601 (timestamp);
storedOrderBook['symbol'] = symbol;
this.orderbooks[symbol] = storedOrderBook;
client.resolve (storedOrderBook, channel);
}
cleanOrderBook (data) {
const bids = this.safeValue (data, 'bids', []);
const asks = this.safeValue (data, 'asks', []);
const cleanedBids = [];
for (let i = 0; i < bids.length; i++) {
cleanedBids.push ([ bids[i][1], bids[i][2] ]);
}
const cleanedAsks = [];
for (let i = 0; i < asks.length; i++) {
cleanedAsks.push ([ asks[i][1], asks[i][2] ]);
}
data['bids'] = cleanedBids;
data['asks'] = cleanedAsks;
return data;
}
handleDelta (bookside, delta) {
const price = delta[1];
const amount = delta[2];
if (delta[0] === 'new' || delta[0] === 'change') {
bookside.store (price, amount, 1);
} else if (delta[0] === 'delete') {
bookside.store (price, amount, 0);
}
}
handleDeltas (bookside, deltas) {
for (let i = 0; i < deltas.length; i++) {
this.handleDelta (bookside, deltas[i]);
}
}
async watchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name deribit#watchOrders
* @see https://docs.deribit.com/#user-orders-instrument_name-raw
* @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|undefined} since the earliest time in ms to fetch orders for
* @param {int|undefined} limit the maximum number of orde structures to retrieve
* @param {object} params extra parameters specific to the deribit api endpoint
* @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure
*/
await this.loadMarkets ();
await this.authenticate (params);
if (symbol !== undefined) {
symbol = this.symbol (symbol);
}
const url = this.urls['api']['ws'];
const currency = this.safeString (params, 'currency', 'any');
const interval = this.safeString (params, 'interval', 'raw');
const kind = this.safeString (params, 'kind', 'any');
params = this.omit (params, 'interval', 'currency', 'kind');
const channel = 'user.orders.' + kind + '.' + currency + '.' + interval;
const message = {
'jsonrpc': '2.0',
'method': 'private/subscribe',
'params': {
'channels': [ channel ],
},
'id': this.requestId (),
};
const request = this.deepExtend (message, params);
const orders = await this.watch (url, channel, request, channel, request);
if (this.newUpdates) {
limit = orders.getLimit (symbol, limit);
}
return this.filterBySymbolSinceLimit (orders, symbol, since, limit, true);
}
handleOrders (client, message) {
// Does not return a snapshot of current orders
//
// {
// jsonrpc: '2.0',
// method: 'subscription',
// params: {
// channel: 'user.orders.any.any.raw',
// data: {
// web: true,
// time_in_force: 'good_til_cancelled',
// replaced: false,
// reduce_only: false,
// profit_loss: 0,
// price: 50000,
// post_only: false,
// order_type: 'limit',
// order_state: 'open',
// order_id: '46094375191',
// max_show: 10,
// last_update_timestamp: 1655401625037,
// label: '',
// is_liquidation: false,
// instrument_name: 'BTC-PERPETUAL',
// filled_amount: 0,
// direction: 'sell',
// creation_timestamp: 1655401625037,
// commission: 0,
// average_price: 0,
// api: false,
// amount: 10
// }
// }
// }
//
if (this.orders === undefined) {
const limit = this.safeInteger (this.options, 'ordersLimit', 1000);
this.orders = new ArrayCacheBySymbolById (limit);
}
const params = this.safeValue (message, 'params', {});
const channel = this.safeString (params, 'channel', '');
const data = this.safeValue (params, 'data', {});
let orders = [];
if (Array.isArray (data)) {
orders = this.parseOrders (data);
} else {
const order = this.parseOrder (data);
orders = [ order ];
}
for (let i = 0; i < orders.length; i++) {
this.orders.append (orders[i]);
}
client.resolve (this.orders, channel);
}
async watchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name deribit#watchOHLCV
* @see https://docs.deribit.com/#chart-trades-instrument_name-resolution
* @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|undefined} since timestamp in ms of the earliest candle to fetch
* @param {int|undefined} limit the maximum amount of candles to fetch
* @param {object} params extra parameters specific to the deribit api endpoint
* @returns {[[int]]} A list of candles ordered as timestamp, open, high, low, close, volume
*/
await this.loadMarkets ();
const market = this.market (symbol);
const url = this.urls['api']['ws'];
const timeframes = this.safeValue (this.options, 'timeframes', {});
const interval = this.safeString (timeframes, timeframe);
if (interval === undefined) {
throw new NotSupported (this.id + ' this interval is not supported, please provide one of the supported timeframes');
}
const channel = 'chart.trades.' + market['id'] + '.' + interval;
const message = {
'jsonrpc': '2.0',
'method': 'public/subscribe',
'params': {
'channels': [ channel ],
},
'id': this.requestId (),
};
const request = this.deepExtend (message, params);
const ohlcv = await this.watch (url, channel, request, channel, request);
if (this.newUpdates) {
limit = ohlcv.getLimit (market['symbol'], limit);
}
return this.filterBySinceLimit (ohlcv, since, limit, 0, true);
}
handleOHLCV (client, message) {
//
// {
// jsonrpc: '2.0',
// method: 'subscription',
// params: {
// channel: 'chart.trades.BTC_USDC-PERPETUAL.1',
// data: {
// volume: 0,
// tick: 1655403420000,
// open: 20951,
// low: 20951,
// high: 20951,
// cost: 0,
// close: 20951
// }
// }
// }
//
const params = this.safeValue (message, 'params', {});
const channel = this.safeString (params, 'channel', '');
const parts = channel.split ('.');
const marketId = this.safeString (parts, 2);
const symbol = this.safeSymbol (marketId);
const ohlcv = this.safeValue (params, 'data', {});
const parsed = [
this.safeNumber (ohlcv, 'tick'),
this.safeNumber (ohlcv, 'open'),
this.safeNumber (ohlcv, 'high'),
this.safeNumber (ohlcv, 'low'),
this.safeNumber (ohlcv, 'close'),
this.safeNumber (ohlcv, 'volume'),
];
let stored = this.safeValue (this.ohlcvs, symbol);
if (stored === undefined) {
const limit = this.safeInteger (this.options, 'OHLCVLimit', 1000);
stored = new ArrayCacheByTimestamp (limit);
}
stored.append (parsed);
this.ohlcvs[symbol] = stored;
client.resolve (stored, channel);
}
handleMessage (client, message) {
//
// error
// {
// "jsonrpc": "2.0",
// "id": 1,
// "error": {
// "message": "Invalid params",
// "data": {
// "reason": "invalid format",
// "param": "nonce"
// },
// "code": -32602
// },
// "usIn": "1655391709417993",
// "usOut": "1655391709418049",
// "usDiff": 56,
// "testnet": false
// }
//
// subscribe
// {
// jsonrpc: '2.0',
// id: 2,
// result: ['ticker.BTC_USDC-PERPETUAL.raw'],
// usIn: '1655393625889396',
// usOut: '1655393625889518',
// usDiff: 122,
// testnet: false
// }
//
// notification
// {
// jsonrpc: '2.0',
// method: 'subscription',
// params: {
// channel: 'ticker.BTC_USDC-PERPETUAL.raw',
// data: {
// timestamp: 1655393724752,
// stats: [Object],
// state: 'open',
// settlement_price: 21729.5891,
// open_interest: 164.501,
// min_price: 20792.9001,
// max_price: 21426.1864,
// mark_price: 21109.4757,
// last_price: 21132,
// instrument_name: 'BTC_USDC-PERPETUAL',
// index_price: 21122.3937,
// funding_8h: -0.00022427,
// estimated_delivery_price: 21122.3937,
// current_funding: -0.00011158,
// best_bid_price: 21106,
// best_bid_amount: 1.143,
// best_ask_price: 21113,
// best_ask_amount: 0.402
// }
// }
// }
//
const error = this.safeValue (message, 'error');
if (error !== undefined) {
throw new ExchangeError (this.id + ' ' + this.json (error));
}
const params = this.safeValue (message, 'params');
const channel = this.safeString (params, 'channel');
if (channel !== undefined) {
const parts = channel.split ('.');
const channelId = this.safeString (parts, 0);
const userHandlers = {
'trades': this.handleMyTrades,
'portfolio': this.handleBalance,
'orders': this.handleOrders,
};
const handlers = {
'ticker': this.handleTicker,
'book': this.handleOrderBook,
'trades': this.handleTrades,
'chart': this.handleOHLCV,
'user': this.safeValue (userHandlers, this.safeString (parts, 1)),
};
const handler = this.safeValue (handlers, channelId);
if (handler !== undefined) {
return handler.call (this, client, message);
}
throw new NotSupported (this.id + ' no handler found for this message ' + this.json (message));
}
const result = this.safeValue (message, 'result', {});
const accessToken = this.safeString (result, 'access_token');
if (accessToken !== undefined) {
return this.handleAuthenticationMessage (client, message);
}
return message;
}
handleAuthenticationMessage (client, message) {
//
// {
// jsonrpc: '2.0',
// id: 1,
// result: {
// token_type: 'bearer',
// scope: 'account:read_write block_trade:read_write connection custody:read_write mainaccount name:ccxt trade:read_write wallet:read_write',
// refresh_token: '1686927372328.1EzFBRmt.logRQWXkPA1oE_Tk0gRsls9Hau7YN6a321XUBnxvR4x6cryhbkKcniUJU-czA8_zKXrqQGpQmfoDwhLIjIsWCvRuu6otbg-LKWlrtTX1GQqLcPaTTHAdZGTMV-HM8HiS03QBd9MIXWRfF53sKj2hdR9nZPZ6MH1XrkpAZPB_peuEEB9wlcc3elzWEZFtCmiy1fnQ8TPHwAJMt3nuUmEcMLt_-F554qrsg_-I66D9xMiifJj4dBemdPfV_PkGPRIwIoKlxDjyv2-xfCw-4eKyo6Hu1m2h6gT1DPOTxSXcBgfBQjpi-_uY3iAIj7U6xjC46PHthEdquhEuCTZl7UfCRZSAWwZA',
// expires_in: 31536000,
// access_token: '1686923272328.1CkwEx-u.qHradpIulmuoeboKMEi8PkQ1_4DF8yFE2zywBTtkD32sruVC53b1HwL5OWRuh2nYAndXff4xuXIMRkkEfMAFCeq24prihxxinoS8DDVkKBxedGx4CUPJFeXjmh7wuRGqQOLg1plXOpbF3fwF2KPEkAuETwcpcVY6K9HUVjutNRfxFe2TR7CvuS9x8TATvoPeu7H1ezYl-LkKSaRifdTXuwituXgp4oDbPRyQLniEBWuYF9rY7qbABxuOJlXI1VZ63u7Bh0mGWei-KeVeqHGNpy6OgrFRPXPxa9_U7vaxCyHW3zZ9959TQ1QUMLWtUX-NLBEv3BT5eCieW9HORYIOKfsgkpd3'
// },
// usIn: '1655391872327712',
// usOut: '1655391872328515',
// usDiff: 803,
// testnet: false
// }
//
const future = this.safeValue (client.futures, 'authenticated');
if (future !== undefined) {
future.resolve (true);
}
return message;
}
async authenticate (params = {}) {
const url = this.urls['api']['ws'];
const client = this.client (url);
const time = this.milliseconds ();
const timeString = this.numberToString (time);
const nonce = timeString;
const messageHash = 'authenticated';
const future = client.future ('authenticated');
const authenticated = this.safeValue (client.subscriptions, messageHash);
if (authenticated === undefined) {
this.checkRequiredCredentials ();
const requestId = this.requestId ();
const signature = this.hmac (this.encode (timeString + '\n' + nonce + '\n'), this.encode (this.secret), 'sha256');
const request = {
'jsonrpc': '2.0',
'id': requestId,
'method': 'public/auth',
'params': {
'grant_type': 'client_signature',
'client_id': this.apiKey,
'timestamp': time,
'signature': signature,
'nonce': nonce,
'data': '',
},
};
this.spawn (this.watch, url, messageHash, this.extend (request, params), messageHash);
}
return await future;
}
};