ccxt 4.2.36 → 4.2.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,9 +16,11 @@ class gemini extends gemini$1 {
16
16
  'watchTicker': false,
17
17
  'watchTickers': false,
18
18
  'watchTrades': true,
19
+ 'watchTradesForSymbols': true,
19
20
  'watchMyTrades': false,
20
21
  'watchOrders': true,
21
22
  'watchOrderBook': true,
23
+ 'watchOrderBookForSymbols': true,
22
24
  'watchOHLCV': true,
23
25
  },
24
26
  'hostname': 'api.gemini.com',
@@ -67,7 +69,29 @@ class gemini extends gemini$1 {
67
69
  }
68
70
  return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
69
71
  }
72
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
73
+ /**
74
+ * @method
75
+ * @name gemini#watchTradesForSymbols
76
+ * @see https://docs.gemini.com/websocket-api/#multi-market-data
77
+ * @description get the list of most recent trades for a list of symbols
78
+ * @param {string[]} symbols unified symbol of the market to fetch trades for
79
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
80
+ * @param {int} [limit] the maximum amount of trades to fetch
81
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
82
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
83
+ */
84
+ const trades = await this.helperForWatchMultipleConstruct('trades', symbols, params);
85
+ if (this.newUpdates) {
86
+ const first = this.safeList(trades, 0);
87
+ const tradeSymbol = this.safeString(first, 'symbol');
88
+ limit = trades.getLimit(tradeSymbol, limit);
89
+ }
90
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
91
+ }
70
92
  parseWsTrade(trade, market = undefined) {
93
+ //
94
+ // regular v2 trade
71
95
  //
72
96
  // {
73
97
  // "type": "trade",
@@ -79,11 +103,31 @@ class gemini extends gemini$1 {
79
103
  // "side": "buy"
80
104
  // }
81
105
  //
106
+ // multi data trade
107
+ //
108
+ // {
109
+ // "type": "trade",
110
+ // "symbol": "ETHUSD",
111
+ // "tid": "1683002242170204", // this is not TS, but somewhat ID
112
+ // "price": "2299.24",
113
+ // "amount": "0.002662",
114
+ // "makerSide": "bid"
115
+ // }
116
+ //
82
117
  const timestamp = this.safeInteger(trade, 'timestamp');
83
- const id = this.safeString(trade, 'event_id');
118
+ const id = this.safeString2(trade, 'event_id', 'tid');
84
119
  const priceString = this.safeString(trade, 'price');
85
- const amountString = this.safeString(trade, 'quantity');
86
- const side = this.safeStringLower(trade, 'side');
120
+ const amountString = this.safeString2(trade, 'quantity', 'amount');
121
+ let side = this.safeStringLower(trade, 'side');
122
+ if (side === undefined) {
123
+ const marketSide = this.safeStringLower(trade, 'makerSide');
124
+ if (marketSide === 'bid') {
125
+ side = 'sell';
126
+ }
127
+ else if (marketSide === 'ask') {
128
+ side = 'buy';
129
+ }
130
+ }
87
131
  const marketId = this.safeStringLower(trade, 'symbol');
88
132
  const symbol = this.safeSymbol(marketId, market);
89
133
  return this.safeTrade({
@@ -183,6 +227,34 @@ class gemini extends gemini$1 {
183
227
  client.resolve(stored, messageHash);
184
228
  }
185
229
  }
230
+ handleTradesForMultidata(client, trades, timestamp) {
231
+ if (trades !== undefined) {
232
+ const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
233
+ const storesForSymbols = {};
234
+ for (let i = 0; i < trades.length; i++) {
235
+ const marketId = trades[i]['symbol'];
236
+ const market = this.safeMarket(marketId.toLowerCase());
237
+ const symbol = market['symbol'];
238
+ const trade = this.parseWsTrade(trades[i], market);
239
+ trade['timestamp'] = timestamp;
240
+ trade['datetime'] = this.iso8601(timestamp);
241
+ let stored = this.safeValue(this.trades, symbol);
242
+ if (stored === undefined) {
243
+ stored = new Cache.ArrayCache(tradesLimit);
244
+ this.trades[symbol] = stored;
245
+ }
246
+ stored.append(trade);
247
+ storesForSymbols[symbol] = stored;
248
+ }
249
+ const symbols = Object.keys(storesForSymbols);
250
+ for (let i = 0; i < symbols.length; i++) {
251
+ const symbol = symbols[i];
252
+ const stored = storesForSymbols[symbol];
253
+ const messageHash = 'trades:' + symbol;
254
+ client.resolve(stored, messageHash);
255
+ }
256
+ }
257
+ }
186
258
  async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
187
259
  /**
188
260
  * @method
@@ -328,6 +400,93 @@ class gemini extends gemini$1 {
328
400
  this.orderbooks[symbol] = orderbook;
329
401
  client.resolve(orderbook, messageHash);
330
402
  }
403
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
404
+ /**
405
+ * @method
406
+ * @name gemini#watchOrderBookForSymbols
407
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
408
+ * @see https://docs.gemini.com/websocket-api/#multi-market-data
409
+ * @param {string[]} symbols unified array of symbols
410
+ * @param {int} [limit] the maximum amount of order book entries to return
411
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
412
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
413
+ */
414
+ const orderbook = await this.helperForWatchMultipleConstruct('orderbook', symbols, params);
415
+ return orderbook.limit();
416
+ }
417
+ async helperForWatchMultipleConstruct(itemHashName, symbols, params = {}) {
418
+ await this.loadMarkets();
419
+ symbols = this.marketSymbols(symbols, undefined, false, true, true);
420
+ const firstMarket = this.market(symbols[0]);
421
+ if (!firstMarket['spot'] && !firstMarket['linear']) {
422
+ throw new errors.NotSupported(this.id + ' watchMultiple supports only spot or linear-swap symbols');
423
+ }
424
+ const messageHashes = [];
425
+ const marketIds = [];
426
+ for (let i = 0; i < symbols.length; i++) {
427
+ const symbol = symbols[i];
428
+ const messageHash = itemHashName + ':' + symbol;
429
+ messageHashes.push(messageHash);
430
+ const market = this.market(symbol);
431
+ marketIds.push(market['id']);
432
+ }
433
+ const queryStr = marketIds.join(',');
434
+ let url = this.urls['api']['ws'] + '/v1/multimarketdata?symbols=' + queryStr + '&heartbeat=true&';
435
+ if (itemHashName === 'orderbook') {
436
+ url += 'trades=false&bids=true&offers=true';
437
+ }
438
+ else if (itemHashName === 'trades') {
439
+ url += 'trades=true&bids=false&offers=false';
440
+ }
441
+ return await this.watchMultiple(url, messageHashes, undefined);
442
+ }
443
+ handleOrderBookForMultidata(client, rawOrderBookChanges, timestamp, nonce) {
444
+ //
445
+ // rawOrderBookChanges
446
+ //
447
+ // [
448
+ // {
449
+ // delta: "4105123935484.817624",
450
+ // price: "0.000000001",
451
+ // reason: "initial", // initial|cancel|place
452
+ // remaining: "4105123935484.817624",
453
+ // side: "bid", // bid|ask
454
+ // symbol: "SHIBUSD",
455
+ // type: "change", // seems always change
456
+ // },
457
+ // ...
458
+ //
459
+ const marketId = rawOrderBookChanges[0]['symbol'];
460
+ const market = this.safeMarket(marketId.toLowerCase());
461
+ const symbol = market['symbol'];
462
+ const messageHash = 'orderbook:' + symbol;
463
+ let orderbook = this.safeDict(this.orderbooks, symbol);
464
+ if (orderbook === undefined) {
465
+ orderbook = this.orderBook();
466
+ }
467
+ const bids = orderbook['bids'];
468
+ const asks = orderbook['asks'];
469
+ for (let i = 0; i < rawOrderBookChanges.length; i++) {
470
+ const entry = rawOrderBookChanges[i];
471
+ const price = this.safeNumber(entry, 'price');
472
+ const size = this.safeNumber(entry, 'remaining');
473
+ const rawSide = this.safeString(entry, 'side');
474
+ if (rawSide === 'bid') {
475
+ bids.store(price, size);
476
+ }
477
+ else {
478
+ asks.store(price, size);
479
+ }
480
+ }
481
+ orderbook['bids'] = bids;
482
+ orderbook['asks'] = asks;
483
+ orderbook['symbol'] = symbol;
484
+ orderbook['nonce'] = nonce;
485
+ orderbook['timestamp'] = timestamp;
486
+ orderbook['datetime'] = this.iso8601(timestamp);
487
+ this.orderbooks[symbol] = orderbook;
488
+ client.resolve(orderbook, messageHash);
489
+ }
331
490
  handleL2Updates(client, message) {
332
491
  //
333
492
  // {
@@ -408,6 +567,7 @@ class gemini extends gemini$1 {
408
567
  // "socket_sequence": 7
409
568
  // }
410
569
  //
570
+ client.lastPong = this.milliseconds();
411
571
  return message;
412
572
  }
413
573
  handleSubscription(client, message) {
@@ -610,6 +770,33 @@ class gemini extends gemini$1 {
610
770
  if (method !== undefined) {
611
771
  method.call(this, client, message);
612
772
  }
773
+ // handle multimarketdata
774
+ if (type === 'update') {
775
+ const ts = this.safeInteger(message, 'timestampms', this.milliseconds());
776
+ const eventId = this.safeInteger(message, 'eventId');
777
+ const events = this.safeList(message, 'events');
778
+ const orderBookItems = [];
779
+ const collectedEventsOfTrades = [];
780
+ for (let i = 0; i < events.length; i++) {
781
+ const event = events[i];
782
+ const eventType = this.safeString(event, 'type');
783
+ const isOrderBook = (eventType === 'change') && ('side' in event) && this.inArray(event['side'], ['ask', 'bid']);
784
+ if (isOrderBook) {
785
+ orderBookItems.push(event);
786
+ }
787
+ else if (eventType === 'trade') {
788
+ collectedEventsOfTrades.push(events[i]);
789
+ }
790
+ }
791
+ const lengthOb = orderBookItems.length;
792
+ if (lengthOb > 0) {
793
+ this.handleOrderBookForMultidata(client, orderBookItems, ts, eventId);
794
+ }
795
+ const lengthTrades = collectedEventsOfTrades.length;
796
+ if (lengthTrades > 0) {
797
+ this.handleTradesForMultidata(client, collectedEventsOfTrades, ts);
798
+ }
799
+ }
613
800
  }
614
801
  async authenticate(params = {}) {
615
802
  const url = this.safeString(params, 'url');
package/js/ccxt.d.ts CHANGED
@@ -4,7 +4,7 @@ import * as functions from './src/base/functions.js';
4
4
  import * as errors from './src/base/errors.js';
5
5
  import type { Market, Trade, Fee, Ticker, OrderBook, Order, Transaction, Tickers, Currency, Balance, DepositAddress, WithdrawalResponse, DepositAddressResponse, OHLCV, Balances, PartialBalances, Dictionary, MinMax, Position, FundingRateHistory, Liquidation, FundingHistory, MarginMode, Greeks } from './src/base/types.js';
6
6
  import { BaseError, ExchangeError, PermissionDenied, AccountNotEnabled, AccountSuspended, ArgumentsRequired, BadRequest, BadSymbol, MarginModeAlreadySet, BadResponse, NullResponse, InsufficientFunds, InvalidAddress, InvalidOrder, OrderNotFound, OrderNotCached, CancelPending, OrderImmediatelyFillable, OrderNotFillable, DuplicateOrderId, NotSupported, NetworkError, DDoSProtection, RateLimitExceeded, ExchangeNotAvailable, OnMaintenance, InvalidNonce, RequestTimeout, AuthenticationError, AddressPending, NoChange } from './src/base/errors.js';
7
- declare const version = "4.2.35";
7
+ declare const version = "4.2.36";
8
8
  import ace from './src/ace.js';
9
9
  import alpaca from './src/alpaca.js';
10
10
  import ascendex from './src/ascendex.js';
package/js/ccxt.js CHANGED
@@ -38,7 +38,7 @@ import * as errors from './src/base/errors.js';
38
38
  import { BaseError, ExchangeError, PermissionDenied, AccountNotEnabled, AccountSuspended, ArgumentsRequired, BadRequest, BadSymbol, MarginModeAlreadySet, BadResponse, NullResponse, InsufficientFunds, InvalidAddress, InvalidOrder, OrderNotFound, OrderNotCached, CancelPending, OrderImmediatelyFillable, OrderNotFillable, DuplicateOrderId, NotSupported, NetworkError, DDoSProtection, RateLimitExceeded, ExchangeNotAvailable, OnMaintenance, InvalidNonce, RequestTimeout, AuthenticationError, AddressPending, NoChange } from './src/base/errors.js';
39
39
  //-----------------------------------------------------------------------------
40
40
  // this is updated by vss.js when building
41
- const version = '4.2.36';
41
+ const version = '4.2.37';
42
42
  Exchange.ccxtVersion = version;
43
43
  //-----------------------------------------------------------------------------
44
44
  import ace from './src/ace.js';
@@ -103,6 +103,7 @@ export interface Order {
103
103
  filled: number;
104
104
  remaining: number;
105
105
  stopPrice?: number;
106
+ triggerPrice?: number;
106
107
  takeProfitPrice?: number;
107
108
  stopLossPrice?: number;
108
109
  cost: number;
@@ -234,6 +235,7 @@ export interface Position {
234
235
  notional?: number;
235
236
  leverage?: number;
236
237
  unrealizedPnl?: number;
238
+ realizedPnl?: number;
237
239
  collateral?: number;
238
240
  entryPrice?: number;
239
241
  markPrice?: number;