ccxt 4.5.48 → 4.5.49
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 +6 -5
- package/dist/ccxt.browser.min.js +10 -10
- package/dist/cjs/ccxt.js +6 -1
- package/dist/cjs/src/abstract/weex.js +11 -0
- package/dist/cjs/src/btcbox.js +1 -1
- package/dist/cjs/src/bullish.js +2 -1
- package/dist/cjs/src/kraken.js +1 -0
- package/dist/cjs/src/krakenfutures.js +10 -1
- package/dist/cjs/src/kucoin.js +5 -1
- package/dist/cjs/src/lighter.js +6 -3
- package/dist/cjs/src/mexc.js +7 -12
- package/dist/cjs/src/paradex.js +5 -2
- package/dist/cjs/src/pro/binance.js +1 -1
- package/dist/cjs/src/pro/cex.js +1 -1
- package/dist/cjs/src/pro/coinbase.js +1 -1
- package/dist/cjs/src/pro/lighter.js +338 -18
- package/dist/cjs/src/pro/weex.js +1906 -0
- package/dist/cjs/src/weex.js +3823 -0
- package/js/ccxt.d.ts +8 -2
- package/js/ccxt.js +6 -2
- package/js/src/abstract/weex.d.ts +83 -0
- package/js/src/abstract/weex.js +11 -0
- package/js/src/btcbox.js +1 -1
- package/js/src/bullish.js +2 -1
- package/js/src/kraken.js +1 -0
- package/js/src/krakenfutures.js +10 -1
- package/js/src/kucoin.d.ts +4 -0
- package/js/src/kucoin.js +5 -1
- package/js/src/lighter.d.ts +1 -0
- package/js/src/lighter.js +6 -3
- package/js/src/mexc.d.ts +2 -0
- package/js/src/mexc.js +7 -12
- package/js/src/paradex.js +5 -2
- package/js/src/pro/binance.js +1 -1
- package/js/src/pro/cex.js +1 -1
- package/js/src/pro/coinbase.js +1 -1
- package/js/src/pro/lighter.d.ts +37 -2
- package/js/src/pro/lighter.js +338 -18
- package/js/src/pro/weex.d.ts +330 -0
- package/js/src/pro/weex.js +1905 -0
- package/js/src/weex.d.ts +675 -0
- package/js/src/weex.js +3822 -0
- package/package.json +1 -1
|
@@ -0,0 +1,1906 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var weex$1 = require('../weex.js');
|
|
6
|
+
var errors = require('../base/errors.js');
|
|
7
|
+
var sha256 = require('../static_dependencies/noble-hashes/sha256.js');
|
|
8
|
+
var Cache = require('../base/ws/Cache.js');
|
|
9
|
+
|
|
10
|
+
// ----------------------------------------------------------------------------
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
class weex extends weex$1["default"] {
|
|
13
|
+
describe() {
|
|
14
|
+
return this.deepExtend(super.describe(), {
|
|
15
|
+
'has': {
|
|
16
|
+
'watchBalance': true,
|
|
17
|
+
'watchBidsAsks': true,
|
|
18
|
+
'watchMyTrades': true,
|
|
19
|
+
'watchOHLCV': true,
|
|
20
|
+
'watchOHLCVForSymbols': true,
|
|
21
|
+
'watchOrderBook': false,
|
|
22
|
+
'watchOrderBookForSymbols': false,
|
|
23
|
+
'watchOrders': true,
|
|
24
|
+
'watchPositions': true,
|
|
25
|
+
'watchTicker': true,
|
|
26
|
+
'watchTickers': true,
|
|
27
|
+
'watchTrades': true,
|
|
28
|
+
'watchTradesForSymbols': true,
|
|
29
|
+
'unWatchBidsAsks': true,
|
|
30
|
+
'unWatchMyTrades': true,
|
|
31
|
+
'unWatchOHLCV': true,
|
|
32
|
+
'unWatchOHLCVForSymbols': true,
|
|
33
|
+
'unWatchOrderBook': false,
|
|
34
|
+
'unWatchOrderBookForSymbols': false,
|
|
35
|
+
'unWatchOrders': true,
|
|
36
|
+
'unWatchPositions': true,
|
|
37
|
+
'unWatchTicker': true,
|
|
38
|
+
'unWatchTickers': true,
|
|
39
|
+
'unWatchTrades': true,
|
|
40
|
+
'unWatchTradesForSymbols': true,
|
|
41
|
+
},
|
|
42
|
+
'urls': {
|
|
43
|
+
'api': {
|
|
44
|
+
'ws': {
|
|
45
|
+
'spot': 'wss://ws-spot.weex.com/v3/ws',
|
|
46
|
+
'contract': 'wss://ws-contract.weex.com/v3/ws',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
'options': {
|
|
51
|
+
'ws': {
|
|
52
|
+
'options': {
|
|
53
|
+
'headers': {
|
|
54
|
+
'User-Agent': 'ccxt', // the exchange requires headers
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
'watchOHLCV': {
|
|
59
|
+
'priceType': 'LAST_PRICE', // or 'MARK_PRICE' for swap markets
|
|
60
|
+
},
|
|
61
|
+
'watchOHLCVForSymbols': {
|
|
62
|
+
'priceType': 'LAST_PRICE', // or 'MARK_PRICE' for swap markets
|
|
63
|
+
},
|
|
64
|
+
'watchOrderBook': {
|
|
65
|
+
'depth': '200', // or '15'
|
|
66
|
+
},
|
|
67
|
+
'watchOrderBookForSymbols': {
|
|
68
|
+
'depth': '200', // or '15'
|
|
69
|
+
},
|
|
70
|
+
'watchBalance': {
|
|
71
|
+
'fetchBalanceSnapshot': true,
|
|
72
|
+
'awaitBalanceSnapshot': true,
|
|
73
|
+
},
|
|
74
|
+
'watchPositions': {
|
|
75
|
+
'fetchPositionsSnapshot': true,
|
|
76
|
+
'awaitPositionsSnapshot': true,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
'streaming': {},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
requestId() {
|
|
83
|
+
this.lockId();
|
|
84
|
+
const requestId = this.sum(this.safeInteger(this.options, 'requestId', 0), 1);
|
|
85
|
+
this.options['requestId'] = requestId;
|
|
86
|
+
this.unlockId();
|
|
87
|
+
return this.numberToString(requestId);
|
|
88
|
+
}
|
|
89
|
+
async subscribePublic(messageHashes, channels, isContract = false, params = {}, subscription = {}) {
|
|
90
|
+
const id = this.requestId();
|
|
91
|
+
let method = 'SUBSCRIBE';
|
|
92
|
+
const unsubscribe = this.safeBool(subscription, 'unsubscribe', false);
|
|
93
|
+
if (unsubscribe) {
|
|
94
|
+
method = 'UNSUBSCRIBE';
|
|
95
|
+
}
|
|
96
|
+
const message = {
|
|
97
|
+
'id': id,
|
|
98
|
+
'method': method,
|
|
99
|
+
'params': channels,
|
|
100
|
+
};
|
|
101
|
+
subscription = this.extend(subscription, { 'id': id });
|
|
102
|
+
const type = isContract ? 'contract' : 'spot';
|
|
103
|
+
const url = this.urls['api']['ws'][type] + '/public';
|
|
104
|
+
return await this.watchMultiple(url, messageHashes, this.deepExtend(message, params), messageHashes, subscription);
|
|
105
|
+
}
|
|
106
|
+
async subscribePrivate(messageHash, subscribeHash, channel, isContract = false, params = {}, subscription = {}) {
|
|
107
|
+
const type = isContract ? 'contract' : 'spot';
|
|
108
|
+
const url = this.urls['api']['ws'][type] + '/private';
|
|
109
|
+
this.authenticate(url);
|
|
110
|
+
let method = 'SUBSCRIBE';
|
|
111
|
+
const unsubscribe = this.safeBool(subscription, 'unsubscribe', false);
|
|
112
|
+
if (unsubscribe) {
|
|
113
|
+
method = 'UNSUBSCRIBE';
|
|
114
|
+
}
|
|
115
|
+
const id = this.requestId();
|
|
116
|
+
const message = {
|
|
117
|
+
'id': id,
|
|
118
|
+
'method': method,
|
|
119
|
+
'params': [channel],
|
|
120
|
+
};
|
|
121
|
+
subscription = this.extend(subscription, { 'id': id });
|
|
122
|
+
return await this.watch(url, messageHash, this.deepExtend(message, params), subscribeHash, subscription);
|
|
123
|
+
}
|
|
124
|
+
authenticate(url) {
|
|
125
|
+
this.checkRequiredCredentials();
|
|
126
|
+
if ((this.clients !== undefined) && (url in this.clients)) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const timestamp = this.nonce();
|
|
130
|
+
const payload = timestamp.toString() + '/v3/ws/private';
|
|
131
|
+
const signature = this.hmac(this.encode(payload), this.encode(this.secret), sha256.sha256, 'base64');
|
|
132
|
+
const originalHeaders = this.options['ws']['options']['headers'];
|
|
133
|
+
const userAgent = this.safeString(originalHeaders, 'User-Agent', 'ccxt');
|
|
134
|
+
const extendedOptions = {
|
|
135
|
+
'ws': {
|
|
136
|
+
'options': {
|
|
137
|
+
'headers': {
|
|
138
|
+
'User-Agent': userAgent,
|
|
139
|
+
'ACCESS-KEY': this.apiKey,
|
|
140
|
+
'ACCESS-SIGN': signature,
|
|
141
|
+
'ACCESS-PASSPHRASE': this.password,
|
|
142
|
+
'ACCESS-TIMESTAMP': this.numberToString(timestamp),
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
this.extendExchangeOptions(extendedOptions);
|
|
148
|
+
// instantiate client
|
|
149
|
+
this.client(url);
|
|
150
|
+
// return headers to original state
|
|
151
|
+
const defaultOptions = {
|
|
152
|
+
'ws': {
|
|
153
|
+
'options': {
|
|
154
|
+
'headers': {
|
|
155
|
+
'User-Agent': userAgent,
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
this.extendExchangeOptions(defaultOptions);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* @method
|
|
164
|
+
* @name weex#watchTicker
|
|
165
|
+
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
166
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Tickers-Channel
|
|
167
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Tickers-Channel
|
|
168
|
+
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
169
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
170
|
+
* @param {string} [params.name] stream to use can be ticker or miniTicker
|
|
171
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
|
|
172
|
+
*/
|
|
173
|
+
async watchTicker(symbol, params = {}) {
|
|
174
|
+
await this.loadMarkets();
|
|
175
|
+
symbol = this.symbol(symbol);
|
|
176
|
+
const tickers = await this.watchTickers([symbol], params);
|
|
177
|
+
return tickers[symbol];
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* @method
|
|
181
|
+
* @name weex#watchTickers
|
|
182
|
+
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
|
183
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Tickers-Channel
|
|
184
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Tickers-Channel
|
|
185
|
+
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
|
|
186
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
187
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
|
|
188
|
+
*/
|
|
189
|
+
async watchTickers(symbols = undefined, params = {}) {
|
|
190
|
+
await this.loadMarkets();
|
|
191
|
+
symbols = this.marketSymbols(symbols, undefined, false, true);
|
|
192
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
193
|
+
const isContract = firstMarket['contract'];
|
|
194
|
+
const topic = 'ticker';
|
|
195
|
+
const messageHashes = [];
|
|
196
|
+
const channels = [];
|
|
197
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
198
|
+
const symbol = symbols[i];
|
|
199
|
+
const market = this.market(symbol);
|
|
200
|
+
const channelName = market['id'] + '@' + topic;
|
|
201
|
+
const messageHash = topic + '::' + symbol;
|
|
202
|
+
messageHashes.push(messageHash);
|
|
203
|
+
channels.push(channelName);
|
|
204
|
+
}
|
|
205
|
+
const newTicker = await this.subscribePublic(messageHashes, channels, isContract, params);
|
|
206
|
+
if (this.newUpdates) {
|
|
207
|
+
const result = {};
|
|
208
|
+
result[newTicker['symbol']] = newTicker;
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
return this.filterByArray(this.tickers, 'symbol', symbols);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* @method
|
|
215
|
+
* @name weex#unWatchTicker
|
|
216
|
+
* @description unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
|
217
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Tickers-Channel
|
|
218
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Tickers-Channel
|
|
219
|
+
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
220
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
221
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
|
|
222
|
+
*/
|
|
223
|
+
async unWatchTicker(symbol, params = {}) {
|
|
224
|
+
return await this.unWatchTickers([symbol], params);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* @method
|
|
228
|
+
* @name weex#unWatchTickers
|
|
229
|
+
* @description unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
|
230
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Tickers-Channel
|
|
231
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Tickers-Channel
|
|
232
|
+
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
|
|
233
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
234
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
|
|
235
|
+
*/
|
|
236
|
+
async unWatchTickers(symbols = undefined, params = {}) {
|
|
237
|
+
await this.loadMarkets();
|
|
238
|
+
symbols = this.marketSymbols(symbols, undefined, false, true);
|
|
239
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
240
|
+
const isContract = firstMarket['contract'];
|
|
241
|
+
const topic = 'ticker';
|
|
242
|
+
const subHashes = [];
|
|
243
|
+
const channels = [];
|
|
244
|
+
const unSubHashes = [];
|
|
245
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
246
|
+
const symbol = symbols[i];
|
|
247
|
+
const market = this.market(symbol);
|
|
248
|
+
const channelName = market['id'] + '@' + topic;
|
|
249
|
+
const messageHash = topic + '::' + symbol;
|
|
250
|
+
const unSubMessageHash = 'unsubscribe::' + messageHash;
|
|
251
|
+
subHashes.push(messageHash);
|
|
252
|
+
channels.push(channelName);
|
|
253
|
+
unSubHashes.push(unSubMessageHash);
|
|
254
|
+
}
|
|
255
|
+
const subscription = {
|
|
256
|
+
'unsubscribe': true,
|
|
257
|
+
'symbols': symbols,
|
|
258
|
+
'messageHashes': unSubHashes,
|
|
259
|
+
'subMessageHashes': subHashes,
|
|
260
|
+
'topic': topic,
|
|
261
|
+
};
|
|
262
|
+
return await this.subscribePublic(unSubHashes, channels, isContract, params, subscription);
|
|
263
|
+
}
|
|
264
|
+
handleTicker(client, message) {
|
|
265
|
+
//
|
|
266
|
+
// {
|
|
267
|
+
// "e": "ticker",
|
|
268
|
+
// "E": 1776081628845,
|
|
269
|
+
// "s": "ETHUSDT",
|
|
270
|
+
// "d": [
|
|
271
|
+
// {
|
|
272
|
+
// "p": "-18.93",
|
|
273
|
+
// "P": "-0.008592",
|
|
274
|
+
// "w": "2192.40298388",
|
|
275
|
+
// "c": "2184.20",
|
|
276
|
+
// "o": "2203.13",
|
|
277
|
+
// "h": "2217.34",
|
|
278
|
+
// "l": "2173.32",
|
|
279
|
+
// "v": "359395.800",
|
|
280
|
+
// "q": "787940424.31399",
|
|
281
|
+
// "O": 1775995200000,
|
|
282
|
+
// "C": 1776081600000,
|
|
283
|
+
// "n": 485169,
|
|
284
|
+
// "m": "2184.28",
|
|
285
|
+
// "i": "2185.2025"
|
|
286
|
+
// }
|
|
287
|
+
// ]
|
|
288
|
+
// }
|
|
289
|
+
//
|
|
290
|
+
const market = this.getMarketFromClientAndMessage(client, message);
|
|
291
|
+
const tickers = this.safeList(message, 'd', []);
|
|
292
|
+
const data = this.safeDict(tickers, 0, {});
|
|
293
|
+
const ticker = this.parseWsTicker(data, market);
|
|
294
|
+
const symbol = market['symbol'];
|
|
295
|
+
const messageHash = 'ticker::' + symbol;
|
|
296
|
+
this.tickers[symbol] = ticker;
|
|
297
|
+
client.resolve(this.tickers[symbol], messageHash);
|
|
298
|
+
}
|
|
299
|
+
parseWsTicker(ticker, market = undefined) {
|
|
300
|
+
//
|
|
301
|
+
// {
|
|
302
|
+
// "p": "-18.93",
|
|
303
|
+
// "P": "-0.008592",
|
|
304
|
+
// "w": "2192.40298388",
|
|
305
|
+
// "c": "2184.20",
|
|
306
|
+
// "o": "2203.13",
|
|
307
|
+
// "h": "2217.34",
|
|
308
|
+
// "l": "2173.32",
|
|
309
|
+
// "v": "359395.800",
|
|
310
|
+
// "q": "787940424.31399",
|
|
311
|
+
// "O": 1775995200000,
|
|
312
|
+
// "C": 1776081600000,
|
|
313
|
+
// "n": 485169,
|
|
314
|
+
// "m": "2184.28",
|
|
315
|
+
// "i": "2185.2025"
|
|
316
|
+
// }
|
|
317
|
+
//
|
|
318
|
+
const timestamp = this.safeInteger(ticker, 'C');
|
|
319
|
+
const close = this.safeString(ticker, 'c');
|
|
320
|
+
return this.safeTicker({
|
|
321
|
+
'symbol': market['symbol'],
|
|
322
|
+
'timestamp': timestamp,
|
|
323
|
+
'datetime': this.iso8601(timestamp),
|
|
324
|
+
'high': this.safeString(ticker, 'h'),
|
|
325
|
+
'low': this.safeString(ticker, 'l'),
|
|
326
|
+
'bid': this.safeString(ticker, 'b'),
|
|
327
|
+
'bidVolume': this.safeString(ticker, 'B'),
|
|
328
|
+
'ask': this.safeString(ticker, 'a'),
|
|
329
|
+
'askVolume': this.safeString(ticker, 'A'),
|
|
330
|
+
'vwap': this.safeString(ticker, 'w'),
|
|
331
|
+
'open': this.safeString(ticker, 'o'),
|
|
332
|
+
'close': close,
|
|
333
|
+
'last': close,
|
|
334
|
+
'previousClose': this.safeString(ticker, 'x'),
|
|
335
|
+
'change': this.safeString(ticker, 'p'),
|
|
336
|
+
'percentage': this.safeString(ticker, 'P'),
|
|
337
|
+
'average': this.safeString(ticker, 'w'),
|
|
338
|
+
'baseVolume': this.safeString(ticker, 'v'),
|
|
339
|
+
'quoteVolume': this.safeString(ticker, 'q'),
|
|
340
|
+
'markPrice': this.safeString(ticker, 'm'),
|
|
341
|
+
'indexPrice': this.safeString(ticker, 'i'),
|
|
342
|
+
'info': ticker,
|
|
343
|
+
}, market);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* @method
|
|
347
|
+
* @name weex#watchTrades
|
|
348
|
+
* @description get the list of most recent trades for a particular symbol
|
|
349
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Trades-Channel
|
|
350
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Trades-Channel
|
|
351
|
+
* @param {string} symbol unified symbol of the market to fetch trades for
|
|
352
|
+
* @param {int} [since] timestamp in ms of the earliest trade to fetch
|
|
353
|
+
* @param {int} [limit] the maximum amount of trades to fetch
|
|
354
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
355
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades}
|
|
356
|
+
*/
|
|
357
|
+
async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
|
|
358
|
+
return await this.watchTradesForSymbols([symbol], since, limit, params);
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* @method
|
|
362
|
+
* @name weex#watchTradesForSymbols
|
|
363
|
+
* @description get the list of most recent trades for a list of symbols
|
|
364
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Trades-Channel
|
|
365
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Trades-Channel
|
|
366
|
+
* @param {string[]} symbols unified symbol of the market to fetch trades for
|
|
367
|
+
* @param {int} [since] timestamp in ms of the earliest trade to fetch
|
|
368
|
+
* @param {int} [limit] the maximum amount of trades to fetch
|
|
369
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
370
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades}
|
|
371
|
+
*/
|
|
372
|
+
async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
|
|
373
|
+
await this.loadMarkets();
|
|
374
|
+
symbols = this.marketSymbols(symbols, undefined, false, true);
|
|
375
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
376
|
+
const isContract = firstMarket['contract'];
|
|
377
|
+
const topic = 'trade';
|
|
378
|
+
const messageHashes = [];
|
|
379
|
+
const channels = [];
|
|
380
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
381
|
+
const symbol = symbols[i];
|
|
382
|
+
const market = this.market(symbol);
|
|
383
|
+
const channelName = market['id'] + '@' + topic;
|
|
384
|
+
const messageHash = topic + '::' + symbol;
|
|
385
|
+
messageHashes.push(messageHash);
|
|
386
|
+
channels.push(channelName);
|
|
387
|
+
}
|
|
388
|
+
const trades = await this.subscribePublic(messageHashes, channels, isContract, params);
|
|
389
|
+
if (this.newUpdates) {
|
|
390
|
+
const first = this.safeValue(trades, 0);
|
|
391
|
+
const tradeSymbol = this.safeString(first, 'symbol');
|
|
392
|
+
limit = trades.getLimit(tradeSymbol, limit);
|
|
393
|
+
}
|
|
394
|
+
return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* @method
|
|
398
|
+
* @name weex#unWatchTrades
|
|
399
|
+
* @description unsubscribes from the trades channel
|
|
400
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Trades-Channel
|
|
401
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Trades-Channel
|
|
402
|
+
* @param {string} symbol unified symbol of the market to fetch trades for
|
|
403
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
404
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades}
|
|
405
|
+
*/
|
|
406
|
+
async unWatchTrades(symbol, params = {}) {
|
|
407
|
+
await this.loadMarkets();
|
|
408
|
+
return await this.unWatchTradesForSymbols([symbol], params);
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* @method
|
|
412
|
+
* @name weex#unWatchTradesForSymbols
|
|
413
|
+
* @description unsubscribes from the trades channel
|
|
414
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Trades-Channel
|
|
415
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Trades-Channel
|
|
416
|
+
* @param {string[]} symbols unified symbol of the market to fetch trades for
|
|
417
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
418
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades}
|
|
419
|
+
*/
|
|
420
|
+
async unWatchTradesForSymbols(symbols, params = {}) {
|
|
421
|
+
await this.loadMarkets();
|
|
422
|
+
symbols = this.marketSymbols(symbols, undefined, false, true);
|
|
423
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
424
|
+
const isContract = firstMarket['contract'];
|
|
425
|
+
const topic = 'trade';
|
|
426
|
+
const subHashes = [];
|
|
427
|
+
const channels = [];
|
|
428
|
+
const unSubHashes = [];
|
|
429
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
430
|
+
const symbol = symbols[i];
|
|
431
|
+
const market = this.market(symbol);
|
|
432
|
+
const channelName = market['id'] + '@' + topic;
|
|
433
|
+
const messageHash = topic + '::' + symbol;
|
|
434
|
+
const unSubMessageHash = 'unsubscribe::' + messageHash;
|
|
435
|
+
subHashes.push(messageHash);
|
|
436
|
+
channels.push(channelName);
|
|
437
|
+
unSubHashes.push(unSubMessageHash);
|
|
438
|
+
}
|
|
439
|
+
const subscription = {
|
|
440
|
+
'unsubscribe': true,
|
|
441
|
+
'symbols': symbols,
|
|
442
|
+
'messageHashes': unSubHashes,
|
|
443
|
+
'subMessageHashes': subHashes,
|
|
444
|
+
'topic': 'trades',
|
|
445
|
+
};
|
|
446
|
+
return await this.subscribePublic(unSubHashes, channels, isContract, params, subscription);
|
|
447
|
+
}
|
|
448
|
+
handleTrade(client, message) {
|
|
449
|
+
//
|
|
450
|
+
// {
|
|
451
|
+
// "e": "trade",
|
|
452
|
+
// "E": 1776104608321,
|
|
453
|
+
// "s": "ETHUSDT",
|
|
454
|
+
// "d": [
|
|
455
|
+
// {
|
|
456
|
+
// "T": 1776104608298,
|
|
457
|
+
// "t": "41099265-7985-4f4c-af93-2cc3bc1cf13b",
|
|
458
|
+
// "p": "2225.15",
|
|
459
|
+
// "q": "0.02525",
|
|
460
|
+
// "v": "56.1850375",
|
|
461
|
+
// "m": false
|
|
462
|
+
// }
|
|
463
|
+
// ]
|
|
464
|
+
// }
|
|
465
|
+
//
|
|
466
|
+
const market = this.getMarketFromClientAndMessage(client, message);
|
|
467
|
+
const symbol = market['symbol'];
|
|
468
|
+
const messageHash = 'trade::' + symbol;
|
|
469
|
+
if (!(symbol in this.trades)) {
|
|
470
|
+
const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
|
|
471
|
+
this.trades[symbol] = new Cache.ArrayCache(limit);
|
|
472
|
+
}
|
|
473
|
+
const tradesArray = this.trades[symbol];
|
|
474
|
+
const data = this.safeList(message, 'd', []);
|
|
475
|
+
const newTrades = [];
|
|
476
|
+
for (let i = 0; i < data.length; i++) {
|
|
477
|
+
const rawTrade = this.safeDict(data, i, {});
|
|
478
|
+
const trade = this.parseWsTrade(rawTrade, market);
|
|
479
|
+
newTrades.push(trade);
|
|
480
|
+
}
|
|
481
|
+
const sorted = this.sortBy(newTrades, 'timestamp');
|
|
482
|
+
for (let j = 0; j < sorted.length; j++) {
|
|
483
|
+
const sortedTrade = sorted[j];
|
|
484
|
+
tradesArray.append(sortedTrade);
|
|
485
|
+
}
|
|
486
|
+
this.trades[symbol] = tradesArray;
|
|
487
|
+
client.resolve(tradesArray, messageHash);
|
|
488
|
+
}
|
|
489
|
+
parseWsTrade(trade, market = undefined) {
|
|
490
|
+
//
|
|
491
|
+
// {
|
|
492
|
+
// "T": 1776089287762,
|
|
493
|
+
// "t": "df4d1af1-71e8-400d-9571-f2cee2e6bea8",
|
|
494
|
+
// "p": "2203.73",
|
|
495
|
+
// "q": "7.214",
|
|
496
|
+
// "v": "15897.70822",
|
|
497
|
+
// "m": false
|
|
498
|
+
// }
|
|
499
|
+
//
|
|
500
|
+
const timestamp = this.safeInteger(trade, 'T');
|
|
501
|
+
return this.safeTrade({
|
|
502
|
+
'info': trade,
|
|
503
|
+
'id': this.safeString(trade, 't'),
|
|
504
|
+
'timestamp': timestamp,
|
|
505
|
+
'datetime': this.iso8601(timestamp),
|
|
506
|
+
'symbol': market['symbol'],
|
|
507
|
+
'order': undefined,
|
|
508
|
+
'type': undefined,
|
|
509
|
+
'side': undefined,
|
|
510
|
+
'takerOrMaker': undefined,
|
|
511
|
+
'price': this.safeString(trade, 'p'),
|
|
512
|
+
'amount': this.safeString(trade, 'q'),
|
|
513
|
+
'cost': this.safeString(trade, 'v'),
|
|
514
|
+
'fee': undefined,
|
|
515
|
+
}, market);
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* @method
|
|
519
|
+
* @name weex#watchOHLCV
|
|
520
|
+
* @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
521
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Candlesticks-Channel
|
|
522
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Candlesticks-Channel
|
|
523
|
+
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
524
|
+
* @param {string} timeframe the length of time each candle represents
|
|
525
|
+
* @param {int} [since] timestamp in ms of the earliest candle to fetch
|
|
526
|
+
* @param {int} [limit] the maximum amount of candles to fetch
|
|
527
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
528
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
529
|
+
*/
|
|
530
|
+
async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
|
531
|
+
const extendedParams = this.extend(params, {
|
|
532
|
+
'callerMethodName': 'watchOHLCV',
|
|
533
|
+
});
|
|
534
|
+
const result = await this.watchOHLCVForSymbols([[symbol, timeframe]], since, limit, extendedParams);
|
|
535
|
+
return result[symbol][timeframe];
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* @method
|
|
539
|
+
* @name weex#watchOHLCVForSymbols
|
|
540
|
+
* @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
541
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Candlesticks-Channel
|
|
542
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Candlesticks-Channel
|
|
543
|
+
* @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
|
|
544
|
+
* @param {int} [since] timestamp in ms of the earliest candle to fetch
|
|
545
|
+
* @param {int} [limit] the maximum amount of candles to fetch
|
|
546
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
547
|
+
* @returns {object} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
548
|
+
*/
|
|
549
|
+
async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
|
|
550
|
+
await this.loadMarkets();
|
|
551
|
+
const callerMethodName = this.safeString(params, 'callerMethodName', 'watchOHLCVForSymbols');
|
|
552
|
+
params = this.omit(params, 'callerMethodName');
|
|
553
|
+
const channels = [];
|
|
554
|
+
const messageHashes = [];
|
|
555
|
+
const firstEntry = this.safeList(symbolsAndTimeframes, 0, []);
|
|
556
|
+
const firstSymbol = this.safeString(firstEntry, 0);
|
|
557
|
+
const firstMarket = this.market(firstSymbol);
|
|
558
|
+
const isContract = firstMarket['contract'];
|
|
559
|
+
let priceType = 'LAST_PRICE';
|
|
560
|
+
if (isContract) {
|
|
561
|
+
[priceType, params] = this.handleOptionAndParams2(params, callerMethodName, 'price', 'priceType', priceType);
|
|
562
|
+
}
|
|
563
|
+
for (let i = 0; i < symbolsAndTimeframes.length; i++) {
|
|
564
|
+
const data = this.safeList(symbolsAndTimeframes, i);
|
|
565
|
+
let symbolString = this.safeString(data, 0);
|
|
566
|
+
const market = this.market(symbolString);
|
|
567
|
+
if (market['type'] !== firstMarket['type']) {
|
|
568
|
+
throw new errors.BadRequest(this.id + ' ' + callerMethodName + ' market symbols must be of the same type');
|
|
569
|
+
}
|
|
570
|
+
symbolString = market['symbol'];
|
|
571
|
+
const unifiedTimeframe = this.safeString(data, 1, '1');
|
|
572
|
+
const interval = this.safeString(this.timeframes, unifiedTimeframe, unifiedTimeframe);
|
|
573
|
+
const channel = market['id'] + '@kline_' + interval + '_' + priceType;
|
|
574
|
+
const messageHash = 'ohlcv::' + symbolString + '::' + unifiedTimeframe;
|
|
575
|
+
channels.push(channel);
|
|
576
|
+
messageHashes.push(messageHash);
|
|
577
|
+
}
|
|
578
|
+
const [symbol, timeframe, stored] = await this.subscribePublic(messageHashes, channels, isContract, params);
|
|
579
|
+
if (this.newUpdates) {
|
|
580
|
+
limit = stored.getLimit(symbol, limit);
|
|
581
|
+
}
|
|
582
|
+
const filtered = this.filterBySinceLimit(stored, since, limit, 0, true);
|
|
583
|
+
return this.createOHLCVObject(symbol, timeframe, filtered);
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* @method
|
|
587
|
+
* @name weex#unWatchOHLCV
|
|
588
|
+
* @description unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
589
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Candlesticks-Channel
|
|
590
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Candlesticks-Channel
|
|
591
|
+
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
592
|
+
* @param {string} timeframe the length of time each candle represents
|
|
593
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
594
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
595
|
+
*/
|
|
596
|
+
async unWatchOHLCV(symbol, timeframe = '1m', params = {}) {
|
|
597
|
+
params['callerMethodName'] = 'unWatchOHLCV';
|
|
598
|
+
return await this.unWatchOHLCVForSymbols([[symbol, timeframe]], params);
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* @method
|
|
602
|
+
* @name weex#unWatchOHLCVForSymbols
|
|
603
|
+
* @description unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
604
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Candlesticks-Channel
|
|
605
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Candlesticks-Channel
|
|
606
|
+
* @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
|
|
607
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
608
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
609
|
+
*/
|
|
610
|
+
async unWatchOHLCVForSymbols(symbolsAndTimeframes, params = {}) {
|
|
611
|
+
await this.loadMarkets();
|
|
612
|
+
const callerMethodName = this.safeString(params, 'callerMethodName', 'unWatchOHLCVForSymbols');
|
|
613
|
+
params = this.omit(params, 'callerMethodName');
|
|
614
|
+
const channels = [];
|
|
615
|
+
const subHashes = [];
|
|
616
|
+
const unSubHashes = [];
|
|
617
|
+
const firstEntry = this.safeList(symbolsAndTimeframes, 0, []);
|
|
618
|
+
const firstSymbol = this.safeString(firstEntry, 0);
|
|
619
|
+
const firstMarket = this.market(firstSymbol);
|
|
620
|
+
const isContract = firstMarket['contract'];
|
|
621
|
+
let priceType = 'LAST_PRICE';
|
|
622
|
+
if (isContract) {
|
|
623
|
+
[priceType, params] = this.handleOptionAndParams2(params, callerMethodName, 'price', 'priceType', priceType);
|
|
624
|
+
}
|
|
625
|
+
for (let i = 0; i < symbolsAndTimeframes.length; i++) {
|
|
626
|
+
const data = this.safeList(symbolsAndTimeframes, i);
|
|
627
|
+
let symbolString = this.safeString(data, 0);
|
|
628
|
+
const market = this.market(symbolString);
|
|
629
|
+
if (market['type'] !== firstMarket['type']) {
|
|
630
|
+
throw new errors.BadRequest(this.id + ' ' + callerMethodName + ' market symbols must be of the same type');
|
|
631
|
+
}
|
|
632
|
+
symbolString = market['symbol'];
|
|
633
|
+
const unifiedTimeframe = this.safeString(data, 1, '1');
|
|
634
|
+
const interval = this.safeString(this.timeframes, unifiedTimeframe, unifiedTimeframe);
|
|
635
|
+
const channel = market['id'] + '@kline_' + interval + '_' + priceType;
|
|
636
|
+
const messageHash = 'ohlcv::' + symbolString + '::' + unifiedTimeframe;
|
|
637
|
+
const unSubMessageHash = 'unsubscribe::' + messageHash;
|
|
638
|
+
channels.push(channel);
|
|
639
|
+
subHashes.push(messageHash);
|
|
640
|
+
unSubHashes.push(unSubMessageHash);
|
|
641
|
+
}
|
|
642
|
+
const subscription = {
|
|
643
|
+
'unsubscribe': true,
|
|
644
|
+
'symbolsAndTimeframes': symbolsAndTimeframes,
|
|
645
|
+
'messageHashes': unSubHashes,
|
|
646
|
+
'subMessageHashes': subHashes,
|
|
647
|
+
'topic': 'ohlcv',
|
|
648
|
+
};
|
|
649
|
+
return await this.subscribePublic(unSubHashes, channels, isContract, params, subscription);
|
|
650
|
+
}
|
|
651
|
+
handleOHLCV(client, message) {
|
|
652
|
+
//
|
|
653
|
+
// {
|
|
654
|
+
// e: 'kline',
|
|
655
|
+
// E: 1776095535012,
|
|
656
|
+
// s: 'ETHUSDT',
|
|
657
|
+
// p: 'LAST_PRICE',
|
|
658
|
+
// d: [
|
|
659
|
+
// {
|
|
660
|
+
// t: 1776092400000,
|
|
661
|
+
// T: 1776096000000,
|
|
662
|
+
// s: 'ETHUSDT',
|
|
663
|
+
// i: '1h',
|
|
664
|
+
// o: '2234.18',
|
|
665
|
+
// c: '2205.15',
|
|
666
|
+
// h: '2236.43',
|
|
667
|
+
// l: '2199.53',
|
|
668
|
+
// v: '12505.60574',
|
|
669
|
+
// n: 3381,
|
|
670
|
+
// q: '27682528.6655305',
|
|
671
|
+
// V: '6420.47929',
|
|
672
|
+
// Q: '14213680.1906424'
|
|
673
|
+
// }
|
|
674
|
+
// ]
|
|
675
|
+
// }
|
|
676
|
+
//
|
|
677
|
+
const market = this.getMarketFromClientAndMessage(client, message);
|
|
678
|
+
const symbol = market['symbol'];
|
|
679
|
+
if (!(symbol in this.ohlcvs)) {
|
|
680
|
+
this.ohlcvs[symbol] = {};
|
|
681
|
+
}
|
|
682
|
+
const data = this.safeList(message, 'd', []);
|
|
683
|
+
const firstEntry = this.safeDict(data, 0, {});
|
|
684
|
+
const interval = this.safeString(firstEntry, 'i');
|
|
685
|
+
const timeframe = this.findTimeframe(interval);
|
|
686
|
+
if (!(timeframe in this.ohlcvs[symbol])) {
|
|
687
|
+
const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
|
|
688
|
+
this.ohlcvs[symbol][timeframe] = new Cache.ArrayCacheByTimestamp(limit);
|
|
689
|
+
}
|
|
690
|
+
const stored = this.ohlcvs[symbol][timeframe];
|
|
691
|
+
for (let i = 0; i < data.length; i++) {
|
|
692
|
+
const entry = this.safeDict(data, i, {});
|
|
693
|
+
const parsed = this.parseWsOHLCV(entry);
|
|
694
|
+
stored.append(parsed);
|
|
695
|
+
}
|
|
696
|
+
const messageHash = 'ohlcv::' + symbol + '::' + timeframe;
|
|
697
|
+
const resolveData = [symbol, timeframe, stored];
|
|
698
|
+
client.resolve(resolveData, messageHash);
|
|
699
|
+
}
|
|
700
|
+
parseWsOHLCV(ohlcv, market = undefined) {
|
|
701
|
+
//
|
|
702
|
+
// {
|
|
703
|
+
// t: 1776092400000,
|
|
704
|
+
// T: 1776096000000,
|
|
705
|
+
// s: 'ETHUSDT',
|
|
706
|
+
// i: '1h',
|
|
707
|
+
// o: '2234.18',
|
|
708
|
+
// c: '2205.15',
|
|
709
|
+
// h: '2236.43',
|
|
710
|
+
// l: '2199.53',
|
|
711
|
+
// v: '12505.60574',
|
|
712
|
+
// n: 3381,
|
|
713
|
+
// q: '27682528.6655305',
|
|
714
|
+
// V: '6420.47929',
|
|
715
|
+
// Q: '14213680.1906424'
|
|
716
|
+
// }
|
|
717
|
+
//
|
|
718
|
+
return [
|
|
719
|
+
this.safeInteger(ohlcv, 't'),
|
|
720
|
+
this.safeNumber(ohlcv, 'o'),
|
|
721
|
+
this.safeNumber(ohlcv, 'h'),
|
|
722
|
+
this.safeNumber(ohlcv, 'l'),
|
|
723
|
+
this.safeNumber(ohlcv, 'c'),
|
|
724
|
+
this.safeNumber(ohlcv, 'v'),
|
|
725
|
+
];
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* @method
|
|
729
|
+
* @name weex#watchOrderBook
|
|
730
|
+
* @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
731
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Depth-Channel
|
|
732
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Depth-Channel
|
|
733
|
+
* @param {string} symbol unified symbol of the market to fetch the order book for
|
|
734
|
+
* @param {int} [limit] the maximum amount of order book entries to return
|
|
735
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
736
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/?id=order-book-structure} indexed by market symbols
|
|
737
|
+
*/
|
|
738
|
+
async watchOrderBook(symbol, limit = undefined, params = {}) {
|
|
739
|
+
params = this.extend(params, {
|
|
740
|
+
'callerMethodName': 'watchOrderBook',
|
|
741
|
+
});
|
|
742
|
+
return await this.watchOrderBookForSymbols([symbol], limit, params);
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* @method
|
|
746
|
+
* @name weex#watchOrderBookForSymbols
|
|
747
|
+
* @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
748
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Depth-Channel
|
|
749
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Depth-Channel
|
|
750
|
+
* @param {string[]} symbols unified array of symbols
|
|
751
|
+
* @param {int} [limit] the maximum amount of order book entries to return
|
|
752
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
753
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/?id=order-book-structure} indexed by market symbols
|
|
754
|
+
*/
|
|
755
|
+
async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
|
|
756
|
+
await this.loadMarkets();
|
|
757
|
+
symbols = this.marketSymbols(symbols, undefined, false, true);
|
|
758
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
759
|
+
const isContract = firstMarket['contract'];
|
|
760
|
+
const callerMethodName = this.safeString(params, 'callerMethodName', 'watchOrderBookForSymbols');
|
|
761
|
+
params = this.omit(params, 'callerMethodName');
|
|
762
|
+
let depth = '200';
|
|
763
|
+
[depth, params] = this.handleOptionAndParams(params, callerMethodName, 'depth', depth);
|
|
764
|
+
const messageHashes = [];
|
|
765
|
+
const channels = [];
|
|
766
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
767
|
+
const symbol = symbols[i];
|
|
768
|
+
const market = this.market(symbol);
|
|
769
|
+
const messageHash = 'orderbook::' + symbol;
|
|
770
|
+
const channel = market['id'] + '@depth' + depth;
|
|
771
|
+
messageHashes.push(messageHash);
|
|
772
|
+
channels.push(channel);
|
|
773
|
+
}
|
|
774
|
+
const subscription = {
|
|
775
|
+
'limit': limit,
|
|
776
|
+
};
|
|
777
|
+
const orderbook = await this.subscribePublic(messageHashes, channels, isContract, params, subscription);
|
|
778
|
+
return orderbook.limit();
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* @method
|
|
782
|
+
* @name weex#unWatchOrderBook
|
|
783
|
+
* @description unWatches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
784
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Depth-Channel
|
|
785
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Depth-Channel
|
|
786
|
+
* @param {string} symbol unified array of symbols
|
|
787
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
788
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/?id=order-book-structure} indexed by market symbols
|
|
789
|
+
*/
|
|
790
|
+
async unWatchOrderBook(symbol, params = {}) {
|
|
791
|
+
params = this.extend(params, {
|
|
792
|
+
'callerMethodName': 'unWatchOrderBook',
|
|
793
|
+
});
|
|
794
|
+
return await this.unWatchOrderBookForSymbols([symbol], params);
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* @method
|
|
798
|
+
* @name weex#unWatchOrderBookForSymbols
|
|
799
|
+
* @description unWatches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
800
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/Depth-Channel
|
|
801
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/public/Depth-Channel
|
|
802
|
+
* @param {string[]} symbols unified array of symbols
|
|
803
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
804
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/?id=order-book-structure} indexed by market symbols
|
|
805
|
+
*/
|
|
806
|
+
async unWatchOrderBookForSymbols(symbols, params = {}) {
|
|
807
|
+
await this.loadMarkets();
|
|
808
|
+
symbols = this.marketSymbols(symbols, undefined, false, true);
|
|
809
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
810
|
+
const isContract = firstMarket['contract'];
|
|
811
|
+
const callerMethodName = this.safeString(params, 'callerMethodName', 'unWatchOrderBookForSymbols');
|
|
812
|
+
params = this.omit(params, 'callerMethodName');
|
|
813
|
+
let depth = '200';
|
|
814
|
+
[depth, params] = this.handleOptionAndParams(params, callerMethodName, 'depth', depth);
|
|
815
|
+
const subHashes = [];
|
|
816
|
+
const channels = [];
|
|
817
|
+
const unSubHashes = [];
|
|
818
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
819
|
+
const symbol = symbols[i];
|
|
820
|
+
const market = this.market(symbol);
|
|
821
|
+
const messageHash = 'orderbook::' + symbol;
|
|
822
|
+
const channel = market['id'] + '@depth' + depth;
|
|
823
|
+
const unSubMessageHash = 'unsubscribe::' + messageHash;
|
|
824
|
+
subHashes.push(messageHash);
|
|
825
|
+
channels.push(channel);
|
|
826
|
+
unSubHashes.push(unSubMessageHash);
|
|
827
|
+
}
|
|
828
|
+
const subscription = {
|
|
829
|
+
'unsubscribe': true,
|
|
830
|
+
'symbols': symbols,
|
|
831
|
+
'messageHashes': unSubHashes,
|
|
832
|
+
'subMessageHashes': subHashes,
|
|
833
|
+
'topic': 'orderbook',
|
|
834
|
+
};
|
|
835
|
+
return await this.subscribePublic(unSubHashes, channels, isContract, params, subscription);
|
|
836
|
+
}
|
|
837
|
+
handleOrderBook(client, message) {
|
|
838
|
+
//
|
|
839
|
+
// {
|
|
840
|
+
// "e": "depth",
|
|
841
|
+
// "E": 1776098967972,
|
|
842
|
+
// "s": "ETHUSDT",
|
|
843
|
+
// "U": 14181847790,
|
|
844
|
+
// "u": 14181847802,
|
|
845
|
+
// "l": 200,
|
|
846
|
+
// "d": "CHANGED",
|
|
847
|
+
// "b": [ [ "2227.21", "0" ], [ "2227.20", "46.519" ] ],
|
|
848
|
+
// "a": [ [ "2227.21", "44.092" ], [ "2227.26", "0" ] ]
|
|
849
|
+
// }
|
|
850
|
+
//
|
|
851
|
+
const market = this.getMarketFromClientAndMessage(client, message);
|
|
852
|
+
const symbol = market['symbol'];
|
|
853
|
+
const messageHash = 'orderbook::' + symbol;
|
|
854
|
+
if (!(symbol in this.orderbooks)) {
|
|
855
|
+
const subscription = this.safeDict(client.subscriptions, messageHash, {});
|
|
856
|
+
const limit = this.safeInteger(subscription, 'limit');
|
|
857
|
+
if (limit !== undefined) {
|
|
858
|
+
this.orderbooks[symbol] = this.orderBook({}, limit);
|
|
859
|
+
}
|
|
860
|
+
else {
|
|
861
|
+
this.orderbooks[symbol] = this.orderBook({});
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
const orderbook = this.orderbooks[symbol];
|
|
865
|
+
const timestamp = this.safeInteger(message, 'E');
|
|
866
|
+
const event = this.safeString(message, 'e');
|
|
867
|
+
const nonce = this.safeInteger(message, 'u');
|
|
868
|
+
if (event === 'depthSnapshot') {
|
|
869
|
+
const parsed = this.parseOrderBook(message, symbol, timestamp, 'b', 'a');
|
|
870
|
+
parsed['nonce'] = nonce;
|
|
871
|
+
orderbook.reset(parsed);
|
|
872
|
+
}
|
|
873
|
+
else {
|
|
874
|
+
const asks = this.safeList(message, 'a', []);
|
|
875
|
+
const bids = this.safeList(message, 'b', []);
|
|
876
|
+
this.handleDeltas(orderbook['asks'], asks);
|
|
877
|
+
this.handleDeltas(orderbook['bids'], bids);
|
|
878
|
+
orderbook['timestamp'] = timestamp;
|
|
879
|
+
orderbook['datetime'] = this.iso8601(timestamp);
|
|
880
|
+
orderbook['nonce'] = nonce;
|
|
881
|
+
}
|
|
882
|
+
client.resolve(orderbook, messageHash);
|
|
883
|
+
}
|
|
884
|
+
handleDelta(bookside, delta) {
|
|
885
|
+
const bidAsk = this.parseBidAsk(delta);
|
|
886
|
+
bookside.storeArray(bidAsk);
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* @method
|
|
890
|
+
* @name weex#watchBidsAsks
|
|
891
|
+
* @description watches best bid & ask for spot symbols
|
|
892
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/BookTicker-Channel
|
|
893
|
+
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
|
|
894
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
895
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
896
|
+
*/
|
|
897
|
+
async watchBidsAsks(symbols = undefined, params = {}) {
|
|
898
|
+
await this.loadMarkets();
|
|
899
|
+
symbols = this.marketSymbols(symbols, undefined, false, true);
|
|
900
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
901
|
+
if (firstMarket['contract']) {
|
|
902
|
+
throw new errors.NotSupported(this.id + ' watchBidsAsks is supported for spot markets only');
|
|
903
|
+
}
|
|
904
|
+
const messageHashes = [];
|
|
905
|
+
const channels = [];
|
|
906
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
907
|
+
const symbol = symbols[i];
|
|
908
|
+
const market = this.market(symbol);
|
|
909
|
+
const channelName = market['id'] + '@' + 'bookTicker';
|
|
910
|
+
const messageHash = 'bidask::' + symbol;
|
|
911
|
+
messageHashes.push(messageHash);
|
|
912
|
+
channels.push(channelName);
|
|
913
|
+
}
|
|
914
|
+
const newTicker = await this.subscribePublic(messageHashes, channels, false, params);
|
|
915
|
+
if (this.newUpdates) {
|
|
916
|
+
const result = {};
|
|
917
|
+
result[newTicker['symbol']] = newTicker;
|
|
918
|
+
return result;
|
|
919
|
+
}
|
|
920
|
+
return this.filterByArray(this.bidsasks, 'symbol', symbols);
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* @method
|
|
924
|
+
* @name weex#unWatchBidsAsks
|
|
925
|
+
* @description unWatches best bid & ask for spot symbols
|
|
926
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/public/BookTicker-Channel
|
|
927
|
+
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
|
|
928
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
929
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
930
|
+
*/
|
|
931
|
+
async unWatchBidsAsks(symbols = undefined, params = {}) {
|
|
932
|
+
await this.loadMarkets();
|
|
933
|
+
symbols = this.marketSymbols(symbols, undefined, false, true);
|
|
934
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
935
|
+
if (firstMarket['contract']) {
|
|
936
|
+
throw new errors.NotSupported(this.id + ' unWatchBidsAsks is supported for spot markets only');
|
|
937
|
+
}
|
|
938
|
+
const subHashes = [];
|
|
939
|
+
const channels = [];
|
|
940
|
+
const unSubHashes = [];
|
|
941
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
942
|
+
const symbol = symbols[i];
|
|
943
|
+
const market = this.market(symbol);
|
|
944
|
+
const channelName = market['id'] + '@' + 'bookTicker';
|
|
945
|
+
const messageHash = 'bidask::' + symbol;
|
|
946
|
+
const unSubMessageHash = 'unsubscribe::' + messageHash;
|
|
947
|
+
subHashes.push(messageHash);
|
|
948
|
+
channels.push(channelName);
|
|
949
|
+
unSubHashes.push(unSubMessageHash);
|
|
950
|
+
}
|
|
951
|
+
const subscription = {
|
|
952
|
+
'unsubscribe': true,
|
|
953
|
+
'symbols': symbols,
|
|
954
|
+
'messageHashes': unSubHashes,
|
|
955
|
+
'subMessageHashes': subHashes,
|
|
956
|
+
'topic': 'bidsasks',
|
|
957
|
+
};
|
|
958
|
+
return await this.subscribePublic(unSubHashes, channels, false, params, subscription);
|
|
959
|
+
}
|
|
960
|
+
handleBidAsk(client, message) {
|
|
961
|
+
//
|
|
962
|
+
// {
|
|
963
|
+
// "e": "bookTicker",
|
|
964
|
+
// "E": 1776103547551,
|
|
965
|
+
// "s": "ETHUSDT",
|
|
966
|
+
// "u": 1776103547547,
|
|
967
|
+
// "b": "2227.39",
|
|
968
|
+
// "B": "1.05512",
|
|
969
|
+
// "a": "2227.40",
|
|
970
|
+
// "A": "6.30889"
|
|
971
|
+
// }
|
|
972
|
+
//
|
|
973
|
+
const market = this.getMarketFromClientAndMessage(client, message);
|
|
974
|
+
const ticker = this.parseWsBidAsk(message, market);
|
|
975
|
+
const symbol = ticker['symbol'];
|
|
976
|
+
this.bidsasks[symbol] = ticker;
|
|
977
|
+
const messageHash = 'bidask::' + symbol;
|
|
978
|
+
client.resolve(ticker, messageHash);
|
|
979
|
+
}
|
|
980
|
+
parseWsBidAsk(message, market = undefined) {
|
|
981
|
+
const timestamp = this.safeInteger(message, 'E');
|
|
982
|
+
return this.safeTicker({
|
|
983
|
+
'symbol': market['symbol'],
|
|
984
|
+
'timestamp': timestamp,
|
|
985
|
+
'datetime': this.iso8601(timestamp),
|
|
986
|
+
'ask': this.safeString(message, 'a'),
|
|
987
|
+
'askVolume': this.safeString(message, 'A'),
|
|
988
|
+
'bid': this.safeString(message, 'b'),
|
|
989
|
+
'bidVolume': this.safeString(message, 'B'),
|
|
990
|
+
'info': message,
|
|
991
|
+
}, market);
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* @method
|
|
995
|
+
* @name weex#watchMyTrades
|
|
996
|
+
* @description watches information on multiple trades made by the user
|
|
997
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/private/Fill-Channel
|
|
998
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/private/Fill-Channel
|
|
999
|
+
* @param {string} symbol unified market symbol of the market trades were made in
|
|
1000
|
+
* @param {int} [since] the earliest time in ms to fetch trades for
|
|
1001
|
+
* @param {int} [limit] the maximum number of trade structures to retrieve
|
|
1002
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1003
|
+
* @param {string} [params.type] spot or swap, default is spot if symbol is not provided
|
|
1004
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=trade-structure}
|
|
1005
|
+
*/
|
|
1006
|
+
async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1007
|
+
await this.loadMarkets();
|
|
1008
|
+
let marketType = undefined;
|
|
1009
|
+
let market = undefined;
|
|
1010
|
+
if (symbol !== undefined) {
|
|
1011
|
+
market = this.market(symbol);
|
|
1012
|
+
symbol = market['symbol'];
|
|
1013
|
+
}
|
|
1014
|
+
[marketType, params] = this.handleMarketTypeAndParams('watchMyTrades', market, params);
|
|
1015
|
+
const isContract = (marketType !== 'spot');
|
|
1016
|
+
let messageHash = isContract ? 'myContractTrades' : 'myTrades';
|
|
1017
|
+
const subscriptionHash = messageHash;
|
|
1018
|
+
if (symbol !== undefined) {
|
|
1019
|
+
messageHash += '::' + symbol;
|
|
1020
|
+
}
|
|
1021
|
+
const channel = 'fill';
|
|
1022
|
+
const trades = await this.subscribePrivate(messageHash, subscriptionHash, channel, isContract, params);
|
|
1023
|
+
if (this.newUpdates) {
|
|
1024
|
+
limit = trades.getLimit(symbol, limit);
|
|
1025
|
+
}
|
|
1026
|
+
return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true);
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* @method
|
|
1030
|
+
* @name weex#unWatchMyTrades
|
|
1031
|
+
* @description unWatches information on multiple trades made by the user
|
|
1032
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/private/Fill-Channel
|
|
1033
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/private/Fill-Channel
|
|
1034
|
+
* @param {string} [symbol] not used by the exchange
|
|
1035
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1036
|
+
* @param {string} [params.type] spot or swap, default is spot
|
|
1037
|
+
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
|
|
1038
|
+
*/
|
|
1039
|
+
async unWatchMyTrades(symbol = undefined, params = {}) {
|
|
1040
|
+
if (symbol !== undefined) {
|
|
1041
|
+
throw new errors.NotSupported(this.id + ' unWatchMyTrades does not support a symbol argument. Unsubscribing from myTrades is global for all symbols.');
|
|
1042
|
+
}
|
|
1043
|
+
let marketType = undefined;
|
|
1044
|
+
[marketType, params] = this.handleMarketTypeAndParams('unWatchMyTrades', undefined, params);
|
|
1045
|
+
const isContract = (marketType !== 'spot');
|
|
1046
|
+
const subHash = isContract ? 'myContractTrades' : 'myTrades';
|
|
1047
|
+
const unSubHash = 'unsubscribe::' + subHash;
|
|
1048
|
+
const channel = 'fill';
|
|
1049
|
+
const subscription = {
|
|
1050
|
+
'unsubscribe': true,
|
|
1051
|
+
'messageHashes': [unSubHash],
|
|
1052
|
+
'subMessageHashes': [subHash],
|
|
1053
|
+
'topic': 'myTrades',
|
|
1054
|
+
'subHashIsPrefix': true,
|
|
1055
|
+
};
|
|
1056
|
+
return await this.subscribePrivate(unSubHash, unSubHash, channel, isContract, params, subscription);
|
|
1057
|
+
}
|
|
1058
|
+
handleMyTrades(client, message) {
|
|
1059
|
+
//
|
|
1060
|
+
// spot
|
|
1061
|
+
// {
|
|
1062
|
+
// e: 'fill',
|
|
1063
|
+
// E: 1776174283564,
|
|
1064
|
+
// v: 83,
|
|
1065
|
+
// msgEvent: 'OrderUpdate',
|
|
1066
|
+
// d: [
|
|
1067
|
+
// {
|
|
1068
|
+
// id: '738928502249620072',
|
|
1069
|
+
// symbol: 'DOGEUSDT',
|
|
1070
|
+
// baseCoin: 'DOGE',
|
|
1071
|
+
// quoteCoin: 'USDT',
|
|
1072
|
+
// orderId: '738928502174122600',
|
|
1073
|
+
// orderSide: 'SELL',
|
|
1074
|
+
// fillSize: '200.0',
|
|
1075
|
+
// fillValue: '19.098000',
|
|
1076
|
+
// fillFee: '0.01909800',
|
|
1077
|
+
// direction: 'TAKER',
|
|
1078
|
+
// createdTime: '1776174283564',
|
|
1079
|
+
// updatedTime: '1776174283564'
|
|
1080
|
+
// }
|
|
1081
|
+
// ]
|
|
1082
|
+
// }
|
|
1083
|
+
//
|
|
1084
|
+
// swap
|
|
1085
|
+
// {
|
|
1086
|
+
// "id": "738957755401896296",
|
|
1087
|
+
// "coin": "USDT",
|
|
1088
|
+
// "symbol": "DOGEUSDT",
|
|
1089
|
+
// "orderId": "738957755376730472",
|
|
1090
|
+
// "marginMode": "CROSSED",
|
|
1091
|
+
// "separatedMode": "COMBINED",
|
|
1092
|
+
// "separatedOpenOrderId": "0",
|
|
1093
|
+
// "positionSide": "LONG",
|
|
1094
|
+
// "orderSide": "BUY",
|
|
1095
|
+
// "fillSize": "100",
|
|
1096
|
+
// "fillValue": "9.59500",
|
|
1097
|
+
// "fillFee": "0.00767600",
|
|
1098
|
+
// "liquidateFee": "0",
|
|
1099
|
+
// "realizePnl": "0",
|
|
1100
|
+
// "direction": "TAKER",
|
|
1101
|
+
// "createdTime": "1776181258059",
|
|
1102
|
+
// "updatedTime": "1776181258059"
|
|
1103
|
+
// }
|
|
1104
|
+
//
|
|
1105
|
+
if (this.myTrades === undefined) {
|
|
1106
|
+
const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
|
|
1107
|
+
this.myTrades = new Cache.ArrayCacheBySymbolById(limit);
|
|
1108
|
+
}
|
|
1109
|
+
const trades = this.myTrades;
|
|
1110
|
+
const data = this.safeList(message, 'd', []);
|
|
1111
|
+
const symbols = {};
|
|
1112
|
+
for (let i = 0; i < data.length; i++) {
|
|
1113
|
+
const trade = this.safeDict(data, i, {});
|
|
1114
|
+
const parsed = this.parseWsMyTrade(trade);
|
|
1115
|
+
const symbol = parsed['symbol'];
|
|
1116
|
+
symbols[symbol] = true;
|
|
1117
|
+
trades.append(parsed);
|
|
1118
|
+
}
|
|
1119
|
+
let messageHash = 'myTrades';
|
|
1120
|
+
const symbolKeys = Object.keys(symbols);
|
|
1121
|
+
const market = this.getMarketFromSymbols(symbolKeys);
|
|
1122
|
+
if (market['contract']) {
|
|
1123
|
+
messageHash = 'myContractTrades';
|
|
1124
|
+
}
|
|
1125
|
+
for (let j = 0; j < symbolKeys.length; j++) {
|
|
1126
|
+
const symbol = symbolKeys[j];
|
|
1127
|
+
const symbolMessageHash = messageHash + '::' + symbol;
|
|
1128
|
+
client.resolve(trades, symbolMessageHash);
|
|
1129
|
+
}
|
|
1130
|
+
client.resolve(trades, messageHash);
|
|
1131
|
+
}
|
|
1132
|
+
parseWsMyTrade(trade, market = undefined) {
|
|
1133
|
+
//
|
|
1134
|
+
// spot
|
|
1135
|
+
// {
|
|
1136
|
+
// id: '738928502249620072',
|
|
1137
|
+
// symbol: 'DOGEUSDT',
|
|
1138
|
+
// baseCoin: 'DOGE',
|
|
1139
|
+
// quoteCoin: 'USDT',
|
|
1140
|
+
// orderId: '738928502174122600',
|
|
1141
|
+
// orderSide: 'SELL',
|
|
1142
|
+
// fillSize: '200.0',
|
|
1143
|
+
// fillValue: '19.098000',
|
|
1144
|
+
// fillFee: '0.01909800',
|
|
1145
|
+
// direction: 'TAKER',
|
|
1146
|
+
// createdTime: '1776174283564',
|
|
1147
|
+
// updatedTime: '1776174283564'
|
|
1148
|
+
// }
|
|
1149
|
+
//
|
|
1150
|
+
const timestamp = this.safeInteger(trade, 'createdTime');
|
|
1151
|
+
const marketId = this.safeString(trade, 'symbol');
|
|
1152
|
+
let marketType = 'spot';
|
|
1153
|
+
const positionSide = this.safeString(trade, 'positionSide');
|
|
1154
|
+
if (positionSide !== undefined) {
|
|
1155
|
+
marketType = 'swap';
|
|
1156
|
+
}
|
|
1157
|
+
market = this.safeMarket(marketId, undefined, undefined, marketType);
|
|
1158
|
+
const side = this.safeStringLower(trade, 'orderSide');
|
|
1159
|
+
let fee = undefined;
|
|
1160
|
+
const commission = this.safeString(trade, 'fillFee');
|
|
1161
|
+
if (commission !== undefined) {
|
|
1162
|
+
const commissionAsset = this.safeString(trade, 'coin');
|
|
1163
|
+
let feeCurrency = this.safeCurrencyCode(commissionAsset);
|
|
1164
|
+
if (marketType === 'spot') {
|
|
1165
|
+
if (side === 'buy') {
|
|
1166
|
+
feeCurrency = market['base'];
|
|
1167
|
+
}
|
|
1168
|
+
else {
|
|
1169
|
+
feeCurrency = market['quote'];
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
fee = {
|
|
1173
|
+
'cost': commission,
|
|
1174
|
+
'currency': feeCurrency,
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
return this.safeTrade({
|
|
1178
|
+
'info': trade,
|
|
1179
|
+
'id': this.safeString(trade, 'id'),
|
|
1180
|
+
'timestamp': timestamp,
|
|
1181
|
+
'datetime': this.iso8601(timestamp),
|
|
1182
|
+
'symbol': market['symbol'],
|
|
1183
|
+
'order': this.safeString(trade, 'orderId'),
|
|
1184
|
+
'type': this.safeString(trade, 'type'),
|
|
1185
|
+
'side': side,
|
|
1186
|
+
'takerOrMaker': this.safeStringLower(trade, 'direction'),
|
|
1187
|
+
'price': undefined,
|
|
1188
|
+
'amount': this.safeString(trade, 'fillSize'),
|
|
1189
|
+
'cost': this.safeString(trade, 'fillValue'),
|
|
1190
|
+
'fee': fee,
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* @method
|
|
1195
|
+
* @name weex#watchOrders
|
|
1196
|
+
* @description watches information on multiple orders made by the user
|
|
1197
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/private/Order-Channel
|
|
1198
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/private/Order-Channel
|
|
1199
|
+
* @param {string} symbol unified market symbol of the market orders were made in
|
|
1200
|
+
* @param {int} [since] the earliest time in ms to fetch orders for
|
|
1201
|
+
* @param {int} [limit] the maximum number of order structures to retrieve
|
|
1202
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1203
|
+
* @param {string} [params.type] spot or swap, default is spot if symbol is not provided
|
|
1204
|
+
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
|
|
1205
|
+
*/
|
|
1206
|
+
async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1207
|
+
await this.loadMarkets();
|
|
1208
|
+
let market = undefined;
|
|
1209
|
+
if (symbol !== undefined) {
|
|
1210
|
+
market = this.market(symbol);
|
|
1211
|
+
symbol = market['symbol'];
|
|
1212
|
+
}
|
|
1213
|
+
let marketType = undefined;
|
|
1214
|
+
[marketType, params] = this.handleMarketTypeAndParams('watchOrders', market, params);
|
|
1215
|
+
const isContract = (marketType !== 'spot');
|
|
1216
|
+
let messageHash = isContract ? 'contractOrders' : 'orders';
|
|
1217
|
+
const subscriptionHash = messageHash;
|
|
1218
|
+
if (symbol !== undefined) {
|
|
1219
|
+
messageHash += '::' + symbol;
|
|
1220
|
+
}
|
|
1221
|
+
const channel = 'orders';
|
|
1222
|
+
const orders = await this.subscribePrivate(messageHash, subscriptionHash, channel, isContract, params);
|
|
1223
|
+
if (this.newUpdates) {
|
|
1224
|
+
limit = orders.getLimit(symbol, limit);
|
|
1225
|
+
}
|
|
1226
|
+
return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* @method
|
|
1230
|
+
* @name weex#unWatchOrders
|
|
1231
|
+
* @description unWatches information on multiple orders made by the user
|
|
1232
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/private/Order-Channel
|
|
1233
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/private/Order-Channel
|
|
1234
|
+
* @param {string} [symbol] not used by the exchange
|
|
1235
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1236
|
+
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1237
|
+
*/
|
|
1238
|
+
async unWatchOrders(symbol = undefined, params = {}) {
|
|
1239
|
+
if (symbol !== undefined) {
|
|
1240
|
+
throw new errors.NotSupported(this.id + ' unWatchOrders does not support a symbol argument. Unsubscribing from orders is global for all symbols.');
|
|
1241
|
+
}
|
|
1242
|
+
let marketType = undefined;
|
|
1243
|
+
[marketType, params] = this.handleMarketTypeAndParams('unWatchOrders', undefined, params);
|
|
1244
|
+
const isContract = (marketType !== 'spot');
|
|
1245
|
+
const subHash = isContract ? 'contractOrders' : 'orders';
|
|
1246
|
+
const unSubHash = 'unsubscribe::' + subHash;
|
|
1247
|
+
const channel = 'orders';
|
|
1248
|
+
const subscription = {
|
|
1249
|
+
'unsubscribe': true,
|
|
1250
|
+
'messageHashes': [unSubHash],
|
|
1251
|
+
'subMessageHashes': [subHash],
|
|
1252
|
+
'topic': 'orders',
|
|
1253
|
+
'subHashIsPrefix': true,
|
|
1254
|
+
};
|
|
1255
|
+
return await this.subscribePrivate(unSubHash, unSubHash, channel, isContract, params, subscription);
|
|
1256
|
+
}
|
|
1257
|
+
handleOrders(client, message) {
|
|
1258
|
+
//
|
|
1259
|
+
// {
|
|
1260
|
+
// "e": "orders",
|
|
1261
|
+
// "E": 1776184415058,
|
|
1262
|
+
// "v": 153,
|
|
1263
|
+
// "msgEvent": "OrderUpdate",
|
|
1264
|
+
// "d": [
|
|
1265
|
+
// {
|
|
1266
|
+
// "id": "738970996765098600",
|
|
1267
|
+
// "symbol": "DOGEUSDT",
|
|
1268
|
+
// "baseCoin": "DOGE",
|
|
1269
|
+
// "quoteCoin": "USDT",
|
|
1270
|
+
// "orderSide": "SELL",
|
|
1271
|
+
// "price": "0",
|
|
1272
|
+
// "size": "200.0",
|
|
1273
|
+
// "value": "0",
|
|
1274
|
+
// "clientOrderId": "b-WEEX111125-bf78d975ca38422bb6ea65",
|
|
1275
|
+
// "type": "MARKET",
|
|
1276
|
+
// "timeInForce": "IOC",
|
|
1277
|
+
// "reduceOnly": false,
|
|
1278
|
+
// "triggerPrice": "0",
|
|
1279
|
+
// "orderSource": "API",
|
|
1280
|
+
// "openTpslParentOrderId": "0",
|
|
1281
|
+
// "setOpenTp": false,
|
|
1282
|
+
// "setOpenSl": false,
|
|
1283
|
+
// "takerFeeRate": "0.001",
|
|
1284
|
+
// "makerFeeRate": "0.001",
|
|
1285
|
+
// "feeDiscount": "1",
|
|
1286
|
+
// "takerFeeDiscount": "1",
|
|
1287
|
+
// "makerFeeDiscount": "1",
|
|
1288
|
+
// "status": "FILLED",
|
|
1289
|
+
// "triggerTime": "0",
|
|
1290
|
+
// "triggerPriceTime": "0",
|
|
1291
|
+
// "triggerPriceValue": "0",
|
|
1292
|
+
// "cancelReason": "UNKNOWN_ORDER_CANCEL_REASON",
|
|
1293
|
+
// "latestFillPrice": "0.09571",
|
|
1294
|
+
// "maxFillPrice": "0.09571",
|
|
1295
|
+
// "minFillPrice": "0.09571",
|
|
1296
|
+
// "cumFillSize": "200.0",
|
|
1297
|
+
// "cumFillValue": "19.142000",
|
|
1298
|
+
// "cumFillFee": "0.01914200",
|
|
1299
|
+
// "createdTime": "1776184415046",
|
|
1300
|
+
// "updatedTime": "1776184415058"
|
|
1301
|
+
// }
|
|
1302
|
+
// ]
|
|
1303
|
+
// }
|
|
1304
|
+
//
|
|
1305
|
+
const data = this.safeList(message, 'd', []);
|
|
1306
|
+
const symbols = {};
|
|
1307
|
+
if (this.orders === undefined) {
|
|
1308
|
+
const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
|
|
1309
|
+
this.orders = new Cache.ArrayCacheBySymbolById(limit);
|
|
1310
|
+
}
|
|
1311
|
+
const orders = this.orders;
|
|
1312
|
+
const newOrders = [];
|
|
1313
|
+
for (let i = 0; i < data.length; i++) {
|
|
1314
|
+
const rawOrder = this.safeDict(data, i, {});
|
|
1315
|
+
const parsed = this.parseWsOrder(rawOrder);
|
|
1316
|
+
orders.append(parsed);
|
|
1317
|
+
newOrders.push(parsed);
|
|
1318
|
+
const symbol = parsed['symbol'];
|
|
1319
|
+
symbols[symbol] = true;
|
|
1320
|
+
}
|
|
1321
|
+
let messageHash = 'orders';
|
|
1322
|
+
const symbolKeys = Object.keys(symbols);
|
|
1323
|
+
const market = this.getMarketFromSymbols(symbolKeys);
|
|
1324
|
+
if (market['contract']) {
|
|
1325
|
+
messageHash = 'contractOrders';
|
|
1326
|
+
}
|
|
1327
|
+
for (let i = 0; i < symbolKeys.length; i++) {
|
|
1328
|
+
const symbol = symbolKeys[i];
|
|
1329
|
+
const symbolMessageHash = messageHash + '::' + symbol;
|
|
1330
|
+
client.resolve(newOrders, symbolMessageHash);
|
|
1331
|
+
}
|
|
1332
|
+
client.resolve(newOrders, messageHash);
|
|
1333
|
+
}
|
|
1334
|
+
parseWsOrder(order, market = undefined) {
|
|
1335
|
+
//
|
|
1336
|
+
// spot
|
|
1337
|
+
// {
|
|
1338
|
+
// "id": "738970996765098600",
|
|
1339
|
+
// "symbol": "DOGEUSDT",
|
|
1340
|
+
// "baseCoin": "DOGE",
|
|
1341
|
+
// "quoteCoin": "USDT",
|
|
1342
|
+
// "orderSide": "SELL",
|
|
1343
|
+
// "price": "0",
|
|
1344
|
+
// "size": "200.0",
|
|
1345
|
+
// "value": "0",
|
|
1346
|
+
// "clientOrderId": "b-WEEX111125-bf78d975ca38422bb6ea65",
|
|
1347
|
+
// "type": "MARKET",
|
|
1348
|
+
// "timeInForce": "IOC",
|
|
1349
|
+
// "reduceOnly": false,
|
|
1350
|
+
// "triggerPrice": "0",
|
|
1351
|
+
// "orderSource": "API",
|
|
1352
|
+
// "openTpslParentOrderId": "0",
|
|
1353
|
+
// "setOpenTp": false,
|
|
1354
|
+
// "setOpenSl": false,
|
|
1355
|
+
// "takerFeeRate": "0.001",
|
|
1356
|
+
// "makerFeeRate": "0.001",
|
|
1357
|
+
// "feeDiscount": "1",
|
|
1358
|
+
// "takerFeeDiscount": "1",
|
|
1359
|
+
// "makerFeeDiscount": "1",
|
|
1360
|
+
// "status": "FILLED",
|
|
1361
|
+
// "triggerTime": "0",
|
|
1362
|
+
// "triggerPriceTime": "0",
|
|
1363
|
+
// "triggerPriceValue": "0",
|
|
1364
|
+
// "cancelReason": "UNKNOWN_ORDER_CANCEL_REASON",
|
|
1365
|
+
// "latestFillPrice": "0.09571",
|
|
1366
|
+
// "maxFillPrice": "0.09571",
|
|
1367
|
+
// "minFillPrice": "0.09571",
|
|
1368
|
+
// "cumFillSize": "200.0",
|
|
1369
|
+
// "cumFillValue": "19.142000",
|
|
1370
|
+
// "cumFillFee": "0.01914200",
|
|
1371
|
+
// "createdTime": "1776184415046",
|
|
1372
|
+
// "updatedTime": "1776184415058"
|
|
1373
|
+
// }
|
|
1374
|
+
//
|
|
1375
|
+
// swap
|
|
1376
|
+
// {
|
|
1377
|
+
// "id": "617414920861909658",
|
|
1378
|
+
// "coin": "USDT",
|
|
1379
|
+
// "symbol": "BTCUSDT",
|
|
1380
|
+
// "marginMode": "CROSSED",
|
|
1381
|
+
// "separatedMode": "COMBINED",
|
|
1382
|
+
// "separatedOpenOrderId": "0",
|
|
1383
|
+
// "positionSide": "LONG",
|
|
1384
|
+
// "orderSide": "BUY",
|
|
1385
|
+
// "price": "0.0",
|
|
1386
|
+
// "size": "0.10000",
|
|
1387
|
+
// "clientOrderId": "1747203186927FPIZRP",
|
|
1388
|
+
// "type": "MARKET",
|
|
1389
|
+
// "timeInForce": "IOC",
|
|
1390
|
+
// "reduceOnly": false,
|
|
1391
|
+
// "triggerPrice": "0",
|
|
1392
|
+
// "triggerPriceType": "CONTRACT_PRICE",
|
|
1393
|
+
// "orderSource": "WEB",
|
|
1394
|
+
// "openTpslParentOrderId": "0",
|
|
1395
|
+
// "positionTpsl": false,
|
|
1396
|
+
// "setOpenTp": false,
|
|
1397
|
+
// "setOpenSl": false,
|
|
1398
|
+
// "leverage": "20",
|
|
1399
|
+
// "takerFeeRate": "0.0006",
|
|
1400
|
+
// "makerFeeRate": "0.0002",
|
|
1401
|
+
// "feeDiscount": "1",
|
|
1402
|
+
// "liquidateFeeRate": "0.01",
|
|
1403
|
+
// "status": "PENDING",
|
|
1404
|
+
// "triggerTime": "0",
|
|
1405
|
+
// "triggerPriceTime": "0",
|
|
1406
|
+
// "triggerPriceValue": "0",
|
|
1407
|
+
// "cancelReason": "UNKNOWN_ORDER_CANCEL_REASON",
|
|
1408
|
+
// "latestFillPrice": "0",
|
|
1409
|
+
// "maxFillPrice": "0",
|
|
1410
|
+
// "minFillPrice": "0",
|
|
1411
|
+
// "cumFillSize": "0",
|
|
1412
|
+
// "cumFillValue": "0",
|
|
1413
|
+
// "cumFillFee": "0",
|
|
1414
|
+
// "cumLiquidateFee": "0",
|
|
1415
|
+
// "cumRealizePnl": "0",
|
|
1416
|
+
// "createdTime": "1747203188148",
|
|
1417
|
+
// "updatedTime": "1747203188148"
|
|
1418
|
+
// }
|
|
1419
|
+
//
|
|
1420
|
+
const timestamp = this.safeInteger(order, 'createdTime');
|
|
1421
|
+
const marketId = this.safeString(order, 'symbol');
|
|
1422
|
+
let marketType = 'spot';
|
|
1423
|
+
const positionSide = this.safeString(order, 'positionSide');
|
|
1424
|
+
if (positionSide !== undefined) {
|
|
1425
|
+
marketType = 'swap';
|
|
1426
|
+
}
|
|
1427
|
+
market = this.safeMarket(marketId, undefined, undefined, marketType);
|
|
1428
|
+
const side = this.safeStringLower(order, 'orderSide');
|
|
1429
|
+
let fee = undefined;
|
|
1430
|
+
const commission = this.safeString(order, 'cumFillFee');
|
|
1431
|
+
if (commission !== undefined) {
|
|
1432
|
+
const commissionAsset = this.safeString(order, 'coin');
|
|
1433
|
+
let feeCurrency = this.safeCurrencyCode(commissionAsset);
|
|
1434
|
+
if (marketType === 'spot') {
|
|
1435
|
+
if (side === 'buy') {
|
|
1436
|
+
feeCurrency = market['base'];
|
|
1437
|
+
}
|
|
1438
|
+
else {
|
|
1439
|
+
feeCurrency = market['quote'];
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
fee = {
|
|
1443
|
+
'cost': commission,
|
|
1444
|
+
'currency': feeCurrency,
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
const rawStatus = this.safeStringLower(order, 'status');
|
|
1448
|
+
const rawType = this.safeString(order, 'type');
|
|
1449
|
+
const triggerPrice = this.omitZero(this.safeString(order, 'triggerPrice'));
|
|
1450
|
+
let stopLossPrice = undefined;
|
|
1451
|
+
let takeProfitPrice = undefined;
|
|
1452
|
+
if (rawType === 'TAKE_PROFIT_MARKET' || rawType === 'TAKE_PROFIT') {
|
|
1453
|
+
takeProfitPrice = triggerPrice;
|
|
1454
|
+
}
|
|
1455
|
+
else if (rawType === 'STOP_LOSS' || rawType === 'STOP' || rawType === 'STOP_MARKET') {
|
|
1456
|
+
stopLossPrice = triggerPrice;
|
|
1457
|
+
}
|
|
1458
|
+
return this.safeOrder({
|
|
1459
|
+
'id': this.safeString(order, 'id'),
|
|
1460
|
+
'clientOrderId': this.safeString(order, 'clientOrderId'),
|
|
1461
|
+
'symbol': market['symbol'],
|
|
1462
|
+
'type': this.parseOrderType(rawType),
|
|
1463
|
+
'timeInForce': this.safeString(order, 'timeInForce'),
|
|
1464
|
+
'postOnly': undefined,
|
|
1465
|
+
'reduceOnly': this.safeBool(order, 'reduceOnly'),
|
|
1466
|
+
'side': side,
|
|
1467
|
+
'amount': this.safeString(order, 'size'),
|
|
1468
|
+
'price': this.safeString(order, 'price'),
|
|
1469
|
+
'triggerPrice': triggerPrice,
|
|
1470
|
+
'cost': this.safeString(order, 'cumFillValue'),
|
|
1471
|
+
'filled': this.safeString(order, 'cumFillSize'),
|
|
1472
|
+
'remaining': undefined,
|
|
1473
|
+
'timestamp': timestamp,
|
|
1474
|
+
'datetime': this.iso8601(timestamp),
|
|
1475
|
+
'fee': fee,
|
|
1476
|
+
'status': this.parseOrderStatus(rawStatus),
|
|
1477
|
+
'lastTradeTimestamp': undefined,
|
|
1478
|
+
'lastUpdateTimestamp': this.safeInteger(order, 'updatedTime'),
|
|
1479
|
+
'average': undefined,
|
|
1480
|
+
'trades': undefined,
|
|
1481
|
+
'stopLossPrice': stopLossPrice,
|
|
1482
|
+
'takeProfitPrice': takeProfitPrice,
|
|
1483
|
+
'info': order,
|
|
1484
|
+
}, market);
|
|
1485
|
+
}
|
|
1486
|
+
/**
|
|
1487
|
+
* @method
|
|
1488
|
+
* @name weex#watchBalance
|
|
1489
|
+
* @description query for balance and get the amount of funds available for trading or funds locked in orders
|
|
1490
|
+
* @see https://www.weex.com/api-doc/spot/Websocket/private/Account-Channel
|
|
1491
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/private/Account-Channel
|
|
1492
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1493
|
+
* @param {string} [params.type] 'spot' or 'swap', default is 'spot'
|
|
1494
|
+
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/?id=balance-structure}
|
|
1495
|
+
*/
|
|
1496
|
+
async watchBalance(params = {}) {
|
|
1497
|
+
await this.loadMarkets();
|
|
1498
|
+
let type = undefined;
|
|
1499
|
+
[type, params] = this.handleMarketTypeAndParams('watchBalance', undefined, params);
|
|
1500
|
+
const isContract = (type !== 'spot');
|
|
1501
|
+
const urlType = isContract ? 'contract' : 'spot';
|
|
1502
|
+
const url = this.urls['api']['ws'][urlType] + '/private';
|
|
1503
|
+
this.authenticate(url);
|
|
1504
|
+
const client = this.client(url);
|
|
1505
|
+
this.setBalanceCache(client, type);
|
|
1506
|
+
const options = this.safeDict(this.options, 'watchBalance');
|
|
1507
|
+
const fetchBalanceSnapshot = this.safeBool(options, 'fetchBalanceSnapshot', false);
|
|
1508
|
+
const awaitBalanceSnapshot = this.safeBool(options, 'awaitBalanceSnapshot', true);
|
|
1509
|
+
if (fetchBalanceSnapshot && awaitBalanceSnapshot) {
|
|
1510
|
+
await client.future(type + ':fetchBalanceSnapshot');
|
|
1511
|
+
}
|
|
1512
|
+
const messageHash = type + ':' + 'balance';
|
|
1513
|
+
return await this.subscribePrivate(messageHash, type, 'account', isContract, params);
|
|
1514
|
+
}
|
|
1515
|
+
setBalanceCache(client, type) {
|
|
1516
|
+
if ((type in client.subscriptions) && (type in this.balance)) {
|
|
1517
|
+
return;
|
|
1518
|
+
}
|
|
1519
|
+
const options = this.safeDict(this.options, 'watchBalance');
|
|
1520
|
+
const fetchBalanceSnapshot = this.safeBool(options, 'fetchBalanceSnapshot', false);
|
|
1521
|
+
if (fetchBalanceSnapshot) {
|
|
1522
|
+
const messageHash = type + ':fetchBalanceSnapshot';
|
|
1523
|
+
if (!(messageHash in client.futures)) {
|
|
1524
|
+
client.future(messageHash);
|
|
1525
|
+
this.spawn(this.loadBalanceSnapshot, client, messageHash, type);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
else {
|
|
1529
|
+
this.balance[type] = {};
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
async loadBalanceSnapshot(client, messageHash, type) {
|
|
1533
|
+
const params = {
|
|
1534
|
+
'type': type,
|
|
1535
|
+
};
|
|
1536
|
+
const response = await this.fetchBalance(params);
|
|
1537
|
+
this.balance[type] = this.extend(response, this.safeValue(this.balance, type, {}));
|
|
1538
|
+
// don't remove the future from the .futures cache
|
|
1539
|
+
if (messageHash in client.futures) {
|
|
1540
|
+
const future = client.futures[messageHash];
|
|
1541
|
+
future.resolve();
|
|
1542
|
+
client.resolve(this.balance[type], type + ':balance');
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
handleBalance(client, message) {
|
|
1546
|
+
//
|
|
1547
|
+
// spot
|
|
1548
|
+
// {
|
|
1549
|
+
// "e": "account",
|
|
1550
|
+
// "E": 1776187844633,
|
|
1551
|
+
// "v": 178,
|
|
1552
|
+
// "msgEvent": "DepositUpdate",
|
|
1553
|
+
// "d": [
|
|
1554
|
+
// {
|
|
1555
|
+
// "coin": "USDT",
|
|
1556
|
+
// "equity": "47.98428060",
|
|
1557
|
+
// "available": "47.98428060",
|
|
1558
|
+
// "frozen": "0"
|
|
1559
|
+
// }
|
|
1560
|
+
// ]
|
|
1561
|
+
// }
|
|
1562
|
+
//
|
|
1563
|
+
// coontract
|
|
1564
|
+
// {
|
|
1565
|
+
// "e": "account",
|
|
1566
|
+
// "E": 1776189629849,
|
|
1567
|
+
// "v": 281,
|
|
1568
|
+
// "msgEvent": "DepositUpdate",
|
|
1569
|
+
// "d": [
|
|
1570
|
+
// {
|
|
1571
|
+
// "coin": "USDT",
|
|
1572
|
+
// "marginMode": "CROSSED",
|
|
1573
|
+
// "crossSymbol": "0",
|
|
1574
|
+
// "isolatedPositionId": "0",
|
|
1575
|
+
// "amount": "0.00000000",
|
|
1576
|
+
// "pendingDepositAmount": "20.00000000",
|
|
1577
|
+
// "pendingWithdrawAmount": "0.00000000",
|
|
1578
|
+
// "pendingTransferInAmount": "0",
|
|
1579
|
+
// "pendingTransferOutAmount": "0",
|
|
1580
|
+
// "liquidating": false,
|
|
1581
|
+
// "legacyAmount": "0.00000000",
|
|
1582
|
+
// "cumDepositAmount": "167.50000925",
|
|
1583
|
+
// "cumWithdrawAmount": "166.94609514",
|
|
1584
|
+
// "cumTransferInAmount": "0",
|
|
1585
|
+
// "cumTransferOutAmount": "0",
|
|
1586
|
+
// "cumMarginMoveInAmount": "10.86162763",
|
|
1587
|
+
// "cumMarginMoveOutAmount": "10.83205378",
|
|
1588
|
+
// "cumPositionOpenLongAmount": "305.59400",
|
|
1589
|
+
// "cumPositionOpenShortAmount": "238.95700",
|
|
1590
|
+
// "cumPositionCloseLongAmount": "305.86600000",
|
|
1591
|
+
// "cumPositionCloseShortAmount": "238.94700000",
|
|
1592
|
+
// "cumPositionFillFeeAmount": "0.00761040",
|
|
1593
|
+
// "cumPositionLiquidateFeeAmount": "0",
|
|
1594
|
+
// "cumPositionFundingAmount": "0.00049824",
|
|
1595
|
+
// "cumOrderFillFeeIncomeAmount": "0",
|
|
1596
|
+
// "cumOrderLiquidateFeeIncomeAmount": "0",
|
|
1597
|
+
// "createdTime": "1775605824300",
|
|
1598
|
+
// "updatedTime": "1776189629849"
|
|
1599
|
+
// }
|
|
1600
|
+
// ]
|
|
1601
|
+
// }
|
|
1602
|
+
//
|
|
1603
|
+
const url = client.url;
|
|
1604
|
+
let accountType = 'spot';
|
|
1605
|
+
if (url.indexOf('contract') >= 0) {
|
|
1606
|
+
accountType = 'swap';
|
|
1607
|
+
}
|
|
1608
|
+
const messageHash = accountType + ':balance';
|
|
1609
|
+
if (this.balance[accountType] === undefined) {
|
|
1610
|
+
this.balance[accountType] = {};
|
|
1611
|
+
}
|
|
1612
|
+
this.balance[accountType]['info'] = message;
|
|
1613
|
+
const balanceUpdates = this.safeList(message, 'd', []);
|
|
1614
|
+
for (let i = 0; i < balanceUpdates.length; i++) {
|
|
1615
|
+
const entry = this.safeDict(balanceUpdates, i);
|
|
1616
|
+
const currencyId = this.safeString(entry, 'coin');
|
|
1617
|
+
const code = this.safeCurrencyCode(currencyId);
|
|
1618
|
+
const account = this.account();
|
|
1619
|
+
account['free'] = this.safeString2(entry, 'available', 'amount');
|
|
1620
|
+
account['used'] = this.safeString(entry, 'frozen');
|
|
1621
|
+
account['total'] = this.safeString2(entry, 'equity', 'legacyAmount');
|
|
1622
|
+
this.balance[accountType][code] = account;
|
|
1623
|
+
}
|
|
1624
|
+
const timestamp = this.safeInteger(message, 'E');
|
|
1625
|
+
this.balance[accountType]['timestamp'] = timestamp;
|
|
1626
|
+
this.balance[accountType]['datetime'] = this.iso8601(timestamp);
|
|
1627
|
+
this.balance[accountType] = this.safeBalance(this.balance[accountType]);
|
|
1628
|
+
client.resolve(this.balance[accountType], messageHash);
|
|
1629
|
+
}
|
|
1630
|
+
/**
|
|
1631
|
+
* @method
|
|
1632
|
+
* @name weex#watchPositions
|
|
1633
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/private/Positions-Channel
|
|
1634
|
+
* @description watch all open positions
|
|
1635
|
+
* @param {string[]|undefined} symbols list of unified market symbols
|
|
1636
|
+
* @param {int} [since] the earliest time in ms to fetch positions for
|
|
1637
|
+
* @param {int} [limit] the maximum number of position structures to retrieve
|
|
1638
|
+
* @param {object} params extra parameters specific to the exchange API endpoint
|
|
1639
|
+
* @param {int} [params.accountNumber] account number to query orders for, required
|
|
1640
|
+
* @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
|
|
1641
|
+
*/
|
|
1642
|
+
async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1643
|
+
await this.loadMarkets();
|
|
1644
|
+
const url = this.urls['api']['ws']['contract'] + '/private';
|
|
1645
|
+
this.authenticate(url);
|
|
1646
|
+
const client = this.client(url);
|
|
1647
|
+
symbols = this.marketSymbols(symbols, 'swap', true);
|
|
1648
|
+
let messageHash = 'positions';
|
|
1649
|
+
const subscriptionHash = messageHash;
|
|
1650
|
+
if (symbols !== undefined) {
|
|
1651
|
+
messageHash += '::' + symbols.join(',');
|
|
1652
|
+
}
|
|
1653
|
+
const channel = 'positions';
|
|
1654
|
+
this.setPositionsCache(client, params);
|
|
1655
|
+
const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
|
|
1656
|
+
const awaitPositionsSnapshot = this.handleOption('watchPositions', 'awaitPositionsSnapshot', true);
|
|
1657
|
+
if (fetchPositionsSnapshot && awaitPositionsSnapshot && this.positions === undefined) {
|
|
1658
|
+
const snapshot = await client.future('fetchPositionsSnapshot');
|
|
1659
|
+
return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
|
|
1660
|
+
}
|
|
1661
|
+
const newPositions = await this.subscribePrivate(messageHash, subscriptionHash, channel, true, params);
|
|
1662
|
+
if (this.newUpdates) {
|
|
1663
|
+
return newPositions;
|
|
1664
|
+
}
|
|
1665
|
+
return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
|
|
1666
|
+
}
|
|
1667
|
+
setPositionsCache(client, params = {}) {
|
|
1668
|
+
const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', false);
|
|
1669
|
+
if (fetchPositionsSnapshot) {
|
|
1670
|
+
const messageHash = 'fetchPositionsSnapshot';
|
|
1671
|
+
if (!(messageHash in client.futures)) {
|
|
1672
|
+
client.future(messageHash);
|
|
1673
|
+
this.spawn(this.loadPositionsSnapshot, client, messageHash, params);
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
else {
|
|
1677
|
+
this.positions = new Cache.ArrayCacheBySymbolById();
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
async loadPositionsSnapshot(client, messageHash, params) {
|
|
1681
|
+
const positions = await this.fetchPositions(undefined, params);
|
|
1682
|
+
this.positions = new Cache.ArrayCacheBySymbolById();
|
|
1683
|
+
const cache = this.positions;
|
|
1684
|
+
for (let i = 0; i < positions.length; i++) {
|
|
1685
|
+
const position = positions[i];
|
|
1686
|
+
cache.append(position);
|
|
1687
|
+
}
|
|
1688
|
+
// don't remove the future from the .futures cache
|
|
1689
|
+
const future = client.futures[messageHash];
|
|
1690
|
+
future.resolve(cache);
|
|
1691
|
+
client.resolve(cache, 'positions');
|
|
1692
|
+
}
|
|
1693
|
+
/**
|
|
1694
|
+
* @method
|
|
1695
|
+
* @name weex#unWatchPositions
|
|
1696
|
+
* @description unWatches all open positions
|
|
1697
|
+
* @see https://www.weex.com/api-doc/contract/Websocket/private/Positions-Channel
|
|
1698
|
+
* @param {string[]} [symbols] not used by the exchange, unsubscription from positions is global for all symbols
|
|
1699
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1700
|
+
* @returns {object} status of the unwatch request
|
|
1701
|
+
*/
|
|
1702
|
+
async unWatchPositions(symbols = undefined, params = {}) {
|
|
1703
|
+
if (symbols !== undefined) {
|
|
1704
|
+
throw new errors.NotSupported(this.id + ' unWatchPositions does not support a symbols argument. Unsubscribing from positions is global for all symbols.');
|
|
1705
|
+
}
|
|
1706
|
+
const subHash = 'positions';
|
|
1707
|
+
const unSubHash = 'unsubscribe::' + subHash;
|
|
1708
|
+
const channel = 'positions';
|
|
1709
|
+
const subscription = {
|
|
1710
|
+
'unsubscribe': true,
|
|
1711
|
+
'messageHashes': [unSubHash],
|
|
1712
|
+
'subMessageHashes': [subHash],
|
|
1713
|
+
'topic': 'positions',
|
|
1714
|
+
'subHashIsPrefix': true,
|
|
1715
|
+
};
|
|
1716
|
+
return await this.subscribePrivate(unSubHash, unSubHash, channel, true, params, subscription);
|
|
1717
|
+
}
|
|
1718
|
+
handlePositions(client, message) {
|
|
1719
|
+
//
|
|
1720
|
+
// {
|
|
1721
|
+
// "e": "positions",
|
|
1722
|
+
// "E": 1776192398399,
|
|
1723
|
+
// "v": 319,
|
|
1724
|
+
// "msgEvent": "OrderUpdate",
|
|
1725
|
+
// "d": [
|
|
1726
|
+
// {
|
|
1727
|
+
// "id": "739004481374519656",
|
|
1728
|
+
// "coin": "USDT",
|
|
1729
|
+
// "symbol": "DOGEUSDT",
|
|
1730
|
+
// "side": "LONG",
|
|
1731
|
+
// "marginMode": "CROSSED",
|
|
1732
|
+
// "separatedMode": "COMBINED",
|
|
1733
|
+
// "separatedOpenOrderId": "0",
|
|
1734
|
+
// "leverage": "11",
|
|
1735
|
+
// "size": "100",
|
|
1736
|
+
// "openValue": "9.31100",
|
|
1737
|
+
// "openFee": "0.00744880",
|
|
1738
|
+
// "fundingFee": "0",
|
|
1739
|
+
// "isolatedMargin": "0",
|
|
1740
|
+
// "autoAppendIsolatedMargin": false,
|
|
1741
|
+
// "cumOpenSize": "100",
|
|
1742
|
+
// "cumOpenValue": "9.31100",
|
|
1743
|
+
// "cumOpenFee": "0.00744880",
|
|
1744
|
+
// "cumCloseSize": "0",
|
|
1745
|
+
// "cumCloseValue": "0",
|
|
1746
|
+
// "cumCloseFee": "0",
|
|
1747
|
+
// "cumFundingFee": "0",
|
|
1748
|
+
// "cumLiquidateFee": "0",
|
|
1749
|
+
// "createdMatchSequenceId": "5792711540",
|
|
1750
|
+
// "updatedMatchSequenceId": "5792711540",
|
|
1751
|
+
// "createdTime": "1776192398399",
|
|
1752
|
+
// "updatedTime": "1776192398399"
|
|
1753
|
+
// }
|
|
1754
|
+
// ]
|
|
1755
|
+
// }
|
|
1756
|
+
//
|
|
1757
|
+
if (this.positions === undefined) {
|
|
1758
|
+
this.positions = new Cache.ArrayCacheBySymbolById();
|
|
1759
|
+
}
|
|
1760
|
+
const cache = this.positions;
|
|
1761
|
+
const newPositions = [];
|
|
1762
|
+
const data = this.safeList(message, 'd', []);
|
|
1763
|
+
for (let i = 0; i < data.length; i++) {
|
|
1764
|
+
const rawPosition = this.safeDict(data, i, {});
|
|
1765
|
+
const position = this.parsePosition(rawPosition);
|
|
1766
|
+
cache.append(position);
|
|
1767
|
+
newPositions.push(position);
|
|
1768
|
+
}
|
|
1769
|
+
const messageHashes = this.findMessageHashes(client, 'positions::');
|
|
1770
|
+
for (let i = 0; i < messageHashes.length; i++) {
|
|
1771
|
+
const messageHash = messageHashes[i];
|
|
1772
|
+
const parts = messageHash.split('::');
|
|
1773
|
+
const symbolsString = parts[1];
|
|
1774
|
+
const symbols = symbolsString.split(',');
|
|
1775
|
+
const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
|
|
1776
|
+
if (!this.isEmpty(positions)) {
|
|
1777
|
+
client.resolve(positions, messageHash);
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
client.resolve(newPositions, 'positions');
|
|
1781
|
+
}
|
|
1782
|
+
getMarketFromClientAndMessage(client, message) {
|
|
1783
|
+
const url = client.url;
|
|
1784
|
+
let marketType = 'spot';
|
|
1785
|
+
if (url.indexOf('contract') >= 0) {
|
|
1786
|
+
marketType = 'swap';
|
|
1787
|
+
}
|
|
1788
|
+
const marketId = this.safeString(message, 's');
|
|
1789
|
+
const market = this.safeMarket(marketId, undefined, undefined, marketType);
|
|
1790
|
+
return market;
|
|
1791
|
+
}
|
|
1792
|
+
async pong(client, message) {
|
|
1793
|
+
//
|
|
1794
|
+
// { "event": "ping", "time": "1776078750000" } - public
|
|
1795
|
+
//
|
|
1796
|
+
// { "type": "ping", "time": "1776172740000" } - private
|
|
1797
|
+
//
|
|
1798
|
+
const response = {
|
|
1799
|
+
'id': this.requestId(),
|
|
1800
|
+
'method': 'PONG',
|
|
1801
|
+
};
|
|
1802
|
+
await client.send(response);
|
|
1803
|
+
}
|
|
1804
|
+
handlePing(client, message) {
|
|
1805
|
+
this.spawn(this.pong, client, message);
|
|
1806
|
+
}
|
|
1807
|
+
handleSubscriptionStatus(client, message) {
|
|
1808
|
+
//
|
|
1809
|
+
// { "result": true, "id": 2 }
|
|
1810
|
+
//
|
|
1811
|
+
const id = this.safeString(message, 'id');
|
|
1812
|
+
const subscriptionsById = this.indexBy(client.subscriptions, 'id');
|
|
1813
|
+
const subscription = this.safeDict(subscriptionsById, id, {});
|
|
1814
|
+
const unsubscribe = this.safeBool(subscription, 'unsubscribe', false);
|
|
1815
|
+
if (unsubscribe) {
|
|
1816
|
+
const subHashIsPrefix = this.safeBool(subscription, 'subHashIsPrefix', false);
|
|
1817
|
+
const messageHashes = this.safeList(subscription, 'messageHashes', []);
|
|
1818
|
+
const subHashes = this.safeList(subscription, 'subMessageHashes', []);
|
|
1819
|
+
for (let i = 0; i < messageHashes.length; i++) {
|
|
1820
|
+
const unSubHash = this.safeString(messageHashes, i);
|
|
1821
|
+
const subHash = this.safeString(subHashes, i);
|
|
1822
|
+
this.cleanUnsubscription(client, subHash, unSubHash, subHashIsPrefix);
|
|
1823
|
+
}
|
|
1824
|
+
this.cleanCache(subscription);
|
|
1825
|
+
}
|
|
1826
|
+
return message;
|
|
1827
|
+
}
|
|
1828
|
+
handleErrorMessage(client, message) {
|
|
1829
|
+
//
|
|
1830
|
+
// {
|
|
1831
|
+
// "result": false,
|
|
1832
|
+
// "id": 1,
|
|
1833
|
+
// "msg": "INVALID_ARGUMENT: invalid symbol : ASDFS_SPBL"
|
|
1834
|
+
// }
|
|
1835
|
+
//
|
|
1836
|
+
const result = this.safeBool(message, 'result', true);
|
|
1837
|
+
if (!result) {
|
|
1838
|
+
const msg = this.safeString(message, 'msg', '');
|
|
1839
|
+
const feedback = this.id + ' ' + this.json(message);
|
|
1840
|
+
try {
|
|
1841
|
+
this.throwExactlyMatchedException(this.exceptions['exact'], msg, feedback);
|
|
1842
|
+
this.throwBroadlyMatchedException(this.exceptions['broad'], msg, feedback);
|
|
1843
|
+
throw new errors.ExchangeError(feedback);
|
|
1844
|
+
}
|
|
1845
|
+
catch (error) {
|
|
1846
|
+
client.reject(error);
|
|
1847
|
+
return true;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
return false;
|
|
1851
|
+
}
|
|
1852
|
+
handleMessage(client, message) {
|
|
1853
|
+
//
|
|
1854
|
+
// { "id": "5", "method": "PONG" }
|
|
1855
|
+
//
|
|
1856
|
+
// { "result": true, "id": 2 }
|
|
1857
|
+
//
|
|
1858
|
+
// {
|
|
1859
|
+
// "result": false,
|
|
1860
|
+
// "id": 1,
|
|
1861
|
+
// "msg": "INVALID_ARGUMENT: invalid symbol : ASDFS_SPBL"
|
|
1862
|
+
// }
|
|
1863
|
+
//
|
|
1864
|
+
if (this.handleErrorMessage(client, message)) {
|
|
1865
|
+
return;
|
|
1866
|
+
}
|
|
1867
|
+
const id = this.safeString(message, 'id');
|
|
1868
|
+
if (id !== undefined) {
|
|
1869
|
+
this.handleSubscriptionStatus(client, message);
|
|
1870
|
+
return;
|
|
1871
|
+
}
|
|
1872
|
+
const event = this.safeStringN(message, ['e', 'event', 'type']);
|
|
1873
|
+
if (event === 'ping') {
|
|
1874
|
+
this.handlePing(client, message);
|
|
1875
|
+
}
|
|
1876
|
+
else if (event === 'ticker') {
|
|
1877
|
+
this.handleTicker(client, message);
|
|
1878
|
+
}
|
|
1879
|
+
else if ((event === 'trade') || (event === 'tradeSnapshot')) {
|
|
1880
|
+
this.handleTrade(client, message);
|
|
1881
|
+
}
|
|
1882
|
+
else if ((event === 'kline') || (event === 'klineSnapshot')) {
|
|
1883
|
+
this.handleOHLCV(client, message);
|
|
1884
|
+
}
|
|
1885
|
+
else if ((event === 'depth') || (event === 'depthSnapshot')) {
|
|
1886
|
+
this.handleOrderBook(client, message);
|
|
1887
|
+
}
|
|
1888
|
+
else if (event === 'bookTicker') {
|
|
1889
|
+
this.handleBidAsk(client, message);
|
|
1890
|
+
}
|
|
1891
|
+
else if (event === 'fill') {
|
|
1892
|
+
this.handleMyTrades(client, message);
|
|
1893
|
+
}
|
|
1894
|
+
else if (event === 'orders') {
|
|
1895
|
+
this.handleOrders(client, message);
|
|
1896
|
+
}
|
|
1897
|
+
else if (event === 'account') {
|
|
1898
|
+
this.handleBalance(client, message);
|
|
1899
|
+
}
|
|
1900
|
+
else if (event === 'positions') {
|
|
1901
|
+
this.handlePositions(client, message);
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
exports["default"] = weex;
|