ccxt 4.4.72 → 4.4.73

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.
@@ -1,1165 +0,0 @@
1
- // ----------------------------------------------------------------------------
2
-
3
- // PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
- // https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
- // EDIT THE CORRESPONDENT .ts FILE INSTEAD
6
-
7
- // ---------------------------------------------------------------------------
8
- import bitfinex2Rest from '../bitfinex2.js';
9
- import { Precise } from '../base/Precise.js';
10
- import { ExchangeError, AuthenticationError, ChecksumError } from '../base/errors.js';
11
- import { ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp } from '../base/ws/Cache.js';
12
- import { sha384 } from '../static_dependencies/noble-hashes/sha512.js';
13
- // ---------------------------------------------------------------------------
14
- export default class bitfinex2 extends bitfinex2Rest {
15
- describe() {
16
- return this.deepExtend(super.describe(), {
17
- 'has': {
18
- 'ws': true,
19
- 'watchTicker': true,
20
- 'watchTickers': false,
21
- 'watchOrderBook': true,
22
- 'watchTrades': true,
23
- 'watchTradesForSymbols': false,
24
- 'watchMyTrades': true,
25
- 'watchBalance': true,
26
- 'watchOHLCV': true,
27
- 'watchOrders': true,
28
- },
29
- 'urls': {
30
- 'api': {
31
- 'ws': {
32
- 'public': 'wss://api-pub.bitfinex.com/ws/2',
33
- 'private': 'wss://api.bitfinex.com/ws/2',
34
- },
35
- },
36
- },
37
- 'options': {
38
- 'watchOrderBook': {
39
- 'prec': 'P0',
40
- 'freq': 'F0',
41
- 'checksum': true,
42
- },
43
- 'ordersLimit': 1000,
44
- },
45
- });
46
- }
47
- async subscribe(channel, symbol, params = {}) {
48
- await this.loadMarkets();
49
- const market = this.market(symbol);
50
- const marketId = market['id'];
51
- const url = this.urls['api']['ws']['public'];
52
- const client = this.client(url);
53
- const messageHash = channel + ':' + marketId;
54
- const request = {
55
- 'event': 'subscribe',
56
- 'channel': channel,
57
- 'symbol': marketId,
58
- };
59
- const result = await this.watch(url, messageHash, this.deepExtend(request, params), messageHash, { 'checksum': false });
60
- const checksum = this.safeBool(this.options, 'checksum', true);
61
- if (checksum && !client.subscriptions[messageHash]['checksum'] && (channel === 'book')) {
62
- client.subscriptions[messageHash]['checksum'] = true;
63
- await client.send({
64
- 'event': 'conf',
65
- 'flags': 131072,
66
- });
67
- }
68
- return result;
69
- }
70
- async subscribePrivate(messageHash) {
71
- await this.loadMarkets();
72
- await this.authenticate();
73
- const url = this.urls['api']['ws']['private'];
74
- return await this.watch(url, messageHash, undefined, 1);
75
- }
76
- /**
77
- * @method
78
- * @name bitfinex2#watchOHLCV
79
- * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
80
- * @param {string} symbol unified symbol of the market to fetch OHLCV data for
81
- * @param {string} timeframe the length of time each candle represents
82
- * @param {int} [since] timestamp in ms of the earliest candle to fetch
83
- * @param {int} [limit] the maximum amount of candles to fetch
84
- * @param {object} [params] extra parameters specific to the exchange API endpoint
85
- * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
86
- */
87
- async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
88
- await this.loadMarkets();
89
- const market = this.market(symbol);
90
- symbol = market['symbol'];
91
- const interval = this.safeString(this.timeframes, timeframe, timeframe);
92
- const channel = 'candles';
93
- const key = 'trade:' + interval + ':' + market['id'];
94
- const messageHash = channel + ':' + interval + ':' + market['id'];
95
- const request = {
96
- 'event': 'subscribe',
97
- 'channel': channel,
98
- 'key': key,
99
- };
100
- const url = this.urls['api']['ws']['public'];
101
- // not using subscribe here because this message has a different format
102
- const ohlcv = await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
103
- if (this.newUpdates) {
104
- limit = ohlcv.getLimit(symbol, limit);
105
- }
106
- return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
107
- }
108
- handleOHLCV(client, message, subscription) {
109
- //
110
- // initial snapshot
111
- // [
112
- // 341527, // channel id
113
- // [
114
- // [
115
- // 1654705860000, // timestamp
116
- // 1802.6, // open
117
- // 1800.3, // close
118
- // 1802.8, // high
119
- // 1800.3, // low
120
- // 86.49588236 // volume
121
- // ],
122
- // [
123
- // 1654705800000,
124
- // 1803.6,
125
- // 1802.6,
126
- // 1804.9,
127
- // 1802.3,
128
- // 74.6348086
129
- // ],
130
- // [
131
- // 1654705740000,
132
- // 1802.5,
133
- // 1803.2,
134
- // 1804.4,
135
- // 1802.4,
136
- // 23.61801085
137
- // ]
138
- // ]
139
- // ]
140
- //
141
- // update
142
- // [
143
- // 211171,
144
- // [
145
- // 1654705680000,
146
- // 1801,
147
- // 1802.4,
148
- // 1802.9,
149
- // 1800.4,
150
- // 23.91911091
151
- // ]
152
- // ]
153
- //
154
- const data = this.safeValue(message, 1, []);
155
- let ohlcvs = undefined;
156
- const first = this.safeValue(data, 0);
157
- if (Array.isArray(first)) {
158
- // snapshot
159
- ohlcvs = data;
160
- }
161
- else {
162
- // update
163
- ohlcvs = [data];
164
- }
165
- const channel = this.safeValue(subscription, 'channel');
166
- const key = this.safeString(subscription, 'key');
167
- const keyParts = key.split(':');
168
- const interval = this.safeString(keyParts, 1);
169
- let marketId = key;
170
- marketId = marketId.replace('trade:', '');
171
- marketId = marketId.replace(interval + ':', '');
172
- const market = this.safeMarket(marketId);
173
- const timeframe = this.findTimeframe(interval);
174
- const symbol = market['symbol'];
175
- const messageHash = channel + ':' + interval + ':' + marketId;
176
- this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
177
- let stored = this.safeValue(this.ohlcvs[symbol], timeframe);
178
- if (stored === undefined) {
179
- const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
180
- stored = new ArrayCacheByTimestamp(limit);
181
- this.ohlcvs[symbol][timeframe] = stored;
182
- }
183
- const ohlcvsLength = ohlcvs.length;
184
- for (let i = 0; i < ohlcvsLength; i++) {
185
- const ohlcv = ohlcvs[ohlcvsLength - i - 1];
186
- const parsed = this.parseOHLCV(ohlcv, market);
187
- stored.append(parsed);
188
- }
189
- client.resolve(stored, messageHash);
190
- }
191
- /**
192
- * @method
193
- * @name bitfinex2#watchTrades
194
- * @description get the list of most recent trades for a particular symbol
195
- * @param {string} symbol unified symbol of the market to fetch trades for
196
- * @param {int} [since] timestamp in ms of the earliest trade to fetch
197
- * @param {int} [limit] the maximum amount of trades to fetch
198
- * @param {object} [params] extra parameters specific to the exchange API endpoint
199
- * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
200
- */
201
- async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
202
- const trades = await this.subscribe('trades', symbol, params);
203
- if (this.newUpdates) {
204
- limit = trades.getLimit(symbol, limit);
205
- }
206
- return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
207
- }
208
- /**
209
- * @method
210
- * @name bitfinex2#watchMyTrades
211
- * @description watches information on multiple trades made by the user
212
- * @param {string} symbol unified market symbol of the market trades were made in
213
- * @param {int} [since] the earliest time in ms to fetch trades for
214
- * @param {int} [limit] the maximum number of trade structures to retrieve
215
- * @param {object} [params] extra parameters specific to the exchange API endpoint
216
- * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
217
- */
218
- async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
219
- await this.loadMarkets();
220
- let messageHash = 'myTrade';
221
- if (symbol !== undefined) {
222
- const market = this.market(symbol);
223
- messageHash += ':' + market['id'];
224
- }
225
- const trades = await this.subscribePrivate(messageHash);
226
- if (this.newUpdates) {
227
- limit = trades.getLimit(symbol, limit);
228
- }
229
- return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true);
230
- }
231
- /**
232
- * @method
233
- * @name bitfinex2#watchTicker
234
- * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
235
- * @param {string} symbol unified symbol of the market to fetch the ticker for
236
- * @param {object} [params] extra parameters specific to the exchange API endpoint
237
- * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
238
- */
239
- async watchTicker(symbol, params = {}) {
240
- return await this.subscribe('ticker', symbol, params);
241
- }
242
- handleMyTrade(client, message, subscription = {}) {
243
- //
244
- // trade execution
245
- // [
246
- // 0,
247
- // "te", // or tu
248
- // [
249
- // 1133411090,
250
- // "tLTCUST",
251
- // 1655110144598,
252
- // 97084883506,
253
- // 0.1,
254
- // 42.821,
255
- // "EXCHANGE MARKET",
256
- // 42.799,
257
- // -1,
258
- // null,
259
- // null,
260
- // 1655110144596
261
- // ]
262
- // ]
263
- //
264
- const name = 'myTrade';
265
- const data = this.safeValue(message, 2);
266
- const trade = this.parseWsTrade(data);
267
- const symbol = trade['symbol'];
268
- const market = this.market(symbol);
269
- const messageHash = name + ':' + market['id'];
270
- if (this.myTrades === undefined) {
271
- const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
272
- this.myTrades = new ArrayCacheBySymbolById(limit);
273
- }
274
- const tradesArray = this.myTrades;
275
- tradesArray.append(trade);
276
- this.myTrades = tradesArray;
277
- // generic subscription
278
- client.resolve(tradesArray, name);
279
- // specific subscription
280
- client.resolve(tradesArray, messageHash);
281
- }
282
- handleTrades(client, message, subscription) {
283
- //
284
- // initial snapshot
285
- //
286
- // [
287
- // 188687, // channel id
288
- // [
289
- // [ 1128060675, 1654701572690, 0.00217533, 1815.3 ], // id, mts, amount, price
290
- // [ 1128060665, 1654701551231, -0.00280472, 1814.1 ],
291
- // [ 1128060664, 1654701550996, -0.00364444, 1814.1 ],
292
- // [ 1128060656, 1654701527730, -0.00265203, 1814.2 ],
293
- // [ 1128060647, 1654701505193, 0.00262395, 1815.2 ],
294
- // [ 1128060642, 1654701484656, -0.13411443, 1816 ],
295
- // [ 1128060641, 1654701484656, -0.00088557, 1816 ],
296
- // [ 1128060639, 1654701478326, -0.002, 1816 ],
297
- // ]
298
- // ]
299
- // update
300
- //
301
- // [
302
- // 360141,
303
- // "te",
304
- // [
305
- // 1128060969, // id
306
- // 1654702500098, // mts
307
- // 0.00325131, // amount positive buy, negative sell
308
- // 1818.5, // price
309
- // ],
310
- // ]
311
- //
312
- //
313
- const channel = this.safeValue(subscription, 'channel');
314
- const marketId = this.safeString(subscription, 'symbol');
315
- const market = this.safeMarket(marketId);
316
- const messageHash = channel + ':' + marketId;
317
- const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
318
- const symbol = market['symbol'];
319
- let stored = this.safeValue(this.trades, symbol);
320
- if (stored === undefined) {
321
- stored = new ArrayCache(tradesLimit);
322
- this.trades[symbol] = stored;
323
- }
324
- const messageLength = message.length;
325
- if (messageLength === 2) {
326
- // initial snapshot
327
- const trades = this.safeList(message, 1, []);
328
- // needs to be reversed to make chronological order
329
- const length = trades.length;
330
- for (let i = 0; i < length; i++) {
331
- const index = length - i - 1;
332
- const parsed = this.parseWsTrade(trades[index], market);
333
- stored.append(parsed);
334
- }
335
- }
336
- else {
337
- // update
338
- const type = this.safeString(message, 1);
339
- if (type === 'tu') {
340
- // don't resolve for a duplicate update
341
- // since te and tu updates are duplicated on the public stream
342
- return;
343
- }
344
- const trade = this.safeValue(message, 2, []);
345
- const parsed = this.parseWsTrade(trade, market);
346
- stored.append(parsed);
347
- }
348
- client.resolve(stored, messageHash);
349
- }
350
- parseWsTrade(trade, market = undefined) {
351
- //
352
- // [
353
- // 1128060969, // id
354
- // 1654702500098, // mts
355
- // 0.00325131, // amount positive buy, negative sell
356
- // 1818.5, // price
357
- // ]
358
- //
359
- // trade execution
360
- //
361
- // [
362
- // 1133411090, // id
363
- // "tLTCUST", // symbol
364
- // 1655110144598, // create ms
365
- // 97084883506, // order id
366
- // 0.1, // amount
367
- // 42.821, // price
368
- // "EXCHANGE MARKET", // order type
369
- // 42.799, // order price
370
- // -1, // maker
371
- // null, // fee
372
- // null, // fee currency
373
- // 1655110144596 // cid
374
- // ]
375
- //
376
- // trade update
377
- //
378
- // [
379
- // 1133411090,
380
- // "tLTCUST",
381
- // 1655110144598,
382
- // 97084883506,
383
- // 0.1,
384
- // 42.821,
385
- // "EXCHANGE MARKET",
386
- // 42.799,
387
- // -1,
388
- // -0.0002,
389
- // "LTC",
390
- // 1655110144596
391
- // ]
392
- //
393
- const numFields = trade.length;
394
- const isPublic = numFields <= 8;
395
- let marketId = (!isPublic) ? this.safeString(trade, 1) : undefined;
396
- market = this.safeMarket(marketId, market);
397
- const createdKey = isPublic ? 1 : 2;
398
- const priceKey = isPublic ? 3 : 5;
399
- const amountKey = isPublic ? 2 : 4;
400
- marketId = market['id'];
401
- let type = this.safeString(trade, 6);
402
- if (type !== undefined) {
403
- if (type.indexOf('LIMIT') > -1) {
404
- type = 'limit';
405
- }
406
- else if (type.indexOf('MARKET') > -1) {
407
- type = 'market';
408
- }
409
- }
410
- const orderId = (!isPublic) ? this.safeString(trade, 3) : undefined;
411
- const id = this.safeString(trade, 0);
412
- const timestamp = this.safeInteger(trade, createdKey);
413
- const price = this.safeString(trade, priceKey);
414
- const amountString = this.safeString(trade, amountKey);
415
- const amount = this.parseNumber(Precise.stringAbs(amountString));
416
- let side = undefined;
417
- if (amount !== undefined) {
418
- side = Precise.stringGt(amountString, '0') ? 'buy' : 'sell';
419
- }
420
- const symbol = this.safeSymbol(marketId, market);
421
- const feeValue = this.safeString(trade, 9);
422
- let fee = undefined;
423
- if (feeValue !== undefined) {
424
- const currencyId = this.safeString(trade, 10);
425
- const code = this.safeCurrencyCode(currencyId);
426
- fee = {
427
- 'cost': feeValue,
428
- 'currency': code,
429
- };
430
- }
431
- const maker = this.safeInteger(trade, 8);
432
- let takerOrMaker = undefined;
433
- if (maker !== undefined) {
434
- takerOrMaker = (maker === -1) ? 'taker' : 'maker';
435
- }
436
- return this.safeTrade({
437
- 'info': trade,
438
- 'timestamp': timestamp,
439
- 'datetime': this.iso8601(timestamp),
440
- 'symbol': symbol,
441
- 'id': id,
442
- 'order': orderId,
443
- 'type': type,
444
- 'takerOrMaker': takerOrMaker,
445
- 'side': side,
446
- 'price': price,
447
- 'amount': amount,
448
- 'cost': undefined,
449
- 'fee': fee,
450
- }, market);
451
- }
452
- handleTicker(client, message, subscription) {
453
- //
454
- // [
455
- // 340432, // channel ID
456
- // [
457
- // 236.62, // 1 BID float Price of last highest bid
458
- // 9.0029, // 2 BID_SIZE float Size of the last highest bid
459
- // 236.88, // 3 ASK float Price of last lowest ask
460
- // 7.1138, // 4 ASK_SIZE float Size of the last lowest ask
461
- // -1.02, // 5 DAILY_CHANGE float Amount that the last price has changed since yesterday
462
- // 0, // 6 DAILY_CHANGE_PERC float Amount that the price has changed expressed in percentage terms
463
- // 236.52, // 7 LAST_PRICE float Price of the last trade.
464
- // 5191.36754297, // 8 VOLUME float Daily volume
465
- // 250.01, // 9 HIGH float Daily high
466
- // 220.05, // 10 LOW float Daily low
467
- // ]
468
- // ]
469
- //
470
- const ticker = this.safeValue(message, 1);
471
- const marketId = this.safeString(subscription, 'symbol');
472
- const market = this.safeMarket(marketId);
473
- const symbol = this.safeSymbol(marketId);
474
- const parsed = this.parseWsTicker(ticker, market);
475
- const channel = 'ticker';
476
- const messageHash = channel + ':' + marketId;
477
- this.tickers[symbol] = parsed;
478
- client.resolve(parsed, messageHash);
479
- }
480
- parseWsTicker(ticker, market = undefined) {
481
- //
482
- // [
483
- // 236.62, // 1 BID float Price of last highest bid
484
- // 9.0029, // 2 BID_SIZE float Size of the last highest bid
485
- // 236.88, // 3 ASK float Price of last lowest ask
486
- // 7.1138, // 4 ASK_SIZE float Size of the last lowest ask
487
- // -1.02, // 5 DAILY_CHANGE float Amount that the last price has changed since yesterday
488
- // 0, // 6 DAILY_CHANGE_PERC float Amount that the price has changed expressed in percentage terms
489
- // 236.52, // 7 LAST_PRICE float Price of the last trade.
490
- // 5191.36754297, // 8 VOLUME float Daily volume
491
- // 250.01, // 9 HIGH float Daily high
492
- // 220.05, // 10 LOW float Daily low
493
- // ]
494
- //
495
- market = this.safeMarket(undefined, market);
496
- const symbol = market['symbol'];
497
- const last = this.safeString(ticker, 6);
498
- const change = this.safeString(ticker, 4);
499
- return this.safeTicker({
500
- 'symbol': symbol,
501
- 'timestamp': undefined,
502
- 'datetime': undefined,
503
- 'high': this.safeString(ticker, 8),
504
- 'low': this.safeString(ticker, 9),
505
- 'bid': this.safeString(ticker, 0),
506
- 'bidVolume': this.safeString(ticker, 1),
507
- 'ask': this.safeString(ticker, 2),
508
- 'askVolume': this.safeString(ticker, 3),
509
- 'vwap': undefined,
510
- 'open': undefined,
511
- 'close': last,
512
- 'last': last,
513
- 'previousClose': undefined,
514
- 'change': change,
515
- 'percentage': this.safeString(ticker, 5),
516
- 'average': undefined,
517
- 'baseVolume': this.safeString(ticker, 7),
518
- 'quoteVolume': undefined,
519
- 'info': ticker,
520
- }, market);
521
- }
522
- /**
523
- * @method
524
- * @name bitfinex2#watchOrderBook
525
- * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
526
- * @param {string} symbol unified symbol of the market to fetch the order book for
527
- * @param {int} [limit] the maximum amount of order book entries to return
528
- * @param {object} [params] extra parameters specific to the exchange API endpoint
529
- * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
530
- */
531
- async watchOrderBook(symbol, limit = undefined, params = {}) {
532
- if (limit !== undefined) {
533
- if ((limit !== 25) && (limit !== 100)) {
534
- throw new ExchangeError(this.id + ' watchOrderBook limit argument must be undefined, 25 or 100');
535
- }
536
- }
537
- const options = this.safeValue(this.options, 'watchOrderBook', {});
538
- const prec = this.safeString(options, 'prec', 'P0');
539
- const freq = this.safeString(options, 'freq', 'F0');
540
- const request = {
541
- 'prec': prec,
542
- 'freq': freq, // string, frequency of updates 'F0' = realtime, 'F1' = 2 seconds, default is 'F0'
543
- };
544
- if (limit !== undefined) {
545
- request['len'] = limit; // string, number of price points, '25', '100', default = '25'
546
- }
547
- const orderbook = await this.subscribe('book', symbol, this.deepExtend(request, params));
548
- return orderbook.limit();
549
- }
550
- handleOrderBook(client, message, subscription) {
551
- //
552
- // first message (snapshot)
553
- //
554
- // [
555
- // 18691, // channel id
556
- // [
557
- // [ 7364.8, 10, 4.354802 ], // price, count, size > 0 = bid
558
- // [ 7364.7, 1, 0.00288831 ],
559
- // [ 7364.3, 12, 0.048 ],
560
- // [ 7364.9, 3, -0.42028976 ], // price, count, size < 0 = ask
561
- // [ 7365, 1, -0.25 ],
562
- // [ 7365.5, 1, -0.00371937 ],
563
- // ]
564
- // ]
565
- //
566
- // subsequent updates
567
- //
568
- // [
569
- // 358169, // channel id
570
- // [
571
- // 1807.1, // price
572
- // 0, // cound
573
- // 1 // size
574
- // ]
575
- // ]
576
- //
577
- const marketId = this.safeString(subscription, 'symbol');
578
- const symbol = this.safeSymbol(marketId);
579
- const channel = 'book';
580
- const messageHash = channel + ':' + marketId;
581
- const prec = this.safeString(subscription, 'prec', 'P0');
582
- const isRaw = (prec === 'R0');
583
- // if it is an initial snapshot
584
- if (!(symbol in this.orderbooks)) {
585
- const limit = this.safeInteger(subscription, 'len');
586
- if (isRaw) {
587
- // raw order books
588
- this.orderbooks[symbol] = this.indexedOrderBook({}, limit);
589
- }
590
- else {
591
- // P0, P1, P2, P3, P4
592
- this.orderbooks[symbol] = this.countedOrderBook({}, limit);
593
- }
594
- const orderbook = this.orderbooks[symbol];
595
- if (isRaw) {
596
- const deltas = message[1];
597
- for (let i = 0; i < deltas.length; i++) {
598
- const delta = deltas[i];
599
- const delta2 = delta[2];
600
- const size = (delta2 < 0) ? -delta2 : delta2;
601
- const side = (delta2 < 0) ? 'asks' : 'bids';
602
- const bookside = orderbook[side];
603
- const idString = this.safeString(delta, 0);
604
- const price = this.safeFloat(delta, 1);
605
- bookside.storeArray([price, size, idString]);
606
- }
607
- }
608
- else {
609
- const deltas = message[1];
610
- for (let i = 0; i < deltas.length; i++) {
611
- const delta = deltas[i];
612
- const amount = this.safeNumber(delta, 2);
613
- const counter = this.safeNumber(delta, 1);
614
- const price = this.safeNumber(delta, 0);
615
- const size = (amount < 0) ? -amount : amount;
616
- const side = (amount < 0) ? 'asks' : 'bids';
617
- const bookside = orderbook[side];
618
- bookside.storeArray([price, size, counter]);
619
- }
620
- }
621
- orderbook['symbol'] = symbol;
622
- client.resolve(orderbook, messageHash);
623
- }
624
- else {
625
- const orderbook = this.orderbooks[symbol];
626
- const deltas = message[1];
627
- const orderbookItem = this.orderbooks[symbol];
628
- if (isRaw) {
629
- const price = this.safeString(deltas, 1);
630
- const deltas2 = deltas[2];
631
- const size = (deltas2 < 0) ? -deltas2 : deltas2;
632
- const side = (deltas2 < 0) ? 'asks' : 'bids';
633
- const bookside = orderbookItem[side];
634
- // price = 0 means that you have to remove the order from your book
635
- const amount = Precise.stringGt(price, '0') ? size : '0';
636
- const idString = this.safeString(deltas, 0);
637
- bookside.storeArray([this.parseNumber(price), this.parseNumber(amount), idString]);
638
- }
639
- else {
640
- const amount = this.safeString(deltas, 2);
641
- const counter = this.safeString(deltas, 1);
642
- const price = this.safeString(deltas, 0);
643
- const size = Precise.stringLt(amount, '0') ? Precise.stringNeg(amount) : amount;
644
- const side = Precise.stringLt(amount, '0') ? 'asks' : 'bids';
645
- const bookside = orderbookItem[side];
646
- bookside.storeArray([this.parseNumber(price), this.parseNumber(size), this.parseNumber(counter)]);
647
- }
648
- client.resolve(orderbook, messageHash);
649
- }
650
- }
651
- handleChecksum(client, message, subscription) {
652
- //
653
- // [ 173904, "cs", -890884919 ]
654
- //
655
- const marketId = this.safeString(subscription, 'symbol');
656
- const symbol = this.safeSymbol(marketId);
657
- const channel = 'book';
658
- const messageHash = channel + ':' + marketId;
659
- const book = this.safeValue(this.orderbooks, symbol);
660
- if (book === undefined) {
661
- return;
662
- }
663
- const depth = 25; // covers the first 25 bids and asks
664
- const stringArray = [];
665
- const bids = book['bids'];
666
- const asks = book['asks'];
667
- const prec = this.safeString(subscription, 'prec', 'P0');
668
- const isRaw = (prec === 'R0');
669
- const idToCheck = isRaw ? 2 : 0;
670
- // pepperoni pizza from bitfinex
671
- for (let i = 0; i < depth; i++) {
672
- const bid = this.safeValue(bids, i);
673
- const ask = this.safeValue(asks, i);
674
- if (bid !== undefined) {
675
- stringArray.push(this.numberToString(bids[i][idToCheck]));
676
- stringArray.push(this.numberToString(bids[i][1]));
677
- }
678
- if (ask !== undefined) {
679
- stringArray.push(this.numberToString(asks[i][idToCheck]));
680
- const aski1 = asks[i][1];
681
- stringArray.push(this.numberToString(-aski1));
682
- }
683
- }
684
- const payload = stringArray.join(':');
685
- const localChecksum = this.crc32(payload, true);
686
- const responseChecksum = this.safeInteger(message, 2);
687
- if (responseChecksum !== localChecksum) {
688
- delete client.subscriptions[messageHash];
689
- delete this.orderbooks[symbol];
690
- const checksum = this.handleOption('watchOrderBook', 'checksum', true);
691
- if (checksum) {
692
- const error = new ChecksumError(this.id + ' ' + this.orderbookChecksumMessage(symbol));
693
- client.reject(error, messageHash);
694
- }
695
- }
696
- }
697
- /**
698
- * @method
699
- * @name bitfinex2#watchBalance
700
- * @description watch balance and get the amount of funds available for trading or funds locked in orders
701
- * @param {object} [params] extra parameters specific to the exchange API endpoint
702
- * @param {str} [params.type] spot or contract if not provided this.options['defaultType'] is used
703
- * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
704
- */
705
- async watchBalance(params = {}) {
706
- await this.loadMarkets();
707
- const balanceType = this.safeString(params, 'wallet', 'exchange'); // exchange, margin
708
- params = this.omit(params, 'wallet');
709
- const messageHash = 'balance:' + balanceType;
710
- return await this.subscribePrivate(messageHash);
711
- }
712
- handleBalance(client, message, subscription) {
713
- //
714
- // snapshot (exchange + margin together)
715
- // [
716
- // 0,
717
- // "ws",
718
- // [
719
- // [
720
- // "exchange",
721
- // "LTC",
722
- // 0.05479727,
723
- // 0,
724
- // null,
725
- // "Trading fees for 0.05 LTC (LTCUST) @ 51.872 on BFX (0.2%)",
726
- // null,
727
- // ]
728
- // [
729
- // "margin",
730
- // "USTF0",
731
- // 11.960650700086292,
732
- // 0,
733
- // null,
734
- // "Trading fees for 0.1 LTCF0 (LTCF0:USTF0) @ 51.844 on BFX (0.065%)",
735
- // null,
736
- // ],
737
- // ],
738
- // ]
739
- //
740
- // spot
741
- // [
742
- // 0,
743
- // "wu",
744
- // [
745
- // "exchange",
746
- // "LTC", // currency
747
- // 0.06729727, // wallet balance
748
- // 0, // unsettled balance
749
- // 0.06729727, // available balance might be null
750
- // "Exchange 0.4 LTC for UST @ 65.075",
751
- // {
752
- // "reason": "TRADE",
753
- // "order_id": 96596397973,
754
- // "order_id_oppo": 96596632735,
755
- // "trade_price": "65.075",
756
- // "trade_amount": "-0.4",
757
- // "order_cid": 1654636218766,
758
- // "order_gid": null
759
- // }
760
- // ]
761
- // ]
762
- //
763
- // margin
764
- //
765
- // [
766
- // "margin",
767
- // "USTF0",
768
- // 11.960650700086292, // total
769
- // 0,
770
- // 6.776250700086292, // available
771
- // "Trading fees for 0.1 LTCF0 (LTCF0:USTF0) @ 51.844 on BFX (0.065%)",
772
- // null
773
- // ]
774
- //
775
- const updateType = this.safeValue(message, 1);
776
- let data = undefined;
777
- if (updateType === 'ws') {
778
- data = this.safeValue(message, 2);
779
- }
780
- else {
781
- data = [this.safeValue(message, 2)];
782
- }
783
- const updatedTypes = {};
784
- for (let i = 0; i < data.length; i++) {
785
- const rawBalance = data[i];
786
- const currencyId = this.safeString(rawBalance, 1);
787
- const code = this.safeCurrencyCode(currencyId);
788
- const balance = this.parseWsBalance(rawBalance);
789
- const balanceType = this.safeString(rawBalance, 0);
790
- const oldBalance = this.safeValue(this.balance, balanceType, {});
791
- oldBalance[code] = balance;
792
- oldBalance['info'] = message;
793
- this.balance[balanceType] = this.safeBalance(oldBalance);
794
- updatedTypes[balanceType] = true;
795
- }
796
- const updatesKeys = Object.keys(updatedTypes);
797
- for (let i = 0; i < updatesKeys.length; i++) {
798
- const type = updatesKeys[i];
799
- const messageHash = 'balance:' + type;
800
- client.resolve(this.balance[type], messageHash);
801
- }
802
- }
803
- parseWsBalance(balance) {
804
- //
805
- // [
806
- // "exchange",
807
- // "LTC",
808
- // 0.05479727, // balance
809
- // 0,
810
- // null, // available null if not calculated yet
811
- // "Trading fees for 0.05 LTC (LTCUST) @ 51.872 on BFX (0.2%)",
812
- // null,
813
- // ]
814
- //
815
- const totalBalance = this.safeString(balance, 2);
816
- const availableBalance = this.safeString(balance, 4);
817
- const account = this.account();
818
- if (availableBalance !== undefined) {
819
- account['free'] = availableBalance;
820
- }
821
- account['total'] = totalBalance;
822
- return account;
823
- }
824
- handleSystemStatus(client, message) {
825
- //
826
- // {
827
- // "event": "info",
828
- // "version": 2,
829
- // "serverId": "e293377e-7bb7-427e-b28c-5db045b2c1d1",
830
- // "platform": { status: 1 }, // 1 for operative, 0 for maintenance
831
- // }
832
- //
833
- return message;
834
- }
835
- handleSubscriptionStatus(client, message) {
836
- //
837
- // {
838
- // "event": "subscribed",
839
- // "channel": "book",
840
- // "chanId": 67473,
841
- // "symbol": "tBTCUSD",
842
- // "prec": "P0",
843
- // "freq": "F0",
844
- // "len": "25",
845
- // "pair": "BTCUSD"
846
- // }
847
- //
848
- const channelId = this.safeString(message, 'chanId');
849
- client.subscriptions[channelId] = message;
850
- return message;
851
- }
852
- async authenticate(params = {}) {
853
- const url = this.urls['api']['ws']['private'];
854
- const client = this.client(url);
855
- const messageHash = 'authenticated';
856
- const future = client.future(messageHash);
857
- const authenticated = this.safeValue(client.subscriptions, messageHash);
858
- if (authenticated === undefined) {
859
- const nonce = this.milliseconds();
860
- const payload = 'AUTH' + nonce.toString();
861
- const signature = this.hmac(this.encode(payload), this.encode(this.secret), sha384, 'hex');
862
- const event = 'auth';
863
- const request = {
864
- 'apiKey': this.apiKey,
865
- 'authSig': signature,
866
- 'authNonce': nonce,
867
- 'authPayload': payload,
868
- 'event': event,
869
- };
870
- const message = this.extend(request, params);
871
- this.watch(url, messageHash, message, messageHash);
872
- }
873
- return await future;
874
- }
875
- handleAuthenticationMessage(client, message) {
876
- const messageHash = 'authenticated';
877
- const status = this.safeString(message, 'status');
878
- if (status === 'OK') {
879
- // we resolve the future here permanently so authentication only happens once
880
- const future = this.safeValue(client.futures, messageHash);
881
- future.resolve(true);
882
- }
883
- else {
884
- const error = new AuthenticationError(this.json(message));
885
- client.reject(error, messageHash);
886
- // allows further authentication attempts
887
- if (messageHash in client.subscriptions) {
888
- delete client.subscriptions[messageHash];
889
- }
890
- }
891
- }
892
- /**
893
- * @method
894
- * @name bitfinex2#watchOrders
895
- * @description watches information on multiple orders made by the user
896
- * @param {string} symbol unified market symbol of the market orders were made in
897
- * @param {int} [since] the earliest time in ms to fetch orders for
898
- * @param {int} [limit] the maximum number of order structures to retrieve
899
- * @param {object} [params] extra parameters specific to the exchange API endpoint
900
- * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
901
- */
902
- async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
903
- await this.loadMarkets();
904
- let messageHash = 'orders';
905
- if (symbol !== undefined) {
906
- const market = this.market(symbol);
907
- messageHash += ':' + market['id'];
908
- }
909
- const orders = await this.subscribePrivate(messageHash);
910
- if (this.newUpdates) {
911
- limit = orders.getLimit(symbol, limit);
912
- }
913
- return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
914
- }
915
- handleOrders(client, message, subscription) {
916
- //
917
- // limit order
918
- // [
919
- // 0,
920
- // "on", // ou or oc
921
- // [
922
- // 96923856256, // order id
923
- // null, // gid
924
- // 1655029337026, // cid
925
- // "tLTCUST", // symbol
926
- // 1655029337027, // created timestamp
927
- // 1655029337029, // updated timestamp
928
- // 0.1, // amount
929
- // 0.1, // amount_orig
930
- // "EXCHANGE LIMIT", // order type
931
- // null, // type_prev
932
- // null, // mts_tif
933
- // null, // placeholder
934
- // 0, // flags
935
- // "ACTIVE", // status
936
- // null,
937
- // null,
938
- // 30, // price
939
- // 0, // price average
940
- // 0, // price_trailling
941
- // 0, // price_aux_limit
942
- // null,
943
- // null,
944
- // null,
945
- // 0, // notify
946
- // 0,
947
- // null,
948
- // null,
949
- // null,
950
- // "BFX",
951
- // null,
952
- // null,
953
- // ]
954
- // ]
955
- //
956
- const data = this.safeValue(message, 2, []);
957
- const messageType = this.safeString(message, 1);
958
- if (this.orders === undefined) {
959
- const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
960
- this.orders = new ArrayCacheBySymbolById(limit);
961
- }
962
- const orders = this.orders;
963
- const symbolIds = {};
964
- if (messageType === 'os') {
965
- const snapshotLength = data.length;
966
- if (snapshotLength === 0) {
967
- return;
968
- }
969
- for (let i = 0; i < data.length; i++) {
970
- const value = data[i];
971
- const parsed = this.parseWsOrder(value);
972
- const symbol = parsed['symbol'];
973
- symbolIds[symbol] = true;
974
- orders.append(parsed);
975
- }
976
- }
977
- else {
978
- const parsed = this.parseWsOrder(data);
979
- orders.append(parsed);
980
- const symbol = parsed['symbol'];
981
- symbolIds[symbol] = true;
982
- }
983
- const name = 'orders';
984
- client.resolve(this.orders, name);
985
- const keys = Object.keys(symbolIds);
986
- for (let i = 0; i < keys.length; i++) {
987
- const symbol = keys[i];
988
- const market = this.market(symbol);
989
- const messageHash = name + ':' + market['id'];
990
- client.resolve(this.orders, messageHash);
991
- }
992
- }
993
- parseWsOrderStatus(status) {
994
- const statuses = {
995
- 'ACTIVE': 'open',
996
- 'CANCELED': 'canceled',
997
- 'EXECUTED': 'closed',
998
- 'PARTIALLY': 'open',
999
- };
1000
- return this.safeString(statuses, status, status);
1001
- }
1002
- parseWsOrder(order, market = undefined) {
1003
- //
1004
- // [
1005
- // 97084883506, // order id
1006
- // null,
1007
- // 1655110144596, // clientOrderId
1008
- // "tLTCUST", // symbol
1009
- // 1655110144596, // created timestamp
1010
- // 1655110144598, // updated timestamp
1011
- // 0, // amount
1012
- // 0.1, // amount_orig negative if sell order
1013
- // "EXCHANGE MARKET", // type
1014
- // null,
1015
- // null,
1016
- // null,
1017
- // 0,
1018
- // "EXECUTED @ 42.821(0.1)", // status
1019
- // null,
1020
- // null,
1021
- // 42.799, // price
1022
- // 42.821, // price average
1023
- // 0, // price trailling
1024
- // 0, // price_aux_limit
1025
- // null,
1026
- // null,
1027
- // null,
1028
- // 0,
1029
- // 0,
1030
- // null,
1031
- // null,
1032
- // null,
1033
- // "BFX",
1034
- // null,
1035
- // null,
1036
- // {}
1037
- // ]
1038
- //
1039
- const id = this.safeString(order, 0);
1040
- const clientOrderId = this.safeString(order, 1);
1041
- const marketId = this.safeString(order, 3);
1042
- const symbol = this.safeSymbol(marketId);
1043
- market = this.safeMarket(symbol);
1044
- let amount = this.safeString(order, 7);
1045
- let side = 'buy';
1046
- if (Precise.stringLt(amount, '0')) {
1047
- amount = Precise.stringAbs(amount);
1048
- side = 'sell';
1049
- }
1050
- const remaining = Precise.stringAbs(this.safeString(order, 6));
1051
- let type = this.safeString(order, 8);
1052
- if (type.indexOf('LIMIT') > -1) {
1053
- type = 'limit';
1054
- }
1055
- else if (type.indexOf('MARKET') > -1) {
1056
- type = 'market';
1057
- }
1058
- const rawState = this.safeString(order, 13);
1059
- const stateParts = rawState.split(' ');
1060
- const trimmedStatus = this.safeString(stateParts, 0);
1061
- const status = this.parseWsOrderStatus(trimmedStatus);
1062
- const price = this.safeString(order, 16);
1063
- const timestamp = this.safeInteger2(order, 5, 4);
1064
- const average = this.safeString(order, 17);
1065
- const stopPrice = this.omitZero(this.safeString(order, 18));
1066
- return this.safeOrder({
1067
- 'info': order,
1068
- 'id': id,
1069
- 'clientOrderId': clientOrderId,
1070
- 'timestamp': timestamp,
1071
- 'datetime': this.iso8601(timestamp),
1072
- 'lastTradeTimestamp': undefined,
1073
- 'symbol': symbol,
1074
- 'type': type,
1075
- 'side': side,
1076
- 'price': price,
1077
- 'stopPrice': stopPrice,
1078
- 'triggerPrice': stopPrice,
1079
- 'average': average,
1080
- 'amount': amount,
1081
- 'remaining': remaining,
1082
- 'filled': undefined,
1083
- 'status': status,
1084
- 'fee': undefined,
1085
- 'cost': undefined,
1086
- 'trades': undefined,
1087
- }, market);
1088
- }
1089
- handleMessage(client, message) {
1090
- const channelId = this.safeString(message, 0);
1091
- //
1092
- // [
1093
- // 1231,
1094
- // "hb",
1095
- // ]
1096
- //
1097
- // auth message
1098
- // {
1099
- // "event": "auth",
1100
- // "status": "OK",
1101
- // "chanId": 0,
1102
- // "userId": 3159883,
1103
- // "auth_id": "ac7108e7-2f26-424d-9982-c24700dc02ca",
1104
- // "caps": {
1105
- // "orders": { read: 1, write: 1 },
1106
- // "account": { read: 1, write: 1 },
1107
- // "funding": { read: 1, write: 1 },
1108
- // "history": { read: 1, write: 0 },
1109
- // "wallets": { read: 1, write: 1 },
1110
- // "withdraw": { read: 0, write: 1 },
1111
- // "positions": { read: 1, write: 1 },
1112
- // "ui_withdraw": { read: 0, write: 0 }
1113
- // }
1114
- // }
1115
- //
1116
- if (Array.isArray(message)) {
1117
- if (message[1] === 'hb') {
1118
- return; // skip heartbeats within subscription channels for now
1119
- }
1120
- const subscription = this.safeValue(client.subscriptions, channelId, {});
1121
- const channel = this.safeString(subscription, 'channel');
1122
- const name = this.safeString(message, 1);
1123
- const publicMethods = {
1124
- 'book': this.handleOrderBook,
1125
- 'cs': this.handleChecksum,
1126
- 'candles': this.handleOHLCV,
1127
- 'ticker': this.handleTicker,
1128
- 'trades': this.handleTrades,
1129
- };
1130
- const privateMethods = {
1131
- 'os': this.handleOrders,
1132
- 'ou': this.handleOrders,
1133
- 'on': this.handleOrders,
1134
- 'oc': this.handleOrders,
1135
- 'wu': this.handleBalance,
1136
- 'ws': this.handleBalance,
1137
- 'tu': this.handleMyTrade,
1138
- };
1139
- let method = undefined;
1140
- if (channelId === '0') {
1141
- method = this.safeValue(privateMethods, name);
1142
- }
1143
- else {
1144
- method = this.safeValue2(publicMethods, name, channel);
1145
- }
1146
- if (method !== undefined) {
1147
- method.call(this, client, message, subscription);
1148
- }
1149
- }
1150
- else {
1151
- const event = this.safeString(message, 'event');
1152
- if (event !== undefined) {
1153
- const methods = {
1154
- 'info': this.handleSystemStatus,
1155
- 'subscribed': this.handleSubscriptionStatus,
1156
- 'auth': this.handleAuthenticationMessage,
1157
- };
1158
- const method = this.safeValue(methods, event);
1159
- if (method !== undefined) {
1160
- method.call(this, client, message);
1161
- }
1162
- }
1163
- }
1164
- }
1165
- }