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.
- package/README.md +4 -4
- package/dist/ccxt.browser.min.js +2 -2
- package/dist/cjs/ccxt.js +1 -6
- package/dist/cjs/src/ace.js +42 -7
- package/dist/cjs/src/alpaca.js +46 -0
- package/dist/cjs/src/ascendex.js +1 -1
- package/dist/cjs/src/base/Exchange.js +6 -16
- package/dist/cjs/src/binance.js +20 -15
- package/dist/cjs/src/bit2c.js +11 -0
- package/dist/cjs/src/bitget.js +7 -5
- package/dist/cjs/src/bitrue.js +1 -1
- package/dist/cjs/src/bybit.js +9 -0
- package/dist/cjs/src/defx.js +1 -1
- package/dist/cjs/src/derive.js +2 -0
- package/dist/cjs/src/pro/bitget.js +1 -1
- package/js/ccxt.d.ts +2 -8
- package/js/ccxt.js +2 -6
- package/js/src/ace.js +42 -7
- package/js/src/alpaca.js +46 -0
- package/js/src/ascendex.js +1 -1
- package/js/src/base/Exchange.d.ts +1 -1
- package/js/src/base/Exchange.js +6 -16
- package/js/src/binance.js +20 -15
- package/js/src/bit2c.js +11 -0
- package/js/src/bitget.js +7 -5
- package/js/src/bitrue.js +1 -1
- package/js/src/bybit.d.ts +4 -20
- package/js/src/bybit.js +9 -0
- package/js/src/defx.js +1 -1
- package/js/src/derive.js +2 -0
- package/js/src/pro/bitget.d.ts +1 -1
- package/js/src/pro/bitget.js +1 -1
- package/package.json +1 -1
- package/js/src/bitfinex1.d.ts +0 -297
- package/js/src/bitfinex1.js +0 -1770
- package/js/src/pro/bitfinex1.d.ts +0 -67
- package/js/src/pro/bitfinex1.js +0 -676
- package/js/src/pro/bitfinex2.d.ts +0 -99
- package/js/src/pro/bitfinex2.js +0 -1165
package/js/src/pro/bitfinex2.js
DELETED
|
@@ -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
|
-
}
|