ccxt 4.1.83 → 4.1.85
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 +5 -4
- package/dist/ccxt.browser.js +1230 -361
- package/dist/ccxt.browser.min.js +2 -2
- package/dist/cjs/ccxt.js +1 -1
- package/dist/cjs/src/base/Exchange.js +3 -0
- package/dist/cjs/src/binance.js +1 -1
- package/dist/cjs/src/bingx.js +10 -8
- package/dist/cjs/src/bithumb.js +2 -2
- package/dist/cjs/src/bitmart.js +90 -73
- package/dist/cjs/src/bitopro.js +2 -2
- package/dist/cjs/src/bybit.js +3 -3
- package/dist/cjs/src/coinex.js +1 -0
- package/dist/cjs/src/coinsph.js +19 -9
- package/dist/cjs/src/htx.js +37 -4
- package/dist/cjs/src/huobijp.js +34 -5
- package/dist/cjs/src/kucoinfutures.js +0 -3
- package/dist/cjs/src/pro/bitmart.js +1026 -250
- package/js/ccxt.d.ts +1 -1
- package/js/ccxt.js +1 -1
- package/js/src/base/Exchange.d.ts +1 -0
- package/js/src/base/Exchange.js +3 -0
- package/js/src/binance.js +1 -1
- package/js/src/bingx.js +10 -8
- package/js/src/bithumb.js +2 -2
- package/js/src/bitmart.js +90 -73
- package/js/src/bitopro.js +2 -2
- package/js/src/bybit.js +3 -3
- package/js/src/coinex.js +1 -0
- package/js/src/coinsph.js +19 -9
- package/js/src/htx.d.ts +1 -0
- package/js/src/htx.js +37 -4
- package/js/src/huobijp.d.ts +1 -0
- package/js/src/huobijp.js +35 -6
- package/js/src/kucoinfutures.d.ts +0 -1
- package/js/src/kucoinfutures.js +0 -3
- package/js/src/pro/bitmart.d.ts +17 -6
- package/js/src/pro/bitmart.js +1028 -252
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ var bitmart$1 = require('../bitmart.js');
|
|
|
4
4
|
var errors = require('../base/errors.js');
|
|
5
5
|
var Cache = require('../base/ws/Cache.js');
|
|
6
6
|
var sha256 = require('../static_dependencies/noble-hashes/sha256.js');
|
|
7
|
+
var OrderBookSide = require('../base/ws/OrderBookSide.js');
|
|
7
8
|
|
|
8
9
|
// ---------------------------------------------------------------------------
|
|
9
10
|
// ---------------------------------------------------------------------------
|
|
@@ -19,24 +20,38 @@ class bitmart extends bitmart$1 {
|
|
|
19
20
|
'cancelOrdersWs': false,
|
|
20
21
|
'cancelAllOrdersWs': false,
|
|
21
22
|
'ws': true,
|
|
23
|
+
'watchBalance': true,
|
|
22
24
|
'watchTicker': true,
|
|
25
|
+
'watchTickers': true,
|
|
23
26
|
'watchOrderBook': true,
|
|
24
27
|
'watchOrders': true,
|
|
25
28
|
'watchTrades': true,
|
|
26
29
|
'watchOHLCV': true,
|
|
30
|
+
'watchPosition': 'emulated',
|
|
31
|
+
'watchPositions': true,
|
|
27
32
|
},
|
|
28
33
|
'urls': {
|
|
29
34
|
'api': {
|
|
30
35
|
'ws': {
|
|
31
|
-
'
|
|
32
|
-
|
|
36
|
+
'spot': {
|
|
37
|
+
'public': 'wss://ws-manager-compress.{hostname}/api?protocol=1.1',
|
|
38
|
+
'private': 'wss://ws-manager-compress.{hostname}/user?protocol=1.1',
|
|
39
|
+
},
|
|
40
|
+
'swap': {
|
|
41
|
+
'public': 'wss://openapi-ws.{hostname}/api?protocol=1.1',
|
|
42
|
+
'private': 'wss://openapi-ws.{hostname}/user?protocol=1.1',
|
|
43
|
+
},
|
|
33
44
|
},
|
|
34
45
|
},
|
|
35
46
|
},
|
|
36
47
|
'options': {
|
|
37
48
|
'defaultType': 'spot',
|
|
49
|
+
'watchBalance': {
|
|
50
|
+
'fetchBalanceSnapshot': true,
|
|
51
|
+
'awaitBalanceSnapshot': true, // whether to wait for the balance snapshot before providing updates
|
|
52
|
+
},
|
|
38
53
|
'watchOrderBook': {
|
|
39
|
-
'depth': '
|
|
54
|
+
'depth': 'depth50', // depth5, depth20, depth50
|
|
40
55
|
},
|
|
41
56
|
'ws': {
|
|
42
57
|
'inflate': true,
|
|
@@ -62,33 +77,166 @@ class bitmart extends bitmart$1 {
|
|
|
62
77
|
},
|
|
63
78
|
});
|
|
64
79
|
}
|
|
65
|
-
async subscribe(channel, symbol, params = {}) {
|
|
66
|
-
await this.loadMarkets();
|
|
80
|
+
async subscribe(channel, symbol, type, params = {}) {
|
|
67
81
|
const market = this.market(symbol);
|
|
68
|
-
const url = this.implodeHostname(this.urls['api']['ws']['public']);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
'
|
|
73
|
-
|
|
82
|
+
const url = this.implodeHostname(this.urls['api']['ws'][type]['public']);
|
|
83
|
+
let request = {};
|
|
84
|
+
let messageHash = undefined;
|
|
85
|
+
if (type === 'spot') {
|
|
86
|
+
messageHash = 'spot/' + channel + ':' + market['id'];
|
|
87
|
+
request = {
|
|
88
|
+
'op': 'subscribe',
|
|
89
|
+
'args': [messageHash],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
messageHash = 'futures/' + channel + ':' + market['id'];
|
|
94
|
+
request = {
|
|
95
|
+
'action': 'subscribe',
|
|
96
|
+
'args': [messageHash],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
74
99
|
return await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
|
|
75
100
|
}
|
|
76
|
-
async
|
|
101
|
+
async watchBalance(params = {}) {
|
|
102
|
+
/**
|
|
103
|
+
* @method
|
|
104
|
+
* @name bitmart#watchBalance
|
|
105
|
+
* @see https://developer-pro.bitmart.com/en/spot/#private-balance-change
|
|
106
|
+
* @see https://developer-pro.bitmart.com/en/futures/#private-assets-channel
|
|
107
|
+
* @description watch balance and get the amount of funds available for trading or funds locked in orders
|
|
108
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
109
|
+
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
|
|
110
|
+
*/
|
|
77
111
|
await this.loadMarkets();
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
112
|
+
let type = 'spot';
|
|
113
|
+
[type, params] = this.handleMarketTypeAndParams('watchBalance', undefined, params);
|
|
114
|
+
await this.authenticate(type, params);
|
|
115
|
+
let request = {};
|
|
116
|
+
if (type === 'spot') {
|
|
117
|
+
request = {
|
|
118
|
+
'op': 'subscribe',
|
|
119
|
+
'args': ['spot/user/balance:BALANCE_UPDATE'],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
request = {
|
|
124
|
+
'action': 'subscribe',
|
|
125
|
+
'args': ['futures/asset:USDT', 'futures/asset:BTC', 'futures/asset:ETH'],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const messageHash = 'balance:' + type;
|
|
129
|
+
const url = this.implodeHostname(this.urls['api']['ws'][type]['private']);
|
|
130
|
+
const client = this.client(url);
|
|
131
|
+
this.setBalanceCache(client, type);
|
|
132
|
+
const fetchBalanceSnapshot = this.handleOptionAndParams(this.options, 'watchBalance', 'fetchBalanceSnapshot', true);
|
|
133
|
+
const awaitBalanceSnapshot = this.handleOptionAndParams(this.options, 'watchBalance', 'awaitBalanceSnapshot', false);
|
|
134
|
+
if (fetchBalanceSnapshot && awaitBalanceSnapshot) {
|
|
135
|
+
await client.future(type + ':fetchBalanceSnapshot');
|
|
136
|
+
}
|
|
86
137
|
return await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
|
|
87
138
|
}
|
|
139
|
+
setBalanceCache(client, type) {
|
|
140
|
+
if (type in client.subscriptions) {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
const options = this.safeValue(this.options, 'watchBalance');
|
|
144
|
+
const fetchBalanceSnapshot = this.handleOptionAndParams(options, 'watchBalance', 'fetchBalanceSnapshot', true);
|
|
145
|
+
if (fetchBalanceSnapshot) {
|
|
146
|
+
const messageHash = type + ':fetchBalanceSnapshot';
|
|
147
|
+
if (!(messageHash in client.futures)) {
|
|
148
|
+
client.future(messageHash);
|
|
149
|
+
this.spawn(this.loadBalanceSnapshot, client, messageHash, type);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
this.balance[type] = {};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async loadBalanceSnapshot(client, messageHash, type) {
|
|
157
|
+
const response = await this.fetchBalance({ 'type': type });
|
|
158
|
+
this.balance[type] = this.extend(response, this.safeValue(this.balance, type, {}));
|
|
159
|
+
// don't remove the future from the .futures cache
|
|
160
|
+
const future = client.futures[messageHash];
|
|
161
|
+
future.resolve();
|
|
162
|
+
client.resolve(this.balance[type], 'balance:' + type);
|
|
163
|
+
}
|
|
164
|
+
handleBalance(client, message) {
|
|
165
|
+
//
|
|
166
|
+
// spot
|
|
167
|
+
// {
|
|
168
|
+
// "data":[
|
|
169
|
+
// {
|
|
170
|
+
// "balance_details":[
|
|
171
|
+
// {
|
|
172
|
+
// "av_bal":"0.206000000000000000000000000000",
|
|
173
|
+
// "ccy":"LTC",
|
|
174
|
+
// "fz_bal":"0.100000000000000000000000000000"
|
|
175
|
+
// }
|
|
176
|
+
// ],
|
|
177
|
+
// "event_time":"1701632345415",
|
|
178
|
+
// "event_type":"TRANSACTION_COMPLETED"
|
|
179
|
+
// }
|
|
180
|
+
// ],
|
|
181
|
+
// "table":"spot/user/balance"
|
|
182
|
+
// }
|
|
183
|
+
// swap
|
|
184
|
+
// {
|
|
185
|
+
// group: 'futures/asset:USDT',
|
|
186
|
+
// data: {
|
|
187
|
+
// currency: 'USDT',
|
|
188
|
+
// available_balance: '37.19688649135',
|
|
189
|
+
// position_deposit: '0.788687546',
|
|
190
|
+
// frozen_balance: '0'
|
|
191
|
+
// }
|
|
192
|
+
// }
|
|
193
|
+
//
|
|
194
|
+
const channel = this.safeString2(message, 'table', 'group');
|
|
195
|
+
const data = this.safeValue(message, 'data');
|
|
196
|
+
if (data === undefined) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const isSpot = (channel.indexOf('spot') >= 0);
|
|
200
|
+
const type = isSpot ? 'spot' : 'swap';
|
|
201
|
+
this.balance['info'] = message;
|
|
202
|
+
if (isSpot) {
|
|
203
|
+
if (!Array.isArray(data)) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
for (let i = 0; i < data.length; i++) {
|
|
207
|
+
const timestamp = this.safeInteger(message, 'event_time');
|
|
208
|
+
this.balance['timestamp'] = timestamp;
|
|
209
|
+
this.balance['datetime'] = this.iso8601(timestamp);
|
|
210
|
+
const balanceDetails = this.safeValue(data[i], 'balance_details', []);
|
|
211
|
+
for (let ii = 0; ii < balanceDetails.length; ii++) {
|
|
212
|
+
const rawBalance = balanceDetails[i];
|
|
213
|
+
const account = this.account();
|
|
214
|
+
const currencyId = this.safeString(rawBalance, 'ccy');
|
|
215
|
+
const code = this.safeCurrencyCode(currencyId);
|
|
216
|
+
account['free'] = this.safeString(rawBalance, 'av_bal');
|
|
217
|
+
account['total'] = this.safeString(rawBalance, 'fz_bal');
|
|
218
|
+
this.balance[code] = account;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
const currencyId = this.safeString(data, 'currency');
|
|
224
|
+
const code = this.safeCurrencyCode(currencyId);
|
|
225
|
+
const account = this.account();
|
|
226
|
+
account['free'] = this.safeString(data, 'available_balance');
|
|
227
|
+
account['used'] = this.safeString(data, 'frozen_balance');
|
|
228
|
+
this.balance[type][code] = account;
|
|
229
|
+
}
|
|
230
|
+
this.balance[type] = this.safeBalance(this.balance[type]);
|
|
231
|
+
const messageHash = 'balance:' + type;
|
|
232
|
+
client.resolve(this.balance[type], messageHash);
|
|
233
|
+
}
|
|
88
234
|
async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
|
|
89
235
|
/**
|
|
90
236
|
* @method
|
|
91
237
|
* @name bitmart#watchTrades
|
|
238
|
+
* @see https://developer-pro.bitmart.com/en/spot/#public-trade-channel
|
|
239
|
+
* @see https://developer-pro.bitmart.com/en/futures/#public-trade-channel
|
|
92
240
|
* @description get the list of most recent trades for a particular symbol
|
|
93
241
|
* @param {string} symbol unified symbol of the market to fetch trades for
|
|
94
242
|
* @param {int} [since] timestamp in ms of the earliest trade to fetch
|
|
@@ -98,7 +246,10 @@ class bitmart extends bitmart$1 {
|
|
|
98
246
|
*/
|
|
99
247
|
await this.loadMarkets();
|
|
100
248
|
symbol = this.symbol(symbol);
|
|
101
|
-
const
|
|
249
|
+
const market = this.market(symbol);
|
|
250
|
+
let type = 'spot';
|
|
251
|
+
[type, params] = this.handleMarketTypeAndParams('watchTrades', market, params);
|
|
252
|
+
const trades = await this.subscribe('trade', symbol, type, params);
|
|
102
253
|
if (this.newUpdates) {
|
|
103
254
|
limit = trades.getLimit(symbol, limit);
|
|
104
255
|
}
|
|
@@ -108,17 +259,64 @@ class bitmart extends bitmart$1 {
|
|
|
108
259
|
/**
|
|
109
260
|
* @method
|
|
110
261
|
* @name bitmart#watchTicker
|
|
262
|
+
* @see https://developer-pro.bitmart.com/en/spot/#public-ticker-channel
|
|
111
263
|
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
112
264
|
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
113
265
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
114
266
|
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
115
267
|
*/
|
|
116
|
-
|
|
268
|
+
await this.loadMarkets();
|
|
269
|
+
symbol = this.symbol(symbol);
|
|
270
|
+
const market = this.market(symbol);
|
|
271
|
+
let type = 'spot';
|
|
272
|
+
[type, params] = this.handleMarketTypeAndParams('watchTicker', market, params);
|
|
273
|
+
if (type === 'swap') {
|
|
274
|
+
throw new errors.NotSupported(this.id + ' watchTicker() does not support ' + type + ' markets. Use watchTickers() instead');
|
|
275
|
+
}
|
|
276
|
+
return await this.subscribe('ticker', symbol, type, params);
|
|
277
|
+
}
|
|
278
|
+
async watchTickers(symbols = undefined, params = {}) {
|
|
279
|
+
/**
|
|
280
|
+
* @method
|
|
281
|
+
* @name bitmart#watchTickers
|
|
282
|
+
* @see https://developer-pro.bitmart.com/en/futures/#overview
|
|
283
|
+
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
|
284
|
+
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
|
|
285
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
286
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
287
|
+
*/
|
|
288
|
+
await this.loadMarkets();
|
|
289
|
+
const market = this.getMarketFromSymbols(symbols);
|
|
290
|
+
let type = 'spot';
|
|
291
|
+
[type, params] = this.handleMarketTypeAndParams('watchTickers', market, params);
|
|
292
|
+
symbols = this.marketSymbols(symbols);
|
|
293
|
+
if (type === 'spot') {
|
|
294
|
+
throw new errors.NotSupported(this.id + ' watchTickers() does not support ' + type + ' markets. Use watchTicker() instead');
|
|
295
|
+
}
|
|
296
|
+
const url = this.implodeHostname(this.urls['api']['ws'][type]['public']);
|
|
297
|
+
if (type === 'swap') {
|
|
298
|
+
type = 'futures';
|
|
299
|
+
}
|
|
300
|
+
let messageHash = 'tickers';
|
|
301
|
+
if (symbols !== undefined) {
|
|
302
|
+
messageHash += '::' + symbols.join(',');
|
|
303
|
+
}
|
|
304
|
+
const request = {
|
|
305
|
+
'action': 'subscribe',
|
|
306
|
+
'args': ['futures/ticker'],
|
|
307
|
+
};
|
|
308
|
+
const newTickers = await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
|
|
309
|
+
if (this.newUpdates) {
|
|
310
|
+
return newTickers;
|
|
311
|
+
}
|
|
312
|
+
return this.filterByArray(this.tickers, 'symbol', symbols);
|
|
117
313
|
}
|
|
118
314
|
async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
119
315
|
/**
|
|
120
316
|
* @method
|
|
121
317
|
* @name bitmart#watchOrders
|
|
318
|
+
* @see https://developer-pro.bitmart.com/en/spot/#private-order-channel
|
|
319
|
+
* @see https://developer-pro.bitmart.com/en/futures/#private-order-channel
|
|
122
320
|
* @description watches information on multiple orders made by the user
|
|
123
321
|
* @param {string} symbol unified market symbol of the market orders were made in
|
|
124
322
|
* @param {int} [since] the earliest time in ms to fetch orders for
|
|
@@ -126,196 +324,626 @@ class bitmart extends bitmart$1 {
|
|
|
126
324
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
127
325
|
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
128
326
|
*/
|
|
129
|
-
if (symbol === undefined) {
|
|
130
|
-
throw new errors.ArgumentsRequired(this.id + ' watchOrders() requires a symbol argument');
|
|
131
|
-
}
|
|
132
327
|
await this.loadMarkets();
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (
|
|
136
|
-
|
|
328
|
+
let market = undefined;
|
|
329
|
+
let messageHash = 'orders';
|
|
330
|
+
if (symbol !== undefined) {
|
|
331
|
+
symbol = this.symbol(symbol);
|
|
332
|
+
market = this.market(symbol);
|
|
333
|
+
messageHash = 'orders::' + symbol;
|
|
334
|
+
}
|
|
335
|
+
let type = 'spot';
|
|
336
|
+
[type, params] = this.handleMarketTypeAndParams('watchOrders', market, params);
|
|
337
|
+
await this.authenticate(type, params);
|
|
338
|
+
let request = undefined;
|
|
339
|
+
if (type === 'spot') {
|
|
340
|
+
if (symbol === undefined) {
|
|
341
|
+
throw new errors.ArgumentsRequired(this.id + ' watchOrders() requires a symbol argument for spot markets');
|
|
342
|
+
}
|
|
343
|
+
request = {
|
|
344
|
+
'op': 'subscribe',
|
|
345
|
+
'args': ['spot/user/order:' + market['id']],
|
|
346
|
+
};
|
|
137
347
|
}
|
|
138
|
-
|
|
139
|
-
|
|
348
|
+
else {
|
|
349
|
+
request = {
|
|
350
|
+
'action': 'subscribe',
|
|
351
|
+
'args': ['futures/order'],
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
const url = this.implodeHostname(this.urls['api']['ws'][type]['private']);
|
|
355
|
+
const newOrders = await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
|
|
140
356
|
if (this.newUpdates) {
|
|
141
|
-
|
|
357
|
+
return newOrders;
|
|
142
358
|
}
|
|
143
|
-
return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
|
|
359
|
+
return this.filterBySymbolSinceLimit(this.orders, symbol, since, limit, true);
|
|
144
360
|
}
|
|
145
361
|
handleOrders(client, message) {
|
|
146
362
|
//
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
//
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
//
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
//
|
|
363
|
+
// spot
|
|
364
|
+
// {
|
|
365
|
+
// "data":[
|
|
366
|
+
// {
|
|
367
|
+
// "symbol": "LTC_USDT",
|
|
368
|
+
// "notional": '',
|
|
369
|
+
// "side": "buy",
|
|
370
|
+
// "last_fill_time": "0",
|
|
371
|
+
// "ms_t": "1646216634000",
|
|
372
|
+
// "type": "limit",
|
|
373
|
+
// "filled_notional": "0.000000000000000000000000000000",
|
|
374
|
+
// "last_fill_price": "0",
|
|
375
|
+
// "size": "0.500000000000000000000000000000",
|
|
376
|
+
// "price": "50.000000000000000000000000000000",
|
|
377
|
+
// "last_fill_count": "0",
|
|
378
|
+
// "filled_size": "0.000000000000000000000000000000",
|
|
379
|
+
// "margin_trading": "0",
|
|
380
|
+
// "state": "8",
|
|
381
|
+
// "order_id": "24807076628",
|
|
382
|
+
// "order_type": "0"
|
|
383
|
+
// }
|
|
384
|
+
// ],
|
|
385
|
+
// "table":"spot/user/order"
|
|
386
|
+
// }
|
|
387
|
+
// swap
|
|
388
|
+
// {
|
|
389
|
+
// "group":"futures/order",
|
|
390
|
+
// "data":[
|
|
391
|
+
// {
|
|
392
|
+
// "action":2,
|
|
393
|
+
// "order":{
|
|
394
|
+
// "order_id":"2312045036986775",
|
|
395
|
+
// "client_order_id":"",
|
|
396
|
+
// "price":"71.61707928",
|
|
397
|
+
// "size":"1",
|
|
398
|
+
// "symbol":"LTCUSDT",
|
|
399
|
+
// "state":1,
|
|
400
|
+
// "side":4,
|
|
401
|
+
// "type":"market",
|
|
402
|
+
// "leverage":"1",
|
|
403
|
+
// "open_type":"cross",
|
|
404
|
+
// "deal_avg_price":"0",
|
|
405
|
+
// "deal_size":"0",
|
|
406
|
+
// "create_time":1701625324646,
|
|
407
|
+
// "update_time":1701625324640,
|
|
408
|
+
// "plan_order_id":"",
|
|
409
|
+
// "last_trade":null
|
|
410
|
+
// }
|
|
166
411
|
// }
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
// }
|
|
412
|
+
// ]
|
|
413
|
+
// }
|
|
170
414
|
//
|
|
171
|
-
const
|
|
172
|
-
|
|
415
|
+
const orders = this.safeValue(message, 'data');
|
|
416
|
+
if (orders === undefined) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
173
419
|
const ordersLength = orders.length;
|
|
420
|
+
const newOrders = [];
|
|
421
|
+
const symbols = {};
|
|
174
422
|
if (ordersLength > 0) {
|
|
175
423
|
const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
|
|
176
424
|
if (this.orders === undefined) {
|
|
177
425
|
this.orders = new Cache.ArrayCacheBySymbolById(limit);
|
|
178
426
|
}
|
|
179
427
|
const stored = this.orders;
|
|
180
|
-
const marketIds = [];
|
|
181
428
|
for (let i = 0; i < orders.length; i++) {
|
|
182
429
|
const order = this.parseWsOrder(orders[i]);
|
|
183
430
|
stored.append(order);
|
|
431
|
+
newOrders.push(order);
|
|
184
432
|
const symbol = order['symbol'];
|
|
185
|
-
|
|
186
|
-
marketIds.push(market['id']);
|
|
187
|
-
}
|
|
188
|
-
for (let i = 0; i < marketIds.length; i++) {
|
|
189
|
-
const messageHash = channel + ':' + marketIds[i];
|
|
190
|
-
client.resolve(this.orders, messageHash);
|
|
433
|
+
symbols[symbol] = true;
|
|
191
434
|
}
|
|
192
435
|
}
|
|
436
|
+
const newOrderSymbols = Object.keys(symbols);
|
|
437
|
+
for (let i = 0; i < newOrderSymbols.length; i++) {
|
|
438
|
+
const symbol = newOrderSymbols[i];
|
|
439
|
+
this.resolvePromiseIfMessagehashMatches(client, 'orders::', symbol, newOrders);
|
|
440
|
+
}
|
|
441
|
+
client.resolve(newOrders, 'orders');
|
|
193
442
|
}
|
|
194
443
|
parseWsOrder(order, market = undefined) {
|
|
195
444
|
//
|
|
196
|
-
//
|
|
197
|
-
//
|
|
198
|
-
//
|
|
199
|
-
//
|
|
200
|
-
//
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
//
|
|
204
|
-
//
|
|
205
|
-
//
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
//
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
445
|
+
// spot
|
|
446
|
+
// {
|
|
447
|
+
// "symbol": "LTC_USDT",
|
|
448
|
+
// "notional": '',
|
|
449
|
+
// "side": "buy",
|
|
450
|
+
// "last_fill_time": "0",
|
|
451
|
+
// "ms_t": "1646216634000",
|
|
452
|
+
// "type": "limit",
|
|
453
|
+
// "filled_notional": "0.000000000000000000000000000000",
|
|
454
|
+
// "last_fill_price": "0",
|
|
455
|
+
// "size": "0.500000000000000000000000000000",
|
|
456
|
+
// "price": "50.000000000000000000000000000000",
|
|
457
|
+
// "last_fill_count": "0",
|
|
458
|
+
// "filled_size": "0.000000000000000000000000000000",
|
|
459
|
+
// "margin_trading": "0",
|
|
460
|
+
// "state": "8",
|
|
461
|
+
// "order_id": "24807076628",
|
|
462
|
+
// "order_type": "0"
|
|
463
|
+
// }
|
|
464
|
+
// swap
|
|
465
|
+
// {
|
|
466
|
+
// "action":2,
|
|
467
|
+
// "order":{
|
|
468
|
+
// "order_id":"2312045036986775",
|
|
469
|
+
// "client_order_id":"",
|
|
470
|
+
// "price":"71.61707928",
|
|
471
|
+
// "size":"1",
|
|
472
|
+
// "symbol":"LTCUSDT",
|
|
473
|
+
// "state":1,
|
|
474
|
+
// "side":4,
|
|
475
|
+
// "type":"market",
|
|
476
|
+
// "leverage":"1",
|
|
477
|
+
// "open_type":"cross",
|
|
478
|
+
// "deal_avg_price":"0",
|
|
479
|
+
// "deal_size":"0",
|
|
480
|
+
// "create_time":1701625324646,
|
|
481
|
+
// "update_time":1701625324640,
|
|
482
|
+
// "plan_order_id":"",
|
|
483
|
+
// "last_trade":null
|
|
484
|
+
// }
|
|
485
|
+
// }
|
|
486
|
+
//
|
|
487
|
+
const action = this.safeNumber(order, 'action');
|
|
488
|
+
const isSpot = (action === undefined);
|
|
489
|
+
if (isSpot) {
|
|
490
|
+
const marketId = this.safeString(order, 'symbol');
|
|
491
|
+
market = this.safeMarket(marketId, market, '_', 'spot');
|
|
492
|
+
const id = this.safeString(order, 'order_id');
|
|
493
|
+
const clientOrderId = this.safeString(order, 'clientOid');
|
|
494
|
+
const price = this.safeString(order, 'price');
|
|
495
|
+
const filled = this.safeString(order, 'filled_size');
|
|
496
|
+
const amount = this.safeString(order, 'size');
|
|
497
|
+
const type = this.safeString(order, 'type');
|
|
498
|
+
const rawState = this.safeString(order, 'state');
|
|
499
|
+
const status = this.parseOrderStatusByType(market['type'], rawState);
|
|
500
|
+
const timestamp = this.safeInteger(order, 'ms_t');
|
|
501
|
+
const symbol = market['symbol'];
|
|
502
|
+
const side = this.safeStringLower(order, 'side');
|
|
503
|
+
return this.safeOrder({
|
|
504
|
+
'info': order,
|
|
505
|
+
'symbol': symbol,
|
|
506
|
+
'id': id,
|
|
507
|
+
'clientOrderId': clientOrderId,
|
|
508
|
+
'timestamp': undefined,
|
|
509
|
+
'datetime': undefined,
|
|
510
|
+
'lastTradeTimestamp': timestamp,
|
|
511
|
+
'type': type,
|
|
512
|
+
'timeInForce': undefined,
|
|
513
|
+
'postOnly': undefined,
|
|
514
|
+
'side': side,
|
|
515
|
+
'price': price,
|
|
516
|
+
'stopPrice': undefined,
|
|
517
|
+
'triggerPrice': undefined,
|
|
518
|
+
'amount': amount,
|
|
519
|
+
'cost': undefined,
|
|
520
|
+
'average': undefined,
|
|
521
|
+
'filled': filled,
|
|
522
|
+
'remaining': undefined,
|
|
523
|
+
'status': status,
|
|
524
|
+
'fee': undefined,
|
|
525
|
+
'trades': undefined,
|
|
526
|
+
}, market);
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
const orderInfo = this.safeValue(order, 'order');
|
|
530
|
+
const marketId = this.safeString(orderInfo, 'symbol');
|
|
531
|
+
const symbol = this.safeSymbol(marketId, market, '', 'swap');
|
|
532
|
+
const orderId = this.safeString(orderInfo, 'order_id');
|
|
533
|
+
const timestamp = this.safeInteger(orderInfo, 'create_time');
|
|
534
|
+
const updatedTimestamp = this.safeInteger(orderInfo, 'update_time');
|
|
535
|
+
const lastTrade = this.safeValue(orderInfo, 'last_trade');
|
|
536
|
+
const cachedOrders = this.orders;
|
|
537
|
+
const orders = this.safeValue(cachedOrders.hashmap, symbol, {});
|
|
538
|
+
const cachedOrder = this.safeValue(orders, orderId);
|
|
539
|
+
let trades = undefined;
|
|
540
|
+
if (cachedOrder !== undefined) {
|
|
541
|
+
trades = this.safeValue(order, 'trades');
|
|
542
|
+
}
|
|
543
|
+
if (lastTrade !== undefined) {
|
|
544
|
+
if (trades === undefined) {
|
|
545
|
+
trades = [];
|
|
546
|
+
}
|
|
547
|
+
trades.push(lastTrade);
|
|
548
|
+
}
|
|
549
|
+
return this.safeOrder({
|
|
550
|
+
'info': order,
|
|
551
|
+
'symbol': symbol,
|
|
552
|
+
'id': orderId,
|
|
553
|
+
'clientOrderId': this.safeString(orderInfo, 'client_order_id'),
|
|
554
|
+
'timestamp': timestamp,
|
|
555
|
+
'datetime': this.iso8601(timestamp),
|
|
556
|
+
'lastTradeTimestamp': updatedTimestamp,
|
|
557
|
+
'type': this.safeString(orderInfo, 'type'),
|
|
558
|
+
'timeInForce': undefined,
|
|
559
|
+
'postOnly': undefined,
|
|
560
|
+
'side': this.parseWsOrderSide(this.safeString(orderInfo, 'side')),
|
|
561
|
+
'price': this.safeString(orderInfo, 'price'),
|
|
562
|
+
'stopPrice': undefined,
|
|
563
|
+
'triggerPrice': undefined,
|
|
564
|
+
'amount': this.safeString(orderInfo, 'size'),
|
|
565
|
+
'cost': undefined,
|
|
566
|
+
'average': this.safeString(orderInfo, 'deal_avg_price'),
|
|
567
|
+
'filled': this.safeString(orderInfo, 'deal_size'),
|
|
568
|
+
'remaining': undefined,
|
|
569
|
+
'status': this.parseWsOrderStatus(this.safeString(order, 'action')),
|
|
570
|
+
'fee': undefined,
|
|
571
|
+
'trades': trades,
|
|
572
|
+
}, market);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
parseWsOrderStatus(statusId) {
|
|
576
|
+
const statuses = {
|
|
577
|
+
'1': 'closed',
|
|
578
|
+
'2': 'open',
|
|
579
|
+
'3': 'canceled',
|
|
580
|
+
'4': 'closed',
|
|
581
|
+
'5': 'canceled',
|
|
582
|
+
'6': 'open',
|
|
583
|
+
'7': 'open',
|
|
584
|
+
'8': 'closed',
|
|
585
|
+
'9': 'closed', // active adl match deal
|
|
586
|
+
};
|
|
587
|
+
return this.safeString(statuses, statusId, statusId);
|
|
588
|
+
}
|
|
589
|
+
parseWsOrderSide(sideId) {
|
|
590
|
+
const sides = {
|
|
591
|
+
'1': 'buy',
|
|
592
|
+
'2': 'buy',
|
|
593
|
+
'3': 'sell',
|
|
594
|
+
'4': 'sell', // sell_open_short
|
|
595
|
+
};
|
|
596
|
+
return this.safeString(sides, sideId, sideId);
|
|
597
|
+
}
|
|
598
|
+
async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
|
|
599
|
+
/**
|
|
600
|
+
* @method
|
|
601
|
+
* @name bitmart#watchPositions
|
|
602
|
+
* @see https://developer-pro.bitmart.com/en/futures/#private-position-channel
|
|
603
|
+
* @description watch all open positions
|
|
604
|
+
* @param {string[]|undefined} symbols list of unified market symbols
|
|
605
|
+
* @param {object} params extra parameters specific to the exchange API endpoint
|
|
606
|
+
* @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
|
|
607
|
+
*/
|
|
608
|
+
await this.loadMarkets();
|
|
609
|
+
const type = 'swap';
|
|
610
|
+
await this.authenticate(type, params);
|
|
611
|
+
symbols = this.marketSymbols(symbols, 'swap', true, true, false);
|
|
612
|
+
let messageHash = 'positions';
|
|
613
|
+
if (symbols !== undefined) {
|
|
614
|
+
messageHash += '::' + symbols.join(',');
|
|
615
|
+
}
|
|
616
|
+
const subscriptionHash = 'futures/position';
|
|
617
|
+
const request = {
|
|
618
|
+
'action': 'subscribe',
|
|
619
|
+
'args': ['futures/position'],
|
|
620
|
+
};
|
|
621
|
+
const url = this.implodeHostname(this.urls['api']['ws'][type]['private']);
|
|
622
|
+
const newPositions = await this.watch(url, messageHash, this.deepExtend(request, params), subscriptionHash);
|
|
623
|
+
if (this.newUpdates) {
|
|
624
|
+
return newPositions;
|
|
625
|
+
}
|
|
626
|
+
return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit);
|
|
627
|
+
}
|
|
628
|
+
handlePositions(client, message) {
|
|
629
|
+
//
|
|
630
|
+
// {
|
|
631
|
+
// "group":"futures/position",
|
|
632
|
+
// "data":[
|
|
633
|
+
// {
|
|
634
|
+
// "symbol":"LTCUSDT",
|
|
635
|
+
// "hold_volume":"5",
|
|
636
|
+
// "position_type":2,
|
|
637
|
+
// "open_type":2,
|
|
638
|
+
// "frozen_volume":"0",
|
|
639
|
+
// "close_volume":"0",
|
|
640
|
+
// "hold_avg_price":"71.582",
|
|
641
|
+
// "close_avg_price":"0",
|
|
642
|
+
// "open_avg_price":"71.582",
|
|
643
|
+
// "liquidate_price":"0",
|
|
644
|
+
// "create_time":1701623327513,
|
|
645
|
+
// "update_time":1701627620439
|
|
646
|
+
// },
|
|
647
|
+
// {
|
|
648
|
+
// "symbol":"LTCUSDT",
|
|
649
|
+
// "hold_volume":"6",
|
|
650
|
+
// "position_type":1,
|
|
651
|
+
// "open_type":2,
|
|
652
|
+
// "frozen_volume":"0",
|
|
653
|
+
// "close_volume":"0",
|
|
654
|
+
// "hold_avg_price":"71.681666666666666667",
|
|
655
|
+
// "close_avg_price":"0",
|
|
656
|
+
// "open_avg_price":"71.681666666666666667",
|
|
657
|
+
// "liquidate_price":"0",
|
|
658
|
+
// "create_time":1701621167225,
|
|
659
|
+
// "update_time":1701628152614
|
|
660
|
+
// }
|
|
661
|
+
// ]
|
|
662
|
+
// }
|
|
663
|
+
//
|
|
664
|
+
const data = this.safeValue(message, 'data', []);
|
|
665
|
+
const cache = this.positions;
|
|
666
|
+
if (this.positions === undefined) {
|
|
667
|
+
this.positions = new Cache.ArrayCacheBySymbolBySide();
|
|
668
|
+
}
|
|
669
|
+
const newPositions = [];
|
|
670
|
+
for (let i = 0; i < data.length; i++) {
|
|
671
|
+
const rawPosition = data[i];
|
|
672
|
+
const position = this.parseWsPosition(rawPosition);
|
|
673
|
+
newPositions.push(position);
|
|
674
|
+
cache.append(position);
|
|
675
|
+
}
|
|
676
|
+
const messageHashes = this.findMessageHashes(client, 'positions::');
|
|
677
|
+
for (let i = 0; i < messageHashes.length; i++) {
|
|
678
|
+
const messageHash = messageHashes[i];
|
|
679
|
+
const parts = messageHash.split('::');
|
|
680
|
+
const symbolsString = parts[1];
|
|
681
|
+
const symbols = symbolsString.split(',');
|
|
682
|
+
const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
|
|
683
|
+
if (!this.isEmpty(positions)) {
|
|
684
|
+
client.resolve(positions, messageHash);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
client.resolve(newPositions, 'positions');
|
|
688
|
+
}
|
|
689
|
+
parseWsPosition(position, market = undefined) {
|
|
690
|
+
//
|
|
691
|
+
// {
|
|
692
|
+
// "symbol":"LTCUSDT",
|
|
693
|
+
// "hold_volume":"6",
|
|
694
|
+
// "position_type":1,
|
|
695
|
+
// "open_type":2,
|
|
696
|
+
// "frozen_volume":"0",
|
|
697
|
+
// "close_volume":"0",
|
|
698
|
+
// "hold_avg_price":"71.681666666666666667",
|
|
699
|
+
// "close_avg_price":"0",
|
|
700
|
+
// "open_avg_price":"71.681666666666666667",
|
|
701
|
+
// "liquidate_price":"0",
|
|
702
|
+
// "create_time":1701621167225,
|
|
703
|
+
// "update_time":1701628152614
|
|
704
|
+
// }
|
|
705
|
+
//
|
|
706
|
+
const marketId = this.safeString(position, 'symbol');
|
|
707
|
+
market = this.safeMarket(marketId, market, '', 'swap');
|
|
226
708
|
const symbol = market['symbol'];
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
709
|
+
const openTimestamp = this.safeInteger(position, 'create_time');
|
|
710
|
+
const timestamp = this.safeInteger(position, 'update_time');
|
|
711
|
+
const side = this.safeNumber(position, 'position_type');
|
|
712
|
+
const marginModeId = this.safeNumber(position, 'open_type');
|
|
713
|
+
return this.safePosition({
|
|
714
|
+
'info': position,
|
|
715
|
+
'id': undefined,
|
|
230
716
|
'symbol': symbol,
|
|
231
|
-
'
|
|
232
|
-
'
|
|
233
|
-
'
|
|
234
|
-
'
|
|
235
|
-
'
|
|
236
|
-
'
|
|
237
|
-
'
|
|
238
|
-
'
|
|
239
|
-
'
|
|
240
|
-
'
|
|
241
|
-
'
|
|
242
|
-
'
|
|
243
|
-
'
|
|
244
|
-
'
|
|
245
|
-
'
|
|
246
|
-
'
|
|
247
|
-
'
|
|
248
|
-
'
|
|
249
|
-
'
|
|
250
|
-
'
|
|
251
|
-
|
|
717
|
+
'timestamp': openTimestamp,
|
|
718
|
+
'datetime': this.iso8601(openTimestamp),
|
|
719
|
+
'lastUpdateTimestamp': timestamp,
|
|
720
|
+
'hedged': undefined,
|
|
721
|
+
'side': (side === 1) ? 'long' : 'short',
|
|
722
|
+
'contracts': this.safeNumber(position, 'hold_volume'),
|
|
723
|
+
'contractSize': this.safeNumber(market, 'contractSize'),
|
|
724
|
+
'entryPrice': this.safeNumber(position, 'open_avg_price'),
|
|
725
|
+
'markPrice': this.safeNumber(position, 'hold_avg_price'),
|
|
726
|
+
'lastPrice': undefined,
|
|
727
|
+
'notional': undefined,
|
|
728
|
+
'leverage': undefined,
|
|
729
|
+
'collateral': undefined,
|
|
730
|
+
'initialMargin': undefined,
|
|
731
|
+
'initialMarginPercentage': undefined,
|
|
732
|
+
'maintenanceMargin': undefined,
|
|
733
|
+
'maintenanceMarginPercentage': undefined,
|
|
734
|
+
'unrealizedPnl': undefined,
|
|
735
|
+
'realizedPnl': undefined,
|
|
736
|
+
'liquidationPrice': this.safeNumber(position, 'liquidate_price'),
|
|
737
|
+
'marginMode': (marginModeId === 1) ? 'isolated' : 'cross',
|
|
738
|
+
'percentage': undefined,
|
|
739
|
+
'marginRatio': undefined,
|
|
740
|
+
'stopLossPrice': undefined,
|
|
741
|
+
'takeProfitPrice': undefined,
|
|
742
|
+
});
|
|
252
743
|
}
|
|
253
744
|
handleTrade(client, message) {
|
|
254
745
|
//
|
|
255
|
-
//
|
|
256
|
-
//
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
-
//
|
|
265
|
-
//
|
|
266
|
-
//
|
|
746
|
+
// spot
|
|
747
|
+
// {
|
|
748
|
+
// "table": "spot/trade",
|
|
749
|
+
// "data": [
|
|
750
|
+
// {
|
|
751
|
+
// "price": "52700.50",
|
|
752
|
+
// "s_t": 1630982050,
|
|
753
|
+
// "side": "buy",
|
|
754
|
+
// "size": "0.00112",
|
|
755
|
+
// "symbol": "BTC_USDT"
|
|
756
|
+
// },
|
|
757
|
+
// ]
|
|
758
|
+
// }
|
|
267
759
|
//
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
760
|
+
// swap
|
|
761
|
+
// {
|
|
762
|
+
// "group":"futures/trade:BTCUSDT",
|
|
763
|
+
// "data":[
|
|
764
|
+
// {
|
|
765
|
+
// "trade_id":6798697637,
|
|
766
|
+
// "contract_id":1,
|
|
767
|
+
// "symbol":"BTCUSDT",
|
|
768
|
+
// "deal_price":"39735.8",
|
|
769
|
+
// "deal_vol":"2",
|
|
770
|
+
// "type":0,
|
|
771
|
+
// "way":1,
|
|
772
|
+
// "create_time":1701618503,
|
|
773
|
+
// "create_time_mill":1701618503517,
|
|
774
|
+
// "created_at":"2023-12-03T15:48:23.517518538Z"
|
|
775
|
+
// }
|
|
776
|
+
// ]
|
|
777
|
+
// }
|
|
778
|
+
//
|
|
779
|
+
const channel = this.safeString2(message, 'table', 'group');
|
|
780
|
+
const isSpot = (channel.indexOf('spot') >= 0);
|
|
781
|
+
const data = this.safeValue(message, 'data');
|
|
782
|
+
if (data === undefined) {
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
let stored = undefined;
|
|
271
786
|
for (let i = 0; i < data.length; i++) {
|
|
272
|
-
const trade = this.
|
|
787
|
+
const trade = this.parseWsTrade(data[i]);
|
|
273
788
|
const symbol = trade['symbol'];
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
let stored = this.safeValue(this.trades, symbol);
|
|
789
|
+
const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
|
|
790
|
+
stored = this.safeValue(this.trades, symbol);
|
|
277
791
|
if (stored === undefined) {
|
|
278
792
|
stored = new Cache.ArrayCache(tradesLimit);
|
|
279
793
|
this.trades[symbol] = stored;
|
|
280
794
|
}
|
|
281
795
|
stored.append(trade);
|
|
282
|
-
client.resolve(stored, messageHash);
|
|
283
796
|
}
|
|
797
|
+
let messageHash = channel;
|
|
798
|
+
if (isSpot) {
|
|
799
|
+
messageHash += ':' + this.safeString(data[0], 'symbol');
|
|
800
|
+
}
|
|
801
|
+
client.resolve(stored, messageHash);
|
|
284
802
|
return message;
|
|
285
803
|
}
|
|
804
|
+
parseWsTrade(trade, market = undefined) {
|
|
805
|
+
// spot
|
|
806
|
+
// {
|
|
807
|
+
// "price": "52700.50",
|
|
808
|
+
// "s_t": 1630982050,
|
|
809
|
+
// "side": "buy",
|
|
810
|
+
// "size": "0.00112",
|
|
811
|
+
// "symbol": "BTC_USDT"
|
|
812
|
+
// }
|
|
813
|
+
// swap
|
|
814
|
+
// {
|
|
815
|
+
// "trade_id":6798697637,
|
|
816
|
+
// "contract_id":1,
|
|
817
|
+
// "symbol":"BTCUSDT",
|
|
818
|
+
// "deal_price":"39735.8",
|
|
819
|
+
// "deal_vol":"2",
|
|
820
|
+
// "type":0,
|
|
821
|
+
// "way":1,
|
|
822
|
+
// "create_time":1701618503,
|
|
823
|
+
// "create_time_mill":1701618503517,
|
|
824
|
+
// "created_at":"2023-12-03T15:48:23.517518538Z"
|
|
825
|
+
// }
|
|
826
|
+
//
|
|
827
|
+
const contractId = this.safeString(trade, 'contract_id');
|
|
828
|
+
const marketType = (contractId === undefined) ? 'spot' : 'swap';
|
|
829
|
+
const marketDelimiter = (marketType === 'spot') ? '_' : '';
|
|
830
|
+
const timestamp = this.safeInteger(trade, 'create_time_mill', this.safeTimestamp(trade, 's_t'));
|
|
831
|
+
const marketId = this.safeString(trade, 'symbol');
|
|
832
|
+
return this.safeTrade({
|
|
833
|
+
'info': trade,
|
|
834
|
+
'id': this.safeString(trade, 'trade_id'),
|
|
835
|
+
'order': undefined,
|
|
836
|
+
'timestamp': timestamp,
|
|
837
|
+
'datetime': this.iso8601(timestamp),
|
|
838
|
+
'symbol': this.safeSymbol(marketId, market, marketDelimiter, marketType),
|
|
839
|
+
'type': undefined,
|
|
840
|
+
'side': this.safeString(trade, 'side'),
|
|
841
|
+
'price': this.safeString2(trade, 'price', 'deal_price'),
|
|
842
|
+
'amount': this.safeString2(trade, 'size', 'deal_vol'),
|
|
843
|
+
'cost': undefined,
|
|
844
|
+
'takerOrMaker': undefined,
|
|
845
|
+
'fee': undefined,
|
|
846
|
+
}, market);
|
|
847
|
+
}
|
|
286
848
|
handleTicker(client, message) {
|
|
287
849
|
//
|
|
288
|
-
//
|
|
289
|
-
//
|
|
290
|
-
//
|
|
291
|
-
//
|
|
292
|
-
//
|
|
293
|
-
//
|
|
294
|
-
//
|
|
295
|
-
//
|
|
296
|
-
//
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
//
|
|
300
|
-
//
|
|
301
|
-
//
|
|
850
|
+
// {
|
|
851
|
+
// "data": [
|
|
852
|
+
// {
|
|
853
|
+
// "base_volume_24h": "78615593.81",
|
|
854
|
+
// "high_24h": "52756.97",
|
|
855
|
+
// "last_price": "52638.31",
|
|
856
|
+
// "low_24h": "50991.35",
|
|
857
|
+
// "open_24h": "51692.03",
|
|
858
|
+
// "s_t": 1630981727,
|
|
859
|
+
// "symbol": "BTC_USDT"
|
|
860
|
+
// }
|
|
861
|
+
// ],
|
|
862
|
+
// "table": "spot/ticker"
|
|
863
|
+
// }
|
|
864
|
+
// {
|
|
865
|
+
// "group":"futures/ticker",
|
|
866
|
+
// "data":{
|
|
867
|
+
// "symbol":"BTCUSDT",
|
|
868
|
+
// "volume_24":"117387.58",
|
|
869
|
+
// "fair_price":"146.24",
|
|
870
|
+
// "last_price":"146.24",
|
|
871
|
+
// "range":"147.17",
|
|
872
|
+
// "ask_price": "147.11",
|
|
873
|
+
// "ask_vol": "1",
|
|
874
|
+
// "bid_price": "142.11",
|
|
875
|
+
// "bid_vol": "1"
|
|
876
|
+
// }
|
|
877
|
+
// }
|
|
302
878
|
//
|
|
303
879
|
const table = this.safeString(message, 'table');
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
880
|
+
const isSpot = (table !== undefined);
|
|
881
|
+
const data = this.safeValue(message, 'data');
|
|
882
|
+
if (data === undefined) {
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
if (isSpot) {
|
|
886
|
+
for (let i = 0; i < data.length; i++) {
|
|
887
|
+
const ticker = this.parseTicker(data[i]);
|
|
888
|
+
const symbol = ticker['symbol'];
|
|
889
|
+
const marketId = this.safeString(ticker['info'], 'symbol');
|
|
890
|
+
const messageHash = table + ':' + marketId;
|
|
891
|
+
this.tickers[symbol] = ticker;
|
|
892
|
+
client.resolve(ticker, messageHash);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
else {
|
|
896
|
+
const ticker = this.parseWsSwapTicker(data);
|
|
897
|
+
const symbol = this.safeString(ticker, 'symbol');
|
|
310
898
|
this.tickers[symbol] = ticker;
|
|
311
|
-
client.resolve(ticker,
|
|
899
|
+
client.resolve(ticker, 'tickers');
|
|
900
|
+
this.resolvePromiseIfMessagehashMatches(client, 'tickers::', symbol, ticker);
|
|
312
901
|
}
|
|
313
902
|
return message;
|
|
314
903
|
}
|
|
904
|
+
parseWsSwapTicker(ticker, market = undefined) {
|
|
905
|
+
//
|
|
906
|
+
// {
|
|
907
|
+
// "symbol":"BTCUSDT",
|
|
908
|
+
// "volume_24":"117387.58",
|
|
909
|
+
// "fair_price":"146.24",
|
|
910
|
+
// "last_price":"146.24",
|
|
911
|
+
// "range":"147.17",
|
|
912
|
+
// "ask_price": "147.11",
|
|
913
|
+
// "ask_vol": "1",
|
|
914
|
+
// "bid_price": "142.11",
|
|
915
|
+
// "bid_vol": "1"
|
|
916
|
+
// }
|
|
917
|
+
const marketId = this.safeString(ticker, 'symbol');
|
|
918
|
+
return this.safeTicker({
|
|
919
|
+
'symbol': this.safeSymbol(marketId, market, '', 'swap'),
|
|
920
|
+
'timestamp': undefined,
|
|
921
|
+
'datetime': undefined,
|
|
922
|
+
'high': undefined,
|
|
923
|
+
'low': undefined,
|
|
924
|
+
'bid': this.safeString(ticker, 'bid_price'),
|
|
925
|
+
'bidVolume': this.safeString(ticker, 'bid_vol'),
|
|
926
|
+
'ask': this.safeString(ticker, 'ask_price'),
|
|
927
|
+
'askVolume': this.safeString(ticker, 'ask_vol'),
|
|
928
|
+
'vwap': undefined,
|
|
929
|
+
'open': undefined,
|
|
930
|
+
'close': undefined,
|
|
931
|
+
'last': this.safeString(ticker, 'last_price'),
|
|
932
|
+
'previousClose': undefined,
|
|
933
|
+
'change': undefined,
|
|
934
|
+
'percentage': undefined,
|
|
935
|
+
'average': this.safeString(ticker, 'fair_price'),
|
|
936
|
+
'baseVolume': undefined,
|
|
937
|
+
'quoteVolume': this.safeString(ticker, 'volume_24'),
|
|
938
|
+
'info': ticker,
|
|
939
|
+
}, market);
|
|
940
|
+
}
|
|
315
941
|
async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
|
316
942
|
/**
|
|
317
943
|
* @method
|
|
318
944
|
* @name bitmart#watchOHLCV
|
|
945
|
+
* @see https://developer-pro.bitmart.com/en/spot/#public-kline-channel
|
|
946
|
+
* @see https://developer-pro.bitmart.com/en/futures/#public-klinebin-channel
|
|
319
947
|
* @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
320
948
|
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
321
949
|
* @param {string} timeframe the length of time each candle represents
|
|
@@ -326,10 +954,19 @@ class bitmart extends bitmart$1 {
|
|
|
326
954
|
*/
|
|
327
955
|
await this.loadMarkets();
|
|
328
956
|
symbol = this.symbol(symbol);
|
|
957
|
+
const market = this.market(symbol);
|
|
958
|
+
let type = 'spot';
|
|
959
|
+
[type, params] = this.handleMarketTypeAndParams('watchOrderBook', market, params);
|
|
329
960
|
const timeframes = this.safeValue(this.options, 'timeframes', {});
|
|
330
961
|
const interval = this.safeString(timeframes, timeframe);
|
|
331
|
-
|
|
332
|
-
|
|
962
|
+
let name = undefined;
|
|
963
|
+
if (type === 'spot') {
|
|
964
|
+
name = 'kline' + interval;
|
|
965
|
+
}
|
|
966
|
+
else {
|
|
967
|
+
name = 'klineBin' + interval;
|
|
968
|
+
}
|
|
969
|
+
const ohlcv = await this.subscribe(name, symbol, type, params);
|
|
333
970
|
if (this.newUpdates) {
|
|
334
971
|
limit = ohlcv.getLimit(symbol, limit);
|
|
335
972
|
}
|
|
@@ -337,40 +974,82 @@ class bitmart extends bitmart$1 {
|
|
|
337
974
|
}
|
|
338
975
|
handleOHLCV(client, message) {
|
|
339
976
|
//
|
|
340
|
-
//
|
|
341
|
-
//
|
|
342
|
-
//
|
|
343
|
-
//
|
|
344
|
-
//
|
|
345
|
-
//
|
|
346
|
-
//
|
|
347
|
-
//
|
|
348
|
-
//
|
|
349
|
-
//
|
|
350
|
-
//
|
|
351
|
-
//
|
|
352
|
-
//
|
|
353
|
-
//
|
|
354
|
-
//
|
|
355
|
-
//
|
|
977
|
+
// {
|
|
978
|
+
// "data": [
|
|
979
|
+
// {
|
|
980
|
+
// "candle": [
|
|
981
|
+
// 1631056350,
|
|
982
|
+
// "46532.83",
|
|
983
|
+
// "46555.71",
|
|
984
|
+
// "46511.41",
|
|
985
|
+
// "46555.71",
|
|
986
|
+
// "0.25"
|
|
987
|
+
// ],
|
|
988
|
+
// "symbol": "BTC_USDT"
|
|
989
|
+
// }
|
|
990
|
+
// ],
|
|
991
|
+
// "table": "spot/kline1m"
|
|
992
|
+
// }
|
|
993
|
+
// swap
|
|
994
|
+
// {
|
|
995
|
+
// "group":"futures/klineBin1m:BTCUSDT",
|
|
996
|
+
// "data":{
|
|
997
|
+
// "symbol":"BTCUSDT",
|
|
998
|
+
// "items":[
|
|
999
|
+
// {
|
|
1000
|
+
// "o":"39635.8",
|
|
1001
|
+
// "h":"39636",
|
|
1002
|
+
// "l":"39614.4",
|
|
1003
|
+
// "c":"39629.7",
|
|
1004
|
+
// "v":"31852",
|
|
1005
|
+
// "ts":1701617761
|
|
1006
|
+
// }
|
|
1007
|
+
// ]
|
|
1008
|
+
// }
|
|
1009
|
+
// }
|
|
356
1010
|
//
|
|
357
|
-
const
|
|
358
|
-
const
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
1011
|
+
const channel = this.safeString2(message, 'table', 'group');
|
|
1012
|
+
const isSpot = (channel.indexOf('spot') >= 0);
|
|
1013
|
+
const data = this.safeValue(message, 'data');
|
|
1014
|
+
if (data === undefined) {
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
const parts = channel.split('/');
|
|
1018
|
+
const part1 = this.safeString(parts, 1, '');
|
|
1019
|
+
let interval = part1.replace('kline', '');
|
|
1020
|
+
interval = interval.replace('Bin', '');
|
|
1021
|
+
const intervalParts = interval.split(':');
|
|
1022
|
+
interval = this.safeString(intervalParts, 0);
|
|
362
1023
|
// use a reverse lookup in a static map instead
|
|
363
1024
|
const timeframes = this.safeValue(this.options, 'timeframes', {});
|
|
364
1025
|
const timeframe = this.findTimeframe(interval, timeframes);
|
|
365
1026
|
const duration = this.parseTimeframe(timeframe);
|
|
366
1027
|
const durationInMs = duration * 1000;
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
1028
|
+
if (isSpot) {
|
|
1029
|
+
for (let i = 0; i < data.length; i++) {
|
|
1030
|
+
const marketId = this.safeString(data[i], 'symbol');
|
|
1031
|
+
const market = this.safeMarket(marketId);
|
|
1032
|
+
const symbol = market['symbol'];
|
|
1033
|
+
const rawOHLCV = this.safeValue(data[i], 'candle');
|
|
1034
|
+
const parsed = this.parseOHLCV(rawOHLCV, market);
|
|
1035
|
+
parsed[0] = this.parseToInt(parsed[0] / durationInMs) * durationInMs;
|
|
1036
|
+
this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
|
|
1037
|
+
let stored = this.safeValue(this.ohlcvs[symbol], timeframe);
|
|
1038
|
+
if (stored === undefined) {
|
|
1039
|
+
const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
|
|
1040
|
+
stored = new Cache.ArrayCacheByTimestamp(limit);
|
|
1041
|
+
this.ohlcvs[symbol][timeframe] = stored;
|
|
1042
|
+
}
|
|
1043
|
+
stored.append(parsed);
|
|
1044
|
+
const messageHash = channel + ':' + marketId;
|
|
1045
|
+
client.resolve(stored, messageHash);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
else {
|
|
1049
|
+
const marketId = this.safeString(data, 'symbol');
|
|
1050
|
+
const market = this.safeMarket(marketId, undefined, '', 'swap');
|
|
371
1051
|
const symbol = market['symbol'];
|
|
372
|
-
const
|
|
373
|
-
parsed[0] = this.parseToInt(parsed[0] / durationInMs) * durationInMs;
|
|
1052
|
+
const items = this.safeValue(data, 'items', []);
|
|
374
1053
|
this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
|
|
375
1054
|
let stored = this.safeValue(this.ohlcvs[symbol], timeframe);
|
|
376
1055
|
if (stored === undefined) {
|
|
@@ -378,24 +1057,34 @@ class bitmart extends bitmart$1 {
|
|
|
378
1057
|
stored = new Cache.ArrayCacheByTimestamp(limit);
|
|
379
1058
|
this.ohlcvs[symbol][timeframe] = stored;
|
|
380
1059
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
1060
|
+
for (let i = 0; i < items.length; i++) {
|
|
1061
|
+
const candle = items[i];
|
|
1062
|
+
const parsed = this.parseOHLCV(candle, market);
|
|
1063
|
+
stored.append(parsed);
|
|
1064
|
+
}
|
|
1065
|
+
client.resolve(stored, channel);
|
|
384
1066
|
}
|
|
385
1067
|
}
|
|
386
1068
|
async watchOrderBook(symbol, limit = undefined, params = {}) {
|
|
387
1069
|
/**
|
|
388
1070
|
* @method
|
|
389
1071
|
* @name bitmart#watchOrderBook
|
|
1072
|
+
* @see https://developer-pro.bitmart.com/en/spot/#public-depth-all-channel
|
|
1073
|
+
* @see https://developer-pro.bitmart.com/en/futures/#public-depth-channel
|
|
390
1074
|
* @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
391
1075
|
* @param {string} symbol unified symbol of the market to fetch the order book for
|
|
392
1076
|
* @param {int} [limit] the maximum amount of order book entries to return
|
|
393
1077
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
394
1078
|
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
395
1079
|
*/
|
|
1080
|
+
await this.loadMarkets();
|
|
396
1081
|
const options = this.safeValue(this.options, 'watchOrderBook', {});
|
|
397
1082
|
const depth = this.safeString(options, 'depth', 'depth50');
|
|
398
|
-
|
|
1083
|
+
symbol = this.symbol(symbol);
|
|
1084
|
+
const market = this.market(symbol);
|
|
1085
|
+
let type = 'spot';
|
|
1086
|
+
[type, params] = this.handleMarketTypeAndParams('watchOrderBook', market, params);
|
|
1087
|
+
const orderbook = await this.subscribe(depth, symbol, type, params);
|
|
399
1088
|
return orderbook.limit();
|
|
400
1089
|
}
|
|
401
1090
|
handleDelta(bookside, delta) {
|
|
@@ -443,22 +1132,19 @@ class bitmart extends bitmart$1 {
|
|
|
443
1132
|
}
|
|
444
1133
|
handleOrderBook(client, message) {
|
|
445
1134
|
//
|
|
1135
|
+
// spot
|
|
446
1136
|
// {
|
|
447
1137
|
// "data": [
|
|
448
1138
|
// {
|
|
449
1139
|
// "asks": [
|
|
450
1140
|
// [ '46828.38', "0.21847" ],
|
|
451
1141
|
// [ '46830.68', "0.08232" ],
|
|
452
|
-
//
|
|
453
|
-
// [ '46837.82', "0.02028" ],
|
|
454
|
-
// [ '46839.43', "0.15068" ]
|
|
1142
|
+
// ...
|
|
455
1143
|
// ],
|
|
456
1144
|
// "bids": [
|
|
457
1145
|
// [ '46820.78', "0.00444" ],
|
|
458
1146
|
// [ '46814.33', "0.00234" ],
|
|
459
|
-
//
|
|
460
|
-
// [ '46808.14', "0.00217" ],
|
|
461
|
-
// [ '46808.04', "0.00013" ]
|
|
1147
|
+
// ...
|
|
462
1148
|
// ],
|
|
463
1149
|
// "ms_t": 1631044962431,
|
|
464
1150
|
// "symbol": "BTC_USDT"
|
|
@@ -466,32 +1152,99 @@ class bitmart extends bitmart$1 {
|
|
|
466
1152
|
// ],
|
|
467
1153
|
// "table": "spot/depth5"
|
|
468
1154
|
// }
|
|
1155
|
+
// swap
|
|
1156
|
+
// {
|
|
1157
|
+
// "group":"futures/depth50:BTCUSDT",
|
|
1158
|
+
// "data":{
|
|
1159
|
+
// "symbol":"BTCUSDT",
|
|
1160
|
+
// "way":1,
|
|
1161
|
+
// "depths":[
|
|
1162
|
+
// {
|
|
1163
|
+
// "price":"39509.8",
|
|
1164
|
+
// "vol":"2379"
|
|
1165
|
+
// },
|
|
1166
|
+
// {
|
|
1167
|
+
// "price":"39509.6",
|
|
1168
|
+
// "vol":"6815"
|
|
1169
|
+
// },
|
|
1170
|
+
// ...
|
|
1171
|
+
// ],
|
|
1172
|
+
// "ms_t":1701566021194
|
|
1173
|
+
// }
|
|
1174
|
+
// }
|
|
469
1175
|
//
|
|
470
|
-
const data = this.safeValue(message, 'data'
|
|
471
|
-
|
|
1176
|
+
const data = this.safeValue(message, 'data');
|
|
1177
|
+
if (data === undefined) {
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
const depths = this.safeValue(data, 'depths');
|
|
1181
|
+
const isSpot = (depths === undefined);
|
|
1182
|
+
const table = this.safeString2(message, 'table', 'group');
|
|
472
1183
|
const parts = table.split('/');
|
|
473
1184
|
const lastPart = this.safeString(parts, 1);
|
|
474
|
-
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
1185
|
+
let limitString = lastPart.replace('depth', '');
|
|
1186
|
+
const dotsIndex = limitString.indexOf(':');
|
|
1187
|
+
limitString = limitString.slice(0, dotsIndex);
|
|
1188
|
+
const limit = this.parseToInt(limitString);
|
|
1189
|
+
if (isSpot) {
|
|
1190
|
+
for (let i = 0; i < data.length; i++) {
|
|
1191
|
+
const update = data[i];
|
|
1192
|
+
const marketId = this.safeString(update, 'symbol');
|
|
1193
|
+
const symbol = this.safeSymbol(marketId);
|
|
1194
|
+
let orderbook = this.safeValue(this.orderbooks, symbol);
|
|
1195
|
+
if (orderbook === undefined) {
|
|
1196
|
+
orderbook = this.orderBook({}, limit);
|
|
1197
|
+
orderbook['symbol'] = symbol;
|
|
1198
|
+
this.orderbooks[symbol] = orderbook;
|
|
1199
|
+
}
|
|
1200
|
+
orderbook.reset({});
|
|
1201
|
+
this.handleOrderBookMessage(client, update, orderbook);
|
|
1202
|
+
const timestamp = this.safeInteger(update, 'ms_t');
|
|
1203
|
+
orderbook['timestamp'] = timestamp;
|
|
1204
|
+
orderbook['datetime'] = this.iso8601(timestamp);
|
|
1205
|
+
const messageHash = table + ':' + marketId;
|
|
1206
|
+
client.resolve(orderbook, messageHash);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
else {
|
|
1210
|
+
const marketId = this.safeString(data, 'symbol');
|
|
479
1211
|
const symbol = this.safeSymbol(marketId);
|
|
480
1212
|
let orderbook = this.safeValue(this.orderbooks, symbol);
|
|
481
1213
|
if (orderbook === undefined) {
|
|
482
1214
|
orderbook = this.orderBook({}, limit);
|
|
1215
|
+
orderbook['symbol'] = symbol;
|
|
483
1216
|
this.orderbooks[symbol] = orderbook;
|
|
484
1217
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
1218
|
+
const way = this.safeNumber(data, 'way');
|
|
1219
|
+
const side = (way === 1) ? 'bids' : 'asks';
|
|
1220
|
+
if (way === 1) {
|
|
1221
|
+
orderbook[side] = new OrderBookSide.Bids([], limit);
|
|
1222
|
+
}
|
|
1223
|
+
else {
|
|
1224
|
+
orderbook[side] = new OrderBookSide.Asks([], limit);
|
|
1225
|
+
}
|
|
1226
|
+
for (let i = 0; i < depths.length; i++) {
|
|
1227
|
+
const depth = depths[i];
|
|
1228
|
+
const price = this.safeNumber(depth, 'price');
|
|
1229
|
+
const amount = this.safeNumber(depth, 'vol');
|
|
1230
|
+
const orderbookSide = this.safeValue(orderbook, side);
|
|
1231
|
+
orderbookSide.store(price, amount);
|
|
1232
|
+
}
|
|
1233
|
+
const bidsLength = orderbook['bids'].length;
|
|
1234
|
+
const asksLength = orderbook['asks'].length;
|
|
1235
|
+
if ((bidsLength === 0) || (asksLength === 0)) {
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1238
|
+
const timestamp = this.safeInteger(data, 'ms_t');
|
|
1239
|
+
orderbook['timestamp'] = timestamp;
|
|
1240
|
+
orderbook['datetime'] = this.iso8601(timestamp);
|
|
1241
|
+
const messageHash = table;
|
|
488
1242
|
client.resolve(orderbook, messageHash);
|
|
489
1243
|
}
|
|
490
|
-
return message;
|
|
491
1244
|
}
|
|
492
|
-
async authenticate(params = {}) {
|
|
1245
|
+
async authenticate(type, params = {}) {
|
|
493
1246
|
this.checkRequiredCredentials();
|
|
494
|
-
const url = this.implodeHostname(this.urls['api']['ws']['private']);
|
|
1247
|
+
const url = this.implodeHostname(this.urls['api']['ws'][type]['private']);
|
|
495
1248
|
const messageHash = 'authenticated';
|
|
496
1249
|
const client = this.client(url);
|
|
497
1250
|
const future = client.future(messageHash);
|
|
@@ -502,15 +1255,28 @@ class bitmart extends bitmart$1 {
|
|
|
502
1255
|
const path = 'bitmart.WebSocket';
|
|
503
1256
|
const auth = timestamp + '#' + memo + '#' + path;
|
|
504
1257
|
const signature = this.hmac(this.encode(auth), this.encode(this.secret), sha256.sha256);
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
1258
|
+
let request = undefined;
|
|
1259
|
+
if (type === 'spot') {
|
|
1260
|
+
request = {
|
|
1261
|
+
'op': 'login',
|
|
1262
|
+
'args': [
|
|
1263
|
+
this.apiKey,
|
|
1264
|
+
timestamp,
|
|
1265
|
+
signature,
|
|
1266
|
+
],
|
|
1267
|
+
};
|
|
1268
|
+
}
|
|
1269
|
+
else {
|
|
1270
|
+
request = {
|
|
1271
|
+
'action': 'access',
|
|
1272
|
+
'args': [
|
|
1273
|
+
this.apiKey,
|
|
1274
|
+
timestamp,
|
|
1275
|
+
signature,
|
|
1276
|
+
'web',
|
|
1277
|
+
],
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
514
1280
|
const message = this.extend(request, params);
|
|
515
1281
|
this.watch(url, messageHash, message, messageHash);
|
|
516
1282
|
}
|
|
@@ -518,13 +1284,16 @@ class bitmart extends bitmart$1 {
|
|
|
518
1284
|
}
|
|
519
1285
|
handleSubscriptionStatus(client, message) {
|
|
520
1286
|
//
|
|
521
|
-
//
|
|
1287
|
+
// {"event":"subscribe","channel":"spot/depth:BTC-USDT"}
|
|
522
1288
|
//
|
|
523
1289
|
return message;
|
|
524
1290
|
}
|
|
525
1291
|
handleAuthenticate(client, message) {
|
|
526
1292
|
//
|
|
527
|
-
//
|
|
1293
|
+
// spot
|
|
1294
|
+
// { event: "login" }
|
|
1295
|
+
// swap
|
|
1296
|
+
// { action: 'access', success: true }
|
|
528
1297
|
//
|
|
529
1298
|
const messageHash = 'authenticated';
|
|
530
1299
|
const future = this.safeValue(client.futures, messageHash);
|
|
@@ -532,29 +1301,41 @@ class bitmart extends bitmart$1 {
|
|
|
532
1301
|
}
|
|
533
1302
|
handleErrorMessage(client, message) {
|
|
534
1303
|
//
|
|
535
|
-
//
|
|
536
|
-
//
|
|
1304
|
+
// { event: "error", message: "Invalid sign", errorCode: 30013 }
|
|
1305
|
+
// {"event":"error","message":"Unrecognized request: {\"event\":\"subscribe\",\"channel\":\"spot/depth:BTC-USDT\"}","errorCode":30039}
|
|
1306
|
+
// {
|
|
1307
|
+
// action: '',
|
|
1308
|
+
// group: 'futures/trade:BTCUSDT',
|
|
1309
|
+
// success: false,
|
|
1310
|
+
// request: { action: '', args: [ 'futures/trade:BTCUSDT' ] },
|
|
1311
|
+
// error: 'Invalid action [] for group [futures/trade:BTCUSDT]'
|
|
1312
|
+
// }
|
|
537
1313
|
//
|
|
538
1314
|
const errorCode = this.safeString(message, 'errorCode');
|
|
1315
|
+
const error = this.safeString(message, 'error');
|
|
539
1316
|
try {
|
|
540
|
-
if (errorCode !== undefined) {
|
|
1317
|
+
if (errorCode !== undefined || error !== undefined) {
|
|
541
1318
|
const feedback = this.id + ' ' + this.json(message);
|
|
542
1319
|
this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
|
|
543
|
-
const messageString = this.safeValue(message, 'message');
|
|
544
|
-
|
|
545
|
-
|
|
1320
|
+
const messageString = this.safeValue(message, 'message', error);
|
|
1321
|
+
this.throwBroadlyMatchedException(this.exceptions['broad'], messageString, feedback);
|
|
1322
|
+
const action = this.safeString(message, 'action');
|
|
1323
|
+
if (action === 'access') {
|
|
1324
|
+
throw new errors.AuthenticationError(feedback);
|
|
546
1325
|
}
|
|
1326
|
+
throw new errors.ExchangeError(feedback);
|
|
547
1327
|
}
|
|
548
1328
|
return false;
|
|
549
1329
|
}
|
|
550
1330
|
catch (e) {
|
|
551
|
-
if (e instanceof errors.AuthenticationError) {
|
|
1331
|
+
if ((e instanceof errors.AuthenticationError)) {
|
|
552
1332
|
const messageHash = 'authenticated';
|
|
553
1333
|
client.reject(e, messageHash);
|
|
554
1334
|
if (messageHash in client.subscriptions) {
|
|
555
1335
|
delete client.subscriptions[messageHash];
|
|
556
1336
|
}
|
|
557
1337
|
}
|
|
1338
|
+
client.reject(e);
|
|
558
1339
|
return true;
|
|
559
1340
|
}
|
|
560
1341
|
}
|
|
@@ -587,14 +1368,14 @@ class bitmart extends bitmart$1 {
|
|
|
587
1368
|
//
|
|
588
1369
|
// { data: '', table: "spot/user/order" }
|
|
589
1370
|
//
|
|
590
|
-
const
|
|
591
|
-
if (
|
|
592
|
-
const event = this.
|
|
1371
|
+
const channel = this.safeString2(message, 'table', 'group');
|
|
1372
|
+
if (channel === undefined) {
|
|
1373
|
+
const event = this.safeString2(message, 'event', 'action');
|
|
593
1374
|
if (event !== undefined) {
|
|
594
1375
|
const methods = {
|
|
595
1376
|
// 'info': this.handleSystemStatus,
|
|
596
|
-
// 'book': 'handleOrderBook',
|
|
597
1377
|
'login': this.handleAuthenticate,
|
|
1378
|
+
'access': this.handleAuthenticate,
|
|
598
1379
|
'subscribe': this.handleSubscriptionStatus,
|
|
599
1380
|
};
|
|
600
1381
|
const method = this.safeValue(methods, event);
|
|
@@ -607,30 +1388,25 @@ class bitmart extends bitmart$1 {
|
|
|
607
1388
|
}
|
|
608
1389
|
}
|
|
609
1390
|
else {
|
|
610
|
-
const parts = table.split('/');
|
|
611
|
-
const name = this.safeString(parts, 1);
|
|
612
1391
|
const methods = {
|
|
613
|
-
'depth': this.handleOrderBook,
|
|
614
1392
|
'depth5': this.handleOrderBook,
|
|
615
1393
|
'depth20': this.handleOrderBook,
|
|
616
1394
|
'depth50': this.handleOrderBook,
|
|
617
1395
|
'ticker': this.handleTicker,
|
|
618
1396
|
'trade': this.handleTrade,
|
|
619
|
-
|
|
1397
|
+
'kline': this.handleOHLCV,
|
|
1398
|
+
'order': this.handleOrders,
|
|
1399
|
+
'position': this.handlePositions,
|
|
1400
|
+
'balance': this.handleBalance,
|
|
1401
|
+
'asset': this.handleBalance,
|
|
620
1402
|
};
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
}
|
|
629
|
-
if (method === undefined) {
|
|
630
|
-
return message;
|
|
631
|
-
}
|
|
632
|
-
else {
|
|
633
|
-
return method.call(this, client, message);
|
|
1403
|
+
const keys = Object.keys(methods);
|
|
1404
|
+
for (let i = 0; i < keys.length; i++) {
|
|
1405
|
+
const key = keys[i];
|
|
1406
|
+
if (channel.indexOf(key) >= 0) {
|
|
1407
|
+
const method = this.safeValue(methods, key);
|
|
1408
|
+
return method.call(this, client, message);
|
|
1409
|
+
}
|
|
634
1410
|
}
|
|
635
1411
|
}
|
|
636
1412
|
}
|