ccxt 4.4.85 → 4.4.87
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 +18 -7
- package/dist/ccxt.browser.min.js +3 -3
- package/dist/cjs/ccxt.js +16 -9
- package/dist/cjs/src/abstract/bittrade.js +9 -0
- package/dist/cjs/src/abstract/modetrade.js +9 -0
- package/dist/cjs/src/ascendex.js +189 -155
- package/dist/cjs/src/base/Exchange.js +10 -8
- package/dist/cjs/src/bequant.js +1 -1
- package/dist/cjs/src/binance.js +1 -1
- package/dist/cjs/src/bitget.js +5 -4
- package/dist/cjs/src/bitmart.js +1 -1
- package/dist/cjs/src/bitteam.js +31 -0
- package/dist/cjs/src/bittrade.js +2049 -0
- package/dist/cjs/src/coinbase.js +2 -6
- package/dist/cjs/src/coinmetro.js +5 -1
- package/dist/cjs/src/deribit.js +4 -5
- package/dist/cjs/src/derive.js +4 -5
- package/dist/cjs/src/ellipx.js +2 -3
- package/dist/cjs/src/gate.js +92 -76
- package/dist/cjs/src/hollaex.js +107 -49
- package/dist/cjs/src/htx.js +30 -52
- package/dist/cjs/src/hyperliquid.js +36 -20
- package/dist/cjs/src/kraken.js +5 -8
- package/dist/cjs/src/mexc.js +2 -2
- package/dist/cjs/src/modetrade.js +2839 -0
- package/dist/cjs/src/ndax.js +25 -24
- package/dist/cjs/src/okcoin.js +12 -31
- package/dist/cjs/src/okx.js +104 -2
- package/dist/cjs/src/okxus.js +53 -0
- package/dist/cjs/src/onetrading.js +9 -6
- package/dist/cjs/src/oxfun.js +42 -114
- package/dist/cjs/src/paradex.js +10 -1
- package/dist/cjs/src/phemex.js +4 -6
- package/dist/cjs/src/poloniex.js +181 -170
- package/dist/cjs/src/pro/binance.js +1 -0
- package/dist/cjs/src/pro/bittrade.js +605 -0
- package/dist/cjs/src/pro/luno.js +6 -5
- package/dist/cjs/src/pro/mexc.js +3 -0
- package/dist/cjs/src/pro/modetrade.js +1334 -0
- package/dist/cjs/src/pro/okxus.js +38 -0
- package/dist/cjs/src/probit.js +18 -51
- package/dist/cjs/src/timex.js +5 -10
- package/dist/cjs/src/vertex.js +3 -4
- package/dist/cjs/src/whitebit.js +41 -11
- package/dist/cjs/src/woo.js +101 -77
- package/dist/cjs/src/woofipro.js +24 -21
- package/dist/cjs/src/xt.js +36 -44
- package/js/ccxt.d.ts +20 -11
- package/js/ccxt.js +14 -8
- package/js/src/abstract/modetrade.d.ts +122 -0
- package/js/src/abstract/myokx.d.ts +2 -0
- package/js/src/abstract/okx.d.ts +2 -0
- package/js/src/abstract/okxus.d.ts +352 -0
- package/js/src/abstract/okxus.js +11 -0
- package/js/src/ascendex.d.ts +2 -0
- package/js/src/ascendex.js +189 -155
- package/js/src/base/Exchange.js +10 -8
- package/js/src/bequant.js +1 -1
- package/js/src/binance.js +1 -1
- package/js/src/bitget.js +5 -4
- package/js/src/bitmart.js +1 -1
- package/js/src/bitteam.js +31 -0
- package/js/src/{huobijp.d.ts → bittrade.d.ts} +29 -29
- package/js/src/{huobijp.js → bittrade.js} +35 -35
- package/js/src/coinbase.js +2 -6
- package/js/src/coinmetro.js +5 -1
- package/js/src/deribit.js +4 -5
- package/js/src/derive.js +4 -3
- package/js/src/ellipx.d.ts +1 -1
- package/js/src/ellipx.js +3 -5
- package/js/src/gate.js +92 -76
- package/js/src/hollaex.js +107 -49
- package/js/src/htx.js +30 -52
- package/js/src/hyperliquid.js +36 -20
- package/js/src/kraken.js +5 -8
- package/js/src/mexc.js +2 -2
- package/js/src/modetrade.d.ts +475 -0
- package/js/src/modetrade.js +2840 -0
- package/js/src/ndax.js +25 -24
- package/js/src/okcoin.js +12 -31
- package/js/src/okx.d.ts +24 -1
- package/js/src/okx.js +104 -2
- package/js/src/okxus.d.ts +4 -0
- package/js/src/okxus.js +54 -0
- package/js/src/onetrading.js +9 -6
- package/js/src/oxfun.js +42 -114
- package/js/src/paradex.js +10 -1
- package/js/src/phemex.js +4 -6
- package/js/src/poloniex.d.ts +2 -0
- package/js/src/poloniex.js +181 -170
- package/js/src/pro/binance.js +1 -0
- package/js/src/pro/{huobijp.d.ts → bittrade.d.ts} +6 -6
- package/js/src/pro/{huobijp.js → bittrade.js} +7 -7
- package/js/src/pro/luno.js +6 -5
- package/js/src/pro/mexc.js +3 -0
- package/js/src/pro/modetrade.d.ts +155 -0
- package/js/src/pro/modetrade.js +1335 -0
- package/js/src/pro/okxus.d.ts +4 -0
- package/js/src/pro/okxus.js +39 -0
- package/js/src/probit.js +18 -51
- package/js/src/timex.js +5 -10
- package/js/src/vertex.js +3 -4
- package/js/src/whitebit.js +42 -11
- package/js/src/woo.d.ts +2 -0
- package/js/src/woo.js +101 -77
- package/js/src/woofipro.d.ts +2 -1
- package/js/src/woofipro.js +24 -21
- package/js/src/xt.js +36 -44
- package/package.json +1 -1
- package/js/src/abstract/kuna.d.ts +0 -185
- package/js/src/kuna.d.ts +0 -335
- package/js/src/kuna.js +0 -2006
- /package/js/src/abstract/{huobijp.d.ts → bittrade.d.ts} +0 -0
- /package/js/src/abstract/{huobijp.js → bittrade.js} +0 -0
- /package/js/src/abstract/{kuna.js → modetrade.js} +0 -0
|
@@ -0,0 +1,1335 @@
|
|
|
1
|
+
// ----------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
// PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
|
4
|
+
// https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
|
5
|
+
// EDIT THE CORRESPONDENT .ts FILE INSTEAD
|
|
6
|
+
|
|
7
|
+
// ----------------------------------------------------------------------------
|
|
8
|
+
import modetradeRest from '../modetrade.js';
|
|
9
|
+
import { AuthenticationError, NotSupported } from '../base/errors.js';
|
|
10
|
+
import { ArrayCacheByTimestamp, ArrayCacheBySymbolById, ArrayCache, ArrayCacheBySymbolBySide } from '../base/ws/Cache.js';
|
|
11
|
+
import { Precise } from '../base/Precise.js';
|
|
12
|
+
import { eddsa } from '../base/functions/crypto.js';
|
|
13
|
+
import { ed25519 } from '../static_dependencies/noble-curves/ed25519.js';
|
|
14
|
+
// ----------------------------------------------------------------------------
|
|
15
|
+
export default class modetrade extends modetradeRest {
|
|
16
|
+
describe() {
|
|
17
|
+
return this.deepExtend(super.describe(), {
|
|
18
|
+
'has': {
|
|
19
|
+
'ws': true,
|
|
20
|
+
'watchBalance': true,
|
|
21
|
+
'watchMyTrades': true,
|
|
22
|
+
'watchOHLCV': true,
|
|
23
|
+
'watchOrderBook': true,
|
|
24
|
+
'watchOrders': true,
|
|
25
|
+
'watchTicker': true,
|
|
26
|
+
'watchTickers': true,
|
|
27
|
+
'watchBidsAsks': true,
|
|
28
|
+
'watchTrades': true,
|
|
29
|
+
'watchTradesForSymbols': false,
|
|
30
|
+
'watchPositions': true,
|
|
31
|
+
},
|
|
32
|
+
'urls': {
|
|
33
|
+
'api': {
|
|
34
|
+
'ws': {
|
|
35
|
+
'public': 'wss://ws-evm.orderly.org/ws/stream',
|
|
36
|
+
'private': 'wss://ws-private-evm.orderly.org/v2/ws/private/stream',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
'test': {
|
|
40
|
+
'ws': {
|
|
41
|
+
'public': 'wss://testnet-ws-evm.orderly.org/ws/stream',
|
|
42
|
+
'private': 'wss://testnet-ws-private-evm.orderly.org/v2/ws/private/stream',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
'requiredCredentials': {
|
|
47
|
+
'apiKey': true,
|
|
48
|
+
'secret': true,
|
|
49
|
+
'accountId': true,
|
|
50
|
+
},
|
|
51
|
+
'options': {
|
|
52
|
+
'tradesLimit': 1000,
|
|
53
|
+
'ordersLimit': 1000,
|
|
54
|
+
'requestId': {},
|
|
55
|
+
'watchPositions': {
|
|
56
|
+
'fetchPositionsSnapshot': true,
|
|
57
|
+
'awaitPositionsSnapshot': true, // whether to wait for the positions snapshot before providing updates
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
'streaming': {
|
|
61
|
+
'ping': this.ping,
|
|
62
|
+
'keepAlive': 10000,
|
|
63
|
+
},
|
|
64
|
+
'exceptions': {
|
|
65
|
+
'ws': {
|
|
66
|
+
'exact': {
|
|
67
|
+
'Auth is needed.': AuthenticationError,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
requestId(url) {
|
|
74
|
+
const options = this.safeDict(this.options, 'requestId', {});
|
|
75
|
+
const previousValue = this.safeInteger(options, url, 0);
|
|
76
|
+
const newValue = this.sum(previousValue, 1);
|
|
77
|
+
this.options['requestId'][url] = newValue;
|
|
78
|
+
return newValue;
|
|
79
|
+
}
|
|
80
|
+
async watchPublic(messageHash, message) {
|
|
81
|
+
// the default id
|
|
82
|
+
let id = 'OqdphuyCtYWxwzhxyLLjOWNdFP7sQt8RPWzmb5xY';
|
|
83
|
+
if (this.accountId !== undefined) {
|
|
84
|
+
id = this.accountId;
|
|
85
|
+
}
|
|
86
|
+
const url = this.urls['api']['ws']['public'] + '/' + id;
|
|
87
|
+
const requestId = this.requestId(url);
|
|
88
|
+
const subscribe = {
|
|
89
|
+
'id': requestId,
|
|
90
|
+
};
|
|
91
|
+
const request = this.extend(subscribe, message);
|
|
92
|
+
return await this.watch(url, messageHash, request, messageHash, subscribe);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* @method
|
|
96
|
+
* @name modetrade#watchOrderBook
|
|
97
|
+
* @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/public/orderbook
|
|
98
|
+
* @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
99
|
+
* @param {string} symbol unified symbol of the market to fetch the order book for
|
|
100
|
+
* @param {int} [limit] the maximum amount of order book entries to return.
|
|
101
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
102
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
103
|
+
*/
|
|
104
|
+
async watchOrderBook(symbol, limit = undefined, params = {}) {
|
|
105
|
+
await this.loadMarkets();
|
|
106
|
+
const name = 'orderbook';
|
|
107
|
+
const market = this.market(symbol);
|
|
108
|
+
const topic = market['id'] + '@' + name;
|
|
109
|
+
const request = {
|
|
110
|
+
'event': 'subscribe',
|
|
111
|
+
'topic': topic,
|
|
112
|
+
};
|
|
113
|
+
const message = this.extend(request, params);
|
|
114
|
+
const orderbook = await this.watchPublic(topic, message);
|
|
115
|
+
return orderbook.limit();
|
|
116
|
+
}
|
|
117
|
+
handleOrderBook(client, message) {
|
|
118
|
+
//
|
|
119
|
+
// {
|
|
120
|
+
// "topic": "PERP_BTC_USDC@orderbook",
|
|
121
|
+
// "ts": 1650121915308,
|
|
122
|
+
// "data": {
|
|
123
|
+
// "symbol": "PERP_BTC_USDC",
|
|
124
|
+
// "bids": [
|
|
125
|
+
// [
|
|
126
|
+
// 0.30891,
|
|
127
|
+
// 2469.98
|
|
128
|
+
// ]
|
|
129
|
+
// ],
|
|
130
|
+
// "asks": [
|
|
131
|
+
// [
|
|
132
|
+
// 0.31075,
|
|
133
|
+
// 2379.63
|
|
134
|
+
// ]
|
|
135
|
+
// ]
|
|
136
|
+
// }
|
|
137
|
+
// }
|
|
138
|
+
//
|
|
139
|
+
const data = this.safeDict(message, 'data', {});
|
|
140
|
+
const marketId = this.safeString(data, 'symbol');
|
|
141
|
+
const market = this.safeMarket(marketId);
|
|
142
|
+
const symbol = market['symbol'];
|
|
143
|
+
const topic = this.safeString(message, 'topic');
|
|
144
|
+
if (!(symbol in this.orderbooks)) {
|
|
145
|
+
this.orderbooks[symbol] = this.orderBook();
|
|
146
|
+
}
|
|
147
|
+
const orderbook = this.orderbooks[symbol];
|
|
148
|
+
const timestamp = this.safeInteger(message, 'ts');
|
|
149
|
+
const snapshot = this.parseOrderBook(data, symbol, timestamp, 'bids', 'asks');
|
|
150
|
+
orderbook.reset(snapshot);
|
|
151
|
+
client.resolve(orderbook, topic);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* @method
|
|
155
|
+
* @name modetrade#watchTicker
|
|
156
|
+
* @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/public/24-hour-ticker
|
|
157
|
+
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
158
|
+
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
159
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
160
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
161
|
+
*/
|
|
162
|
+
async watchTicker(symbol, params = {}) {
|
|
163
|
+
await this.loadMarkets();
|
|
164
|
+
const name = 'ticker';
|
|
165
|
+
const market = this.market(symbol);
|
|
166
|
+
symbol = market['symbol'];
|
|
167
|
+
const topic = market['id'] + '@' + name;
|
|
168
|
+
const request = {
|
|
169
|
+
'event': 'subscribe',
|
|
170
|
+
'topic': topic,
|
|
171
|
+
};
|
|
172
|
+
const message = this.extend(request, params);
|
|
173
|
+
return await this.watchPublic(topic, message);
|
|
174
|
+
}
|
|
175
|
+
parseWsTicker(ticker, market = undefined) {
|
|
176
|
+
//
|
|
177
|
+
// {
|
|
178
|
+
// "symbol": "PERP_BTC_USDC",
|
|
179
|
+
// "open": 19441.5,
|
|
180
|
+
// "close": 20147.07,
|
|
181
|
+
// "high": 20761.87,
|
|
182
|
+
// "low": 19320.54,
|
|
183
|
+
// "volume": 2481.103,
|
|
184
|
+
// "amount": 50037935.0286,
|
|
185
|
+
// "count": 3689
|
|
186
|
+
// }
|
|
187
|
+
//
|
|
188
|
+
return this.safeTicker({
|
|
189
|
+
'symbol': this.safeSymbol(undefined, market),
|
|
190
|
+
'timestamp': undefined,
|
|
191
|
+
'datetime': undefined,
|
|
192
|
+
'high': this.safeString(ticker, 'high'),
|
|
193
|
+
'low': this.safeString(ticker, 'low'),
|
|
194
|
+
'bid': undefined,
|
|
195
|
+
'bidVolume': undefined,
|
|
196
|
+
'ask': undefined,
|
|
197
|
+
'askVolume': undefined,
|
|
198
|
+
'vwap': undefined,
|
|
199
|
+
'open': this.safeString(ticker, 'open'),
|
|
200
|
+
'close': this.safeString(ticker, 'close'),
|
|
201
|
+
'last': undefined,
|
|
202
|
+
'previousClose': undefined,
|
|
203
|
+
'change': undefined,
|
|
204
|
+
'percentage': undefined,
|
|
205
|
+
'average': undefined,
|
|
206
|
+
'baseVolume': this.safeString(ticker, 'volume'),
|
|
207
|
+
'quoteVolume': this.safeString(ticker, 'amount'),
|
|
208
|
+
'info': ticker,
|
|
209
|
+
}, market);
|
|
210
|
+
}
|
|
211
|
+
handleTicker(client, message) {
|
|
212
|
+
//
|
|
213
|
+
// {
|
|
214
|
+
// "topic": "PERP_BTC_USDC@ticker",
|
|
215
|
+
// "ts": 1657120017000,
|
|
216
|
+
// "data": {
|
|
217
|
+
// "symbol": "PERP_BTC_USDC",
|
|
218
|
+
// "open": 19441.5,
|
|
219
|
+
// "close": 20147.07,
|
|
220
|
+
// "high": 20761.87,
|
|
221
|
+
// "low": 19320.54,
|
|
222
|
+
// "volume": 2481.103,
|
|
223
|
+
// "amount": 50037935.0286,
|
|
224
|
+
// "count": 3689
|
|
225
|
+
// }
|
|
226
|
+
// }
|
|
227
|
+
//
|
|
228
|
+
const data = this.safeDict(message, 'data', {});
|
|
229
|
+
const topic = this.safeString(message, 'topic');
|
|
230
|
+
const marketId = this.safeString(data, 'symbol');
|
|
231
|
+
const market = this.safeMarket(marketId);
|
|
232
|
+
const timestamp = this.safeInteger(message, 'ts');
|
|
233
|
+
data['date'] = timestamp;
|
|
234
|
+
const ticker = this.parseWsTicker(data, market);
|
|
235
|
+
ticker['symbol'] = market['symbol'];
|
|
236
|
+
this.tickers[market['symbol']] = ticker;
|
|
237
|
+
client.resolve(ticker, topic);
|
|
238
|
+
return message;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* @method
|
|
242
|
+
* @name modetrade#watchTickers
|
|
243
|
+
* @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/public/24-hour-tickers
|
|
244
|
+
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
|
245
|
+
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
|
|
246
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
247
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
248
|
+
*/
|
|
249
|
+
async watchTickers(symbols = undefined, params = {}) {
|
|
250
|
+
await this.loadMarkets();
|
|
251
|
+
symbols = this.marketSymbols(symbols);
|
|
252
|
+
const name = 'tickers';
|
|
253
|
+
const topic = name;
|
|
254
|
+
const request = {
|
|
255
|
+
'event': 'subscribe',
|
|
256
|
+
'topic': topic,
|
|
257
|
+
};
|
|
258
|
+
const message = this.extend(request, params);
|
|
259
|
+
const tickers = await this.watchPublic(topic, message);
|
|
260
|
+
return this.filterByArray(tickers, 'symbol', symbols);
|
|
261
|
+
}
|
|
262
|
+
handleTickers(client, message) {
|
|
263
|
+
//
|
|
264
|
+
// {
|
|
265
|
+
// "topic":"tickers",
|
|
266
|
+
// "ts":1618820615000,
|
|
267
|
+
// "data":[
|
|
268
|
+
// {
|
|
269
|
+
// "symbol":"PERP_NEAR_USDC",
|
|
270
|
+
// "open":16.297,
|
|
271
|
+
// "close":17.183,
|
|
272
|
+
// "high":24.707,
|
|
273
|
+
// "low":11.997,
|
|
274
|
+
// "volume":0,
|
|
275
|
+
// "amount":0,
|
|
276
|
+
// "count":0
|
|
277
|
+
// },
|
|
278
|
+
// ...
|
|
279
|
+
// ]
|
|
280
|
+
// }
|
|
281
|
+
//
|
|
282
|
+
const topic = this.safeString(message, 'topic');
|
|
283
|
+
const data = this.safeList(message, 'data', []);
|
|
284
|
+
const timestamp = this.safeInteger(message, 'ts');
|
|
285
|
+
const result = [];
|
|
286
|
+
for (let i = 0; i < data.length; i++) {
|
|
287
|
+
const marketId = this.safeString(data[i], 'symbol');
|
|
288
|
+
const market = this.safeMarket(marketId);
|
|
289
|
+
const ticker = this.parseWsTicker(this.extend(data[i], { 'date': timestamp }), market);
|
|
290
|
+
this.tickers[market['symbol']] = ticker;
|
|
291
|
+
result.push(ticker);
|
|
292
|
+
}
|
|
293
|
+
client.resolve(result, topic);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* @method
|
|
297
|
+
* @name modetrade#watchBidsAsks
|
|
298
|
+
* @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/public/bbos
|
|
299
|
+
* @description watches best bid & ask for symbols
|
|
300
|
+
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
|
|
301
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
302
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
303
|
+
*/
|
|
304
|
+
async watchBidsAsks(symbols = undefined, params = {}) {
|
|
305
|
+
await this.loadMarkets();
|
|
306
|
+
symbols = this.marketSymbols(symbols);
|
|
307
|
+
const name = 'bbos';
|
|
308
|
+
const topic = name;
|
|
309
|
+
const request = {
|
|
310
|
+
'event': 'subscribe',
|
|
311
|
+
'topic': topic,
|
|
312
|
+
};
|
|
313
|
+
const message = this.extend(request, params);
|
|
314
|
+
const tickers = await this.watchPublic(topic, message);
|
|
315
|
+
return this.filterByArray(tickers, 'symbol', symbols);
|
|
316
|
+
}
|
|
317
|
+
handleBidAsk(client, message) {
|
|
318
|
+
//
|
|
319
|
+
// {
|
|
320
|
+
// "topic": "bbos",
|
|
321
|
+
// "ts": 1726212495000,
|
|
322
|
+
// "data": [
|
|
323
|
+
// {
|
|
324
|
+
// "symbol": "PERP_BTC_USDC",
|
|
325
|
+
// "ask": 0.16570,
|
|
326
|
+
// "askSize": 4224,
|
|
327
|
+
// "bid": 0.16553,
|
|
328
|
+
// "bidSize": 6645
|
|
329
|
+
// }
|
|
330
|
+
// ]
|
|
331
|
+
// }
|
|
332
|
+
//
|
|
333
|
+
const topic = this.safeString(message, 'topic');
|
|
334
|
+
const data = this.safeList(message, 'data', []);
|
|
335
|
+
const timestamp = this.safeInteger(message, 'ts');
|
|
336
|
+
const result = [];
|
|
337
|
+
for (let i = 0; i < data.length; i++) {
|
|
338
|
+
const ticker = this.parseWsBidAsk(this.extend(data[i], { 'ts': timestamp }));
|
|
339
|
+
this.tickers[ticker['symbol']] = ticker;
|
|
340
|
+
result.push(ticker);
|
|
341
|
+
}
|
|
342
|
+
client.resolve(result, topic);
|
|
343
|
+
}
|
|
344
|
+
parseWsBidAsk(ticker, market = undefined) {
|
|
345
|
+
const marketId = this.safeString(ticker, 'symbol');
|
|
346
|
+
market = this.safeMarket(marketId, market);
|
|
347
|
+
const symbol = this.safeString(market, 'symbol');
|
|
348
|
+
const timestamp = this.safeInteger(ticker, 'ts');
|
|
349
|
+
return this.safeTicker({
|
|
350
|
+
'symbol': symbol,
|
|
351
|
+
'timestamp': timestamp,
|
|
352
|
+
'datetime': this.iso8601(timestamp),
|
|
353
|
+
'ask': this.safeString(ticker, 'ask'),
|
|
354
|
+
'askVolume': this.safeString(ticker, 'askSize'),
|
|
355
|
+
'bid': this.safeString(ticker, 'bid'),
|
|
356
|
+
'bidVolume': this.safeString(ticker, 'bidSize'),
|
|
357
|
+
'info': ticker,
|
|
358
|
+
}, market);
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* @method
|
|
362
|
+
* @name modetrade#watchOHLCV
|
|
363
|
+
* @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
364
|
+
* @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/public/k-line
|
|
365
|
+
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
366
|
+
* @param {string} timeframe the length of time each candle represents
|
|
367
|
+
* @param {int} [since] timestamp in ms of the earliest candle to fetch
|
|
368
|
+
* @param {int} [limit] the maximum amount of candles to fetch
|
|
369
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
370
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
371
|
+
*/
|
|
372
|
+
async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
|
373
|
+
await this.loadMarkets();
|
|
374
|
+
if ((timeframe !== '1m') && (timeframe !== '5m') && (timeframe !== '15m') && (timeframe !== '30m') && (timeframe !== '1h') && (timeframe !== '1d') && (timeframe !== '1w') && (timeframe !== '1M')) {
|
|
375
|
+
throw new NotSupported(this.id + ' watchOHLCV timeframe argument must be 1m, 5m, 15m, 30m, 1h, 1d, 1w, 1M');
|
|
376
|
+
}
|
|
377
|
+
const market = this.market(symbol);
|
|
378
|
+
const interval = this.safeString(this.timeframes, timeframe, timeframe);
|
|
379
|
+
const name = 'kline';
|
|
380
|
+
const topic = market['id'] + '@' + name + '_' + interval;
|
|
381
|
+
const request = {
|
|
382
|
+
'event': 'subscribe',
|
|
383
|
+
'topic': topic,
|
|
384
|
+
};
|
|
385
|
+
const message = this.extend(request, params);
|
|
386
|
+
const ohlcv = await this.watchPublic(topic, message);
|
|
387
|
+
if (this.newUpdates) {
|
|
388
|
+
limit = ohlcv.getLimit(market['symbol'], limit);
|
|
389
|
+
}
|
|
390
|
+
return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
|
|
391
|
+
}
|
|
392
|
+
handleOHLCV(client, message) {
|
|
393
|
+
//
|
|
394
|
+
// {
|
|
395
|
+
// "topic":"PERP_BTC_USDC@kline_1m",
|
|
396
|
+
// "ts":1618822432146,
|
|
397
|
+
// "data":{
|
|
398
|
+
// "symbol":"PERP_BTC_USDC",
|
|
399
|
+
// "type":"1m",
|
|
400
|
+
// "open":56948.97,
|
|
401
|
+
// "close":56891.76,
|
|
402
|
+
// "high":56948.97,
|
|
403
|
+
// "low":56889.06,
|
|
404
|
+
// "volume":44.00947568,
|
|
405
|
+
// "amount":2504584.9,
|
|
406
|
+
// "startTime":1618822380000,
|
|
407
|
+
// "endTime":1618822440000
|
|
408
|
+
// }
|
|
409
|
+
// }
|
|
410
|
+
//
|
|
411
|
+
const data = this.safeDict(message, 'data', {});
|
|
412
|
+
const topic = this.safeString(message, 'topic');
|
|
413
|
+
const marketId = this.safeString(data, 'symbol');
|
|
414
|
+
const market = this.safeMarket(marketId);
|
|
415
|
+
const symbol = market['symbol'];
|
|
416
|
+
const interval = this.safeString(data, 'type');
|
|
417
|
+
const timeframe = this.findTimeframe(interval);
|
|
418
|
+
const parsed = [
|
|
419
|
+
this.safeInteger(data, 'startTime'),
|
|
420
|
+
this.safeNumber(data, 'open'),
|
|
421
|
+
this.safeNumber(data, 'high'),
|
|
422
|
+
this.safeNumber(data, 'low'),
|
|
423
|
+
this.safeNumber(data, 'close'),
|
|
424
|
+
this.safeNumber(data, 'volume'),
|
|
425
|
+
];
|
|
426
|
+
this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
|
|
427
|
+
let stored = this.safeValue(this.ohlcvs[symbol], timeframe);
|
|
428
|
+
if (stored === undefined) {
|
|
429
|
+
const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
|
|
430
|
+
stored = new ArrayCacheByTimestamp(limit);
|
|
431
|
+
this.ohlcvs[symbol][timeframe] = stored;
|
|
432
|
+
}
|
|
433
|
+
const ohlcvCache = this.ohlcvs[symbol][timeframe];
|
|
434
|
+
ohlcvCache.append(parsed);
|
|
435
|
+
client.resolve(ohlcvCache, topic);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* @method
|
|
439
|
+
* @name modetrade#watchTrades
|
|
440
|
+
* @description watches information on multiple trades made in a market
|
|
441
|
+
* @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/public/trade
|
|
442
|
+
* @param {string} symbol unified market symbol of the market trades were made in
|
|
443
|
+
* @param {int} [since] the earliest time in ms to fetch trades for
|
|
444
|
+
* @param {int} [limit] the maximum number of trade structures to retrieve
|
|
445
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
446
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
|
|
447
|
+
*/
|
|
448
|
+
async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
|
|
449
|
+
await this.loadMarkets();
|
|
450
|
+
const market = this.market(symbol);
|
|
451
|
+
symbol = market['symbol'];
|
|
452
|
+
const topic = market['id'] + '@trade';
|
|
453
|
+
const request = {
|
|
454
|
+
'event': 'subscribe',
|
|
455
|
+
'topic': topic,
|
|
456
|
+
};
|
|
457
|
+
const message = this.extend(request, params);
|
|
458
|
+
const trades = await this.watchPublic(topic, message);
|
|
459
|
+
if (this.newUpdates) {
|
|
460
|
+
limit = trades.getLimit(market['symbol'], limit);
|
|
461
|
+
}
|
|
462
|
+
return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true);
|
|
463
|
+
}
|
|
464
|
+
handleTrade(client, message) {
|
|
465
|
+
//
|
|
466
|
+
// {
|
|
467
|
+
// "topic":"PERP_ADA_USDC@trade",
|
|
468
|
+
// "ts":1618820361552,
|
|
469
|
+
// "data":{
|
|
470
|
+
// "symbol":"PERP_ADA_USDC",
|
|
471
|
+
// "price":1.27988,
|
|
472
|
+
// "size":300,
|
|
473
|
+
// "side":"BUY",
|
|
474
|
+
// }
|
|
475
|
+
// }
|
|
476
|
+
//
|
|
477
|
+
const topic = this.safeString(message, 'topic');
|
|
478
|
+
const timestamp = this.safeInteger(message, 'ts');
|
|
479
|
+
const data = this.safeDict(message, 'data', {});
|
|
480
|
+
const marketId = this.safeString(data, 'symbol');
|
|
481
|
+
const market = this.safeMarket(marketId);
|
|
482
|
+
const symbol = market['symbol'];
|
|
483
|
+
const trade = this.parseWsTrade(this.extend(data, { 'timestamp': timestamp }), market);
|
|
484
|
+
if (!(symbol in this.trades)) {
|
|
485
|
+
const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
|
|
486
|
+
const stored = new ArrayCache(limit);
|
|
487
|
+
this.trades[symbol] = stored;
|
|
488
|
+
}
|
|
489
|
+
const trades = this.trades[symbol];
|
|
490
|
+
trades.append(trade);
|
|
491
|
+
this.trades[symbol] = trades;
|
|
492
|
+
client.resolve(trades, topic);
|
|
493
|
+
}
|
|
494
|
+
parseWsTrade(trade, market = undefined) {
|
|
495
|
+
//
|
|
496
|
+
// {
|
|
497
|
+
// "symbol":"PERP_ADA_USDC",
|
|
498
|
+
// "timestamp":1618820361552,
|
|
499
|
+
// "price":1.27988,
|
|
500
|
+
// "size":300,
|
|
501
|
+
// "side":"BUY",
|
|
502
|
+
// }
|
|
503
|
+
// private stream
|
|
504
|
+
// {
|
|
505
|
+
// symbol: 'PERP_XRP_USDC',
|
|
506
|
+
// clientOrderId: '',
|
|
507
|
+
// orderId: 1167632251,
|
|
508
|
+
// type: 'MARKET',
|
|
509
|
+
// side: 'BUY',
|
|
510
|
+
// quantity: 20,
|
|
511
|
+
// price: 0,
|
|
512
|
+
// tradeId: '1715179456664012',
|
|
513
|
+
// executedPrice: 0.5276,
|
|
514
|
+
// executedQuantity: 20,
|
|
515
|
+
// fee: 0.006332,
|
|
516
|
+
// feeAsset: 'USDC',
|
|
517
|
+
// totalExecutedQuantity: 20,
|
|
518
|
+
// avgPrice: 0.5276,
|
|
519
|
+
// averageExecutedPrice: 0.5276,
|
|
520
|
+
// status: 'FILLED',
|
|
521
|
+
// reason: '',
|
|
522
|
+
// totalFee: 0.006332,
|
|
523
|
+
// visible: 0,
|
|
524
|
+
// visibleQuantity: 0,
|
|
525
|
+
// timestamp: 1715179456660,
|
|
526
|
+
// orderTag: 'CCXT',
|
|
527
|
+
// createdTime: 1715179456656,
|
|
528
|
+
// maker: false
|
|
529
|
+
// }
|
|
530
|
+
//
|
|
531
|
+
const marketId = this.safeString(trade, 'symbol');
|
|
532
|
+
market = this.safeMarket(marketId, market);
|
|
533
|
+
const symbol = market['symbol'];
|
|
534
|
+
const price = this.safeString2(trade, 'executedPrice', 'price');
|
|
535
|
+
const amount = this.safeString2(trade, 'executedQuantity', 'size');
|
|
536
|
+
const cost = Precise.stringMul(price, amount);
|
|
537
|
+
const side = this.safeStringLower(trade, 'side');
|
|
538
|
+
const timestamp = this.safeInteger(trade, 'timestamp');
|
|
539
|
+
let takerOrMaker = undefined;
|
|
540
|
+
const maker = this.safeBool(trade, 'maker');
|
|
541
|
+
if (maker !== undefined) {
|
|
542
|
+
takerOrMaker = maker ? 'maker' : 'taker';
|
|
543
|
+
}
|
|
544
|
+
let fee = undefined;
|
|
545
|
+
const feeValue = this.safeString(trade, 'fee');
|
|
546
|
+
if (feeValue !== undefined) {
|
|
547
|
+
fee = {
|
|
548
|
+
'cost': feeValue,
|
|
549
|
+
'currency': this.safeCurrencyCode(this.safeString(trade, 'feeAsset')),
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
return this.safeTrade({
|
|
553
|
+
'id': this.safeString(trade, 'tradeId'),
|
|
554
|
+
'timestamp': timestamp,
|
|
555
|
+
'datetime': this.iso8601(timestamp),
|
|
556
|
+
'symbol': symbol,
|
|
557
|
+
'side': side,
|
|
558
|
+
'price': price,
|
|
559
|
+
'amount': amount,
|
|
560
|
+
'cost': cost,
|
|
561
|
+
'order': this.safeString(trade, 'orderId'),
|
|
562
|
+
'takerOrMaker': takerOrMaker,
|
|
563
|
+
'type': this.safeStringLower(trade, 'type'),
|
|
564
|
+
'fee': fee,
|
|
565
|
+
'info': trade,
|
|
566
|
+
}, market);
|
|
567
|
+
}
|
|
568
|
+
handleAuth(client, message) {
|
|
569
|
+
//
|
|
570
|
+
// {
|
|
571
|
+
// "event": "auth",
|
|
572
|
+
// "success": true,
|
|
573
|
+
// "ts": 1657463158812
|
|
574
|
+
// }
|
|
575
|
+
//
|
|
576
|
+
const messageHash = 'authenticated';
|
|
577
|
+
const success = this.safeValue(message, 'success');
|
|
578
|
+
if (success) {
|
|
579
|
+
// client.resolve (message, messageHash);
|
|
580
|
+
const future = this.safeValue(client.futures, 'authenticated');
|
|
581
|
+
future.resolve(true);
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
const error = new AuthenticationError(this.json(message));
|
|
585
|
+
client.reject(error, messageHash);
|
|
586
|
+
// allows further authentication attempts
|
|
587
|
+
if (messageHash in client.subscriptions) {
|
|
588
|
+
delete client.subscriptions['authenticated'];
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
async authenticate(params = {}) {
|
|
593
|
+
this.checkRequiredCredentials();
|
|
594
|
+
const url = this.urls['api']['ws']['private'] + '/' + this.accountId;
|
|
595
|
+
const client = this.client(url);
|
|
596
|
+
const messageHash = 'authenticated';
|
|
597
|
+
const event = 'auth';
|
|
598
|
+
const future = client.future(messageHash);
|
|
599
|
+
const authenticated = this.safeValue(client.subscriptions, messageHash);
|
|
600
|
+
if (authenticated === undefined) {
|
|
601
|
+
const ts = this.nonce().toString();
|
|
602
|
+
const auth = ts;
|
|
603
|
+
let secret = this.secret;
|
|
604
|
+
if (secret.indexOf('ed25519:') >= 0) {
|
|
605
|
+
const parts = secret.split('ed25519:');
|
|
606
|
+
secret = parts[1];
|
|
607
|
+
}
|
|
608
|
+
const signature = eddsa(this.encode(auth), this.base58ToBinary(secret), ed25519);
|
|
609
|
+
const request = {
|
|
610
|
+
'event': event,
|
|
611
|
+
'params': {
|
|
612
|
+
'orderly_key': this.apiKey,
|
|
613
|
+
'sign': signature,
|
|
614
|
+
'timestamp': ts,
|
|
615
|
+
},
|
|
616
|
+
};
|
|
617
|
+
const message = this.extend(request, params);
|
|
618
|
+
this.watch(url, messageHash, message, messageHash);
|
|
619
|
+
}
|
|
620
|
+
return await future;
|
|
621
|
+
}
|
|
622
|
+
async watchPrivate(messageHash, message, params = {}) {
|
|
623
|
+
await this.authenticate(params);
|
|
624
|
+
const url = this.urls['api']['ws']['private'] + '/' + this.accountId;
|
|
625
|
+
const requestId = this.requestId(url);
|
|
626
|
+
const subscribe = {
|
|
627
|
+
'id': requestId,
|
|
628
|
+
};
|
|
629
|
+
const request = this.extend(subscribe, message);
|
|
630
|
+
return await this.watch(url, messageHash, request, messageHash, subscribe);
|
|
631
|
+
}
|
|
632
|
+
async watchPrivateMultiple(messageHashes, message, params = {}) {
|
|
633
|
+
await this.authenticate(params);
|
|
634
|
+
const url = this.urls['api']['ws']['private'] + '/' + this.accountId;
|
|
635
|
+
const requestId = this.requestId(url);
|
|
636
|
+
const subscribe = {
|
|
637
|
+
'id': requestId,
|
|
638
|
+
};
|
|
639
|
+
const request = this.extend(subscribe, message);
|
|
640
|
+
return await this.watchMultiple(url, messageHashes, request, messageHashes, subscribe);
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* @method
|
|
644
|
+
* @name modetrade#watchOrders
|
|
645
|
+
* @description watches information on multiple orders made by the user
|
|
646
|
+
* @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/private/execution-report
|
|
647
|
+
* @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/private/algo-execution-report
|
|
648
|
+
* @param {string} symbol unified market symbol of the market orders were made in
|
|
649
|
+
* @param {int} [since] the earliest time in ms to fetch orders for
|
|
650
|
+
* @param {int} [limit] the maximum number of order structures to retrieve
|
|
651
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
652
|
+
* @param {bool} [params.trigger] true if trigger order
|
|
653
|
+
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
654
|
+
*/
|
|
655
|
+
async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
656
|
+
await this.loadMarkets();
|
|
657
|
+
const trigger = this.safeBool2(params, 'stop', 'trigger', false);
|
|
658
|
+
const topic = (trigger) ? 'algoexecutionreport' : 'executionreport';
|
|
659
|
+
params = this.omit(params, ['stop', 'trigger']);
|
|
660
|
+
let messageHash = topic;
|
|
661
|
+
if (symbol !== undefined) {
|
|
662
|
+
const market = this.market(symbol);
|
|
663
|
+
symbol = market['symbol'];
|
|
664
|
+
messageHash += ':' + symbol;
|
|
665
|
+
}
|
|
666
|
+
const request = {
|
|
667
|
+
'event': 'subscribe',
|
|
668
|
+
'topic': topic,
|
|
669
|
+
};
|
|
670
|
+
const message = this.extend(request, params);
|
|
671
|
+
const orders = await this.watchPrivate(messageHash, message);
|
|
672
|
+
if (this.newUpdates) {
|
|
673
|
+
limit = orders.getLimit(symbol, limit);
|
|
674
|
+
}
|
|
675
|
+
return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* @method
|
|
679
|
+
* @name modetrade#watchMyTrades
|
|
680
|
+
* @description watches information on multiple trades made by the user
|
|
681
|
+
* @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/private/execution-report
|
|
682
|
+
* @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/private/algo-execution-report
|
|
683
|
+
* @param {string} symbol unified market symbol of the market orders were made in
|
|
684
|
+
* @param {int} [since] the earliest time in ms to fetch orders for
|
|
685
|
+
* @param {int} [limit] the maximum number of order structures to retrieve
|
|
686
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
687
|
+
* @param {bool} [params.trigger] true if trigger order
|
|
688
|
+
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
689
|
+
*/
|
|
690
|
+
async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
691
|
+
await this.loadMarkets();
|
|
692
|
+
const trigger = this.safeBool2(params, 'stop', 'trigger', false);
|
|
693
|
+
const topic = (trigger) ? 'algoexecutionreport' : 'executionreport';
|
|
694
|
+
params = this.omit(params, 'stop');
|
|
695
|
+
let messageHash = 'myTrades';
|
|
696
|
+
if (symbol !== undefined) {
|
|
697
|
+
const market = this.market(symbol);
|
|
698
|
+
symbol = market['symbol'];
|
|
699
|
+
messageHash += ':' + symbol;
|
|
700
|
+
}
|
|
701
|
+
const request = {
|
|
702
|
+
'event': 'subscribe',
|
|
703
|
+
'topic': topic,
|
|
704
|
+
};
|
|
705
|
+
const message = this.extend(request, params);
|
|
706
|
+
const orders = await this.watchPrivate(messageHash, message);
|
|
707
|
+
if (this.newUpdates) {
|
|
708
|
+
limit = orders.getLimit(symbol, limit);
|
|
709
|
+
}
|
|
710
|
+
return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
|
|
711
|
+
}
|
|
712
|
+
parseWsOrder(order, market = undefined) {
|
|
713
|
+
//
|
|
714
|
+
// {
|
|
715
|
+
// "symbol": "PERP_BTC_USDT",
|
|
716
|
+
// "clientOrderId": 0,
|
|
717
|
+
// "orderId": 52952826,
|
|
718
|
+
// "type": "LIMIT",
|
|
719
|
+
// "side": "SELL",
|
|
720
|
+
// "quantity": 0.01,
|
|
721
|
+
// "price": 22000,
|
|
722
|
+
// "tradeId": 0,
|
|
723
|
+
// "executedPrice": 0,
|
|
724
|
+
// "executedQuantity": 0,
|
|
725
|
+
// "fee": 0,
|
|
726
|
+
// "feeAsset": "USDT",
|
|
727
|
+
// "totalExecutedQuantity": 0,
|
|
728
|
+
// "status": "NEW",
|
|
729
|
+
// "reason": '',
|
|
730
|
+
// "orderTag": "default",
|
|
731
|
+
// "totalFee": 0,
|
|
732
|
+
// "visible": 0.01,
|
|
733
|
+
// "timestamp": 1657515556799,
|
|
734
|
+
// "reduceOnly": false,
|
|
735
|
+
// "maker": false
|
|
736
|
+
// }
|
|
737
|
+
// algo order
|
|
738
|
+
// {
|
|
739
|
+
// "symbol":"PERP_MATIC_USDC",
|
|
740
|
+
// "rootAlgoOrderId":123,
|
|
741
|
+
// "parentAlgoOrderId":123,
|
|
742
|
+
// "algoOrderId":123,
|
|
743
|
+
// "orderTag":"some tags",
|
|
744
|
+
// "algoType": "STOP",
|
|
745
|
+
// "clientOrderId":"client_id",
|
|
746
|
+
// "type":"LIMIT",
|
|
747
|
+
// "side":"BUY",
|
|
748
|
+
// "quantity":7029.0,
|
|
749
|
+
// "price":0.7699,
|
|
750
|
+
// "tradeId":0,
|
|
751
|
+
// "triggerTradePrice":0,
|
|
752
|
+
// "triggerTime":1234567,
|
|
753
|
+
// "triggered": false,
|
|
754
|
+
// "activated": false,
|
|
755
|
+
// "executedPrice":0.0,
|
|
756
|
+
// "executedQuantity":0.0,
|
|
757
|
+
// "fee":0.0,
|
|
758
|
+
// "feeAsset":"USDC",
|
|
759
|
+
// "totalExecutedQuantity":0.0,
|
|
760
|
+
// "averageExecutedQuantity":0.0,
|
|
761
|
+
// "avgPrice":0,
|
|
762
|
+
// "triggerPrice":0.0,
|
|
763
|
+
// "triggerPriceType":"STOP",
|
|
764
|
+
// "isActivated": false,
|
|
765
|
+
// "status":"NEW",
|
|
766
|
+
// "rootAlgoStatus": "FILLED",
|
|
767
|
+
// "algoStatus": "FILLED",
|
|
768
|
+
// "reason":"",
|
|
769
|
+
// "totalFee":0.0,
|
|
770
|
+
// "visible": 7029.0,
|
|
771
|
+
// "visibleQuantity":7029.0,
|
|
772
|
+
// "timestamp":1704679472448,
|
|
773
|
+
// "maker":false,
|
|
774
|
+
// "isMaker":false,
|
|
775
|
+
// "createdTime":1704679472448
|
|
776
|
+
// }
|
|
777
|
+
//
|
|
778
|
+
const orderId = this.safeString(order, 'orderId');
|
|
779
|
+
const marketId = this.safeString(order, 'symbol');
|
|
780
|
+
market = this.market(marketId);
|
|
781
|
+
const symbol = market['symbol'];
|
|
782
|
+
const timestamp = this.safeInteger(order, 'timestamp');
|
|
783
|
+
const fee = {
|
|
784
|
+
'cost': this.safeString(order, 'totalFee'),
|
|
785
|
+
'currency': this.safeString(order, 'feeAsset'),
|
|
786
|
+
};
|
|
787
|
+
const priceString = this.safeString(order, 'price');
|
|
788
|
+
let price = this.safeNumber(order, 'price');
|
|
789
|
+
const avgPrice = this.safeNumber(order, 'avgPrice');
|
|
790
|
+
if (Precise.stringEq(priceString, '0') && (avgPrice !== undefined)) {
|
|
791
|
+
price = avgPrice;
|
|
792
|
+
}
|
|
793
|
+
const amount = this.safeString(order, 'quantity');
|
|
794
|
+
const side = this.safeStringLower(order, 'side');
|
|
795
|
+
const type = this.safeStringLower(order, 'type');
|
|
796
|
+
const filled = this.safeNumber(order, 'totalExecutedQuantity');
|
|
797
|
+
const totalExecQuantity = this.safeString(order, 'totalExecutedQuantity');
|
|
798
|
+
let remaining = amount;
|
|
799
|
+
if (Precise.stringGe(amount, totalExecQuantity)) {
|
|
800
|
+
remaining = Precise.stringSub(remaining, totalExecQuantity);
|
|
801
|
+
}
|
|
802
|
+
const rawStatus = this.safeString(order, 'status');
|
|
803
|
+
const status = this.parseOrderStatus(rawStatus);
|
|
804
|
+
const trades = undefined;
|
|
805
|
+
const clientOrderId = this.safeString(order, 'clientOrderId');
|
|
806
|
+
const triggerPrice = this.safeNumber(order, 'triggerPrice');
|
|
807
|
+
return this.safeOrder({
|
|
808
|
+
'info': order,
|
|
809
|
+
'symbol': symbol,
|
|
810
|
+
'id': orderId,
|
|
811
|
+
'clientOrderId': clientOrderId,
|
|
812
|
+
'timestamp': timestamp,
|
|
813
|
+
'datetime': this.iso8601(timestamp),
|
|
814
|
+
'lastTradeTimestamp': timestamp,
|
|
815
|
+
'type': type,
|
|
816
|
+
'timeInForce': undefined,
|
|
817
|
+
'postOnly': undefined,
|
|
818
|
+
'side': side,
|
|
819
|
+
'price': price,
|
|
820
|
+
'stopPrice': triggerPrice,
|
|
821
|
+
'triggerPrice': triggerPrice,
|
|
822
|
+
'amount': amount,
|
|
823
|
+
'cost': undefined,
|
|
824
|
+
'average': undefined,
|
|
825
|
+
'filled': filled,
|
|
826
|
+
'remaining': remaining,
|
|
827
|
+
'status': status,
|
|
828
|
+
'fee': fee,
|
|
829
|
+
'trades': trades,
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
handleOrderUpdate(client, message) {
|
|
833
|
+
//
|
|
834
|
+
// {
|
|
835
|
+
// "topic": "executionreport",
|
|
836
|
+
// "ts": 1657515556799,
|
|
837
|
+
// "data": {
|
|
838
|
+
// "symbol": "PERP_BTC_USDT",
|
|
839
|
+
// "clientOrderId": 0,
|
|
840
|
+
// "orderId": 52952826,
|
|
841
|
+
// "type": "LIMIT",
|
|
842
|
+
// "side": "SELL",
|
|
843
|
+
// "quantity": 0.01,
|
|
844
|
+
// "price": 22000,
|
|
845
|
+
// "tradeId": 0,
|
|
846
|
+
// "executedPrice": 0,
|
|
847
|
+
// "executedQuantity": 0,
|
|
848
|
+
// "fee": 0,
|
|
849
|
+
// "feeAsset": "USDT",
|
|
850
|
+
// "totalExecutedQuantity": 0,
|
|
851
|
+
// "status": "NEW",
|
|
852
|
+
// "reason": '',
|
|
853
|
+
// "orderTag": "default",
|
|
854
|
+
// "totalFee": 0,
|
|
855
|
+
// "visible": 0.01,
|
|
856
|
+
// "timestamp": 1657515556799,
|
|
857
|
+
// "maker": false
|
|
858
|
+
// }
|
|
859
|
+
// }
|
|
860
|
+
//
|
|
861
|
+
const topic = this.safeString(message, 'topic');
|
|
862
|
+
const data = this.safeValue(message, 'data');
|
|
863
|
+
if (Array.isArray(data)) {
|
|
864
|
+
// algoexecutionreport
|
|
865
|
+
for (let i = 0; i < data.length; i++) {
|
|
866
|
+
const order = data[i];
|
|
867
|
+
const tradeId = this.omitZero(this.safeString(data, 'tradeId'));
|
|
868
|
+
if (tradeId !== undefined) {
|
|
869
|
+
this.handleMyTrade(client, order);
|
|
870
|
+
}
|
|
871
|
+
this.handleOrder(client, order, topic);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
else {
|
|
875
|
+
// executionreport
|
|
876
|
+
const tradeId = this.omitZero(this.safeString(data, 'tradeId'));
|
|
877
|
+
if (tradeId !== undefined) {
|
|
878
|
+
this.handleMyTrade(client, data);
|
|
879
|
+
}
|
|
880
|
+
this.handleOrder(client, data, topic);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
handleOrder(client, message, topic) {
|
|
884
|
+
const parsed = this.parseWsOrder(message);
|
|
885
|
+
const symbol = this.safeString(parsed, 'symbol');
|
|
886
|
+
const orderId = this.safeString(parsed, 'id');
|
|
887
|
+
if (symbol !== undefined) {
|
|
888
|
+
if (this.orders === undefined) {
|
|
889
|
+
const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
|
|
890
|
+
this.orders = new ArrayCacheBySymbolById(limit);
|
|
891
|
+
}
|
|
892
|
+
const cachedOrders = this.orders;
|
|
893
|
+
const orders = this.safeDict(cachedOrders.hashmap, symbol, {});
|
|
894
|
+
const order = this.safeDict(orders, orderId);
|
|
895
|
+
if (order !== undefined) {
|
|
896
|
+
const fee = this.safeValue(order, 'fee');
|
|
897
|
+
if (fee !== undefined) {
|
|
898
|
+
parsed['fee'] = fee;
|
|
899
|
+
}
|
|
900
|
+
const fees = this.safeList(order, 'fees');
|
|
901
|
+
if (fees !== undefined) {
|
|
902
|
+
parsed['fees'] = fees;
|
|
903
|
+
}
|
|
904
|
+
parsed['trades'] = this.safeList(order, 'trades');
|
|
905
|
+
parsed['timestamp'] = this.safeInteger(order, 'timestamp');
|
|
906
|
+
parsed['datetime'] = this.safeString(order, 'datetime');
|
|
907
|
+
}
|
|
908
|
+
cachedOrders.append(parsed);
|
|
909
|
+
client.resolve(this.orders, topic);
|
|
910
|
+
const messageHashSymbol = topic + ':' + symbol;
|
|
911
|
+
client.resolve(this.orders, messageHashSymbol);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
handleMyTrade(client, message) {
|
|
915
|
+
//
|
|
916
|
+
// {
|
|
917
|
+
// symbol: 'PERP_XRP_USDC',
|
|
918
|
+
// clientOrderId: '',
|
|
919
|
+
// orderId: 1167632251,
|
|
920
|
+
// type: 'MARKET',
|
|
921
|
+
// side: 'BUY',
|
|
922
|
+
// quantity: 20,
|
|
923
|
+
// price: 0,
|
|
924
|
+
// tradeId: '1715179456664012',
|
|
925
|
+
// executedPrice: 0.5276,
|
|
926
|
+
// executedQuantity: 20,
|
|
927
|
+
// fee: 0.006332,
|
|
928
|
+
// feeAsset: 'USDC',
|
|
929
|
+
// totalExecutedQuantity: 20,
|
|
930
|
+
// avgPrice: 0.5276,
|
|
931
|
+
// averageExecutedPrice: 0.5276,
|
|
932
|
+
// status: 'FILLED',
|
|
933
|
+
// reason: '',
|
|
934
|
+
// totalFee: 0.006332,
|
|
935
|
+
// visible: 0,
|
|
936
|
+
// visibleQuantity: 0,
|
|
937
|
+
// timestamp: 1715179456660,
|
|
938
|
+
// orderTag: 'CCXT',
|
|
939
|
+
// createdTime: 1715179456656,
|
|
940
|
+
// maker: false
|
|
941
|
+
// }
|
|
942
|
+
//
|
|
943
|
+
const messageHash = 'myTrades';
|
|
944
|
+
const marketId = this.safeString(message, 'symbol');
|
|
945
|
+
const market = this.safeMarket(marketId);
|
|
946
|
+
const symbol = market['symbol'];
|
|
947
|
+
const trade = this.parseWsTrade(message, market);
|
|
948
|
+
let trades = this.myTrades;
|
|
949
|
+
if (trades === undefined) {
|
|
950
|
+
const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
|
|
951
|
+
trades = new ArrayCacheBySymbolById(limit);
|
|
952
|
+
this.myTrades = trades;
|
|
953
|
+
}
|
|
954
|
+
trades.append(trade);
|
|
955
|
+
client.resolve(trades, messageHash);
|
|
956
|
+
const symbolSpecificMessageHash = messageHash + ':' + symbol;
|
|
957
|
+
client.resolve(trades, symbolSpecificMessageHash);
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* @method
|
|
961
|
+
* @name modetrade#watchPositions
|
|
962
|
+
* @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/private/position-push
|
|
963
|
+
* @description watch all open positions
|
|
964
|
+
* @param {string[]} [symbols] list of unified market symbols
|
|
965
|
+
* @param since timestamp in ms of the earliest position to fetch
|
|
966
|
+
* @param limit the maximum number of positions to fetch
|
|
967
|
+
* @param {object} params extra parameters specific to the exchange API endpoint
|
|
968
|
+
* @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
|
|
969
|
+
*/
|
|
970
|
+
async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
|
|
971
|
+
await this.loadMarkets();
|
|
972
|
+
const messageHashes = [];
|
|
973
|
+
symbols = this.marketSymbols(symbols);
|
|
974
|
+
if (!this.isEmpty(symbols)) {
|
|
975
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
976
|
+
const symbol = symbols[i];
|
|
977
|
+
messageHashes.push('positions::' + symbol);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
else {
|
|
981
|
+
messageHashes.push('positions');
|
|
982
|
+
}
|
|
983
|
+
const url = this.urls['api']['ws']['private'] + '/' + this.accountId;
|
|
984
|
+
const client = this.client(url);
|
|
985
|
+
this.setPositionsCache(client, symbols);
|
|
986
|
+
const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
|
|
987
|
+
const awaitPositionsSnapshot = this.handleOption('watchPositions', 'awaitPositionsSnapshot', true);
|
|
988
|
+
if (fetchPositionsSnapshot && awaitPositionsSnapshot && this.positions === undefined) {
|
|
989
|
+
const snapshot = await client.future('fetchPositionsSnapshot');
|
|
990
|
+
return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
|
|
991
|
+
}
|
|
992
|
+
const request = {
|
|
993
|
+
'event': 'subscribe',
|
|
994
|
+
'topic': 'position',
|
|
995
|
+
};
|
|
996
|
+
const newPositions = await this.watchPrivateMultiple(messageHashes, request, params);
|
|
997
|
+
if (this.newUpdates) {
|
|
998
|
+
return newPositions;
|
|
999
|
+
}
|
|
1000
|
+
return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
|
|
1001
|
+
}
|
|
1002
|
+
setPositionsCache(client, type, symbols = undefined) {
|
|
1003
|
+
const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', false);
|
|
1004
|
+
if (fetchPositionsSnapshot) {
|
|
1005
|
+
const messageHash = 'fetchPositionsSnapshot';
|
|
1006
|
+
if (!(messageHash in client.futures)) {
|
|
1007
|
+
client.future(messageHash);
|
|
1008
|
+
this.spawn(this.loadPositionsSnapshot, client, messageHash);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
else {
|
|
1012
|
+
this.positions = new ArrayCacheBySymbolBySide();
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
async loadPositionsSnapshot(client, messageHash) {
|
|
1016
|
+
const positions = await this.fetchPositions();
|
|
1017
|
+
this.positions = new ArrayCacheBySymbolBySide();
|
|
1018
|
+
const cache = this.positions;
|
|
1019
|
+
for (let i = 0; i < positions.length; i++) {
|
|
1020
|
+
const position = positions[i];
|
|
1021
|
+
const contracts = this.safeString(position, 'contracts', '0');
|
|
1022
|
+
if (Precise.stringGt(contracts, '0')) {
|
|
1023
|
+
cache.append(position);
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
// don't remove the future from the .futures cache
|
|
1027
|
+
const future = client.futures[messageHash];
|
|
1028
|
+
future.resolve(cache);
|
|
1029
|
+
client.resolve(cache, 'positions');
|
|
1030
|
+
}
|
|
1031
|
+
handlePositions(client, message) {
|
|
1032
|
+
//
|
|
1033
|
+
// {
|
|
1034
|
+
// "topic":"position",
|
|
1035
|
+
// "ts":1705292345255,
|
|
1036
|
+
// "data":{
|
|
1037
|
+
// "positions":[
|
|
1038
|
+
// {
|
|
1039
|
+
// "symbol":"PERP_ETH_USDC",
|
|
1040
|
+
// "positionQty":3.1408,
|
|
1041
|
+
// "costPosition":5706.51952,
|
|
1042
|
+
// "lastSumUnitaryFunding":0.804,
|
|
1043
|
+
// "sumUnitaryFundingVersion":0,
|
|
1044
|
+
// "pendingLongQty":0.0,
|
|
1045
|
+
// "pendingShortQty":-1.0,
|
|
1046
|
+
// "settlePrice":1816.9,
|
|
1047
|
+
// "averageOpenPrice":1804.51490427,
|
|
1048
|
+
// "unsettledPnl":-2.79856,
|
|
1049
|
+
// "pnl24H":-338.90179488,
|
|
1050
|
+
// "fee24H":4.242423,
|
|
1051
|
+
// "markPrice":1816.2,
|
|
1052
|
+
// "estLiqPrice":0.0,
|
|
1053
|
+
// "version":179967,
|
|
1054
|
+
// "imrwithOrders":0.1,
|
|
1055
|
+
// "mmrwithOrders":0.05,
|
|
1056
|
+
// "mmr":0.05,
|
|
1057
|
+
// "imr":0.1,
|
|
1058
|
+
// "timestamp":1685154032762
|
|
1059
|
+
// }
|
|
1060
|
+
// ]
|
|
1061
|
+
// }
|
|
1062
|
+
// }
|
|
1063
|
+
//
|
|
1064
|
+
const data = this.safeDict(message, 'data', {});
|
|
1065
|
+
const rawPositions = this.safeList(data, 'positions', []);
|
|
1066
|
+
if (this.positions === undefined) {
|
|
1067
|
+
this.positions = new ArrayCacheBySymbolBySide();
|
|
1068
|
+
}
|
|
1069
|
+
const cache = this.positions;
|
|
1070
|
+
const newPositions = [];
|
|
1071
|
+
for (let i = 0; i < rawPositions.length; i++) {
|
|
1072
|
+
const rawPosition = rawPositions[i];
|
|
1073
|
+
const marketId = this.safeString(rawPosition, 'symbol');
|
|
1074
|
+
const market = this.safeMarket(marketId);
|
|
1075
|
+
const position = this.parseWsPosition(rawPosition, market);
|
|
1076
|
+
newPositions.push(position);
|
|
1077
|
+
cache.append(position);
|
|
1078
|
+
const messageHash = 'positions::' + market['symbol'];
|
|
1079
|
+
client.resolve(position, messageHash);
|
|
1080
|
+
}
|
|
1081
|
+
client.resolve(newPositions, 'positions');
|
|
1082
|
+
}
|
|
1083
|
+
parseWsPosition(position, market = undefined) {
|
|
1084
|
+
//
|
|
1085
|
+
// {
|
|
1086
|
+
// "symbol":"PERP_ETH_USDC",
|
|
1087
|
+
// "positionQty":3.1408,
|
|
1088
|
+
// "costPosition":5706.51952,
|
|
1089
|
+
// "lastSumUnitaryFunding":0.804,
|
|
1090
|
+
// "sumUnitaryFundingVersion":0,
|
|
1091
|
+
// "pendingLongQty":0.0,
|
|
1092
|
+
// "pendingShortQty":-1.0,
|
|
1093
|
+
// "settlePrice":1816.9,
|
|
1094
|
+
// "averageOpenPrice":1804.51490427,
|
|
1095
|
+
// "unsettledPnl":-2.79856,
|
|
1096
|
+
// "pnl24H":-338.90179488,
|
|
1097
|
+
// "fee24H":4.242423,
|
|
1098
|
+
// "markPrice":1816.2,
|
|
1099
|
+
// "estLiqPrice":0.0,
|
|
1100
|
+
// "version":179967,
|
|
1101
|
+
// "imrwithOrders":0.1,
|
|
1102
|
+
// "mmrwithOrders":0.05,
|
|
1103
|
+
// "mmr":0.05,
|
|
1104
|
+
// "imr":0.1,
|
|
1105
|
+
// "timestamp":1685154032762
|
|
1106
|
+
// }
|
|
1107
|
+
//
|
|
1108
|
+
const contract = this.safeString(position, 'symbol');
|
|
1109
|
+
market = this.safeMarket(contract, market);
|
|
1110
|
+
let size = this.safeString(position, 'positionQty');
|
|
1111
|
+
let side = undefined;
|
|
1112
|
+
if (Precise.stringGt(size, '0')) {
|
|
1113
|
+
side = 'long';
|
|
1114
|
+
}
|
|
1115
|
+
else {
|
|
1116
|
+
side = 'short';
|
|
1117
|
+
}
|
|
1118
|
+
const contractSize = this.safeString(market, 'contractSize');
|
|
1119
|
+
const markPrice = this.safeString(position, 'markPrice');
|
|
1120
|
+
const timestamp = this.safeInteger(position, 'timestamp');
|
|
1121
|
+
const entryPrice = this.safeString(position, 'averageOpenPrice');
|
|
1122
|
+
const unrealisedPnl = this.safeString(position, 'unsettledPnl');
|
|
1123
|
+
size = Precise.stringAbs(size);
|
|
1124
|
+
const notional = Precise.stringMul(size, markPrice);
|
|
1125
|
+
return this.safePosition({
|
|
1126
|
+
'info': position,
|
|
1127
|
+
'id': undefined,
|
|
1128
|
+
'symbol': this.safeString(market, 'symbol'),
|
|
1129
|
+
'timestamp': timestamp,
|
|
1130
|
+
'datetime': this.iso8601(timestamp),
|
|
1131
|
+
'lastUpdateTimestamp': undefined,
|
|
1132
|
+
'initialMargin': undefined,
|
|
1133
|
+
'initialMarginPercentage': undefined,
|
|
1134
|
+
'maintenanceMargin': undefined,
|
|
1135
|
+
'maintenanceMarginPercentage': undefined,
|
|
1136
|
+
'entryPrice': this.parseNumber(entryPrice),
|
|
1137
|
+
'notional': this.parseNumber(notional),
|
|
1138
|
+
'leverage': undefined,
|
|
1139
|
+
'unrealizedPnl': this.parseNumber(unrealisedPnl),
|
|
1140
|
+
'contracts': this.parseNumber(size),
|
|
1141
|
+
'contractSize': this.parseNumber(contractSize),
|
|
1142
|
+
'marginRatio': undefined,
|
|
1143
|
+
'liquidationPrice': this.safeNumber(position, 'estLiqPrice'),
|
|
1144
|
+
'markPrice': this.parseNumber(markPrice),
|
|
1145
|
+
'lastPrice': undefined,
|
|
1146
|
+
'collateral': undefined,
|
|
1147
|
+
'marginMode': 'cross',
|
|
1148
|
+
'marginType': undefined,
|
|
1149
|
+
'side': side,
|
|
1150
|
+
'percentage': undefined,
|
|
1151
|
+
'hedged': undefined,
|
|
1152
|
+
'stopLossPrice': undefined,
|
|
1153
|
+
'takeProfitPrice': undefined,
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
/**
|
|
1157
|
+
* @method
|
|
1158
|
+
* @name modetrade#watchBalance
|
|
1159
|
+
* @description watch balance and get the amount of funds available for trading or funds locked in orders
|
|
1160
|
+
* @see https://orderly.network/docs/build-on-evm/evm-api/websocket-api/private/balance
|
|
1161
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1162
|
+
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
|
|
1163
|
+
*/
|
|
1164
|
+
async watchBalance(params = {}) {
|
|
1165
|
+
await this.loadMarkets();
|
|
1166
|
+
const topic = 'balance';
|
|
1167
|
+
const messageHash = topic;
|
|
1168
|
+
const request = {
|
|
1169
|
+
'event': 'subscribe',
|
|
1170
|
+
'topic': topic,
|
|
1171
|
+
};
|
|
1172
|
+
const message = this.extend(request, params);
|
|
1173
|
+
return await this.watchPrivate(messageHash, message);
|
|
1174
|
+
}
|
|
1175
|
+
handleBalance(client, message) {
|
|
1176
|
+
//
|
|
1177
|
+
// {
|
|
1178
|
+
// "topic":"balance",
|
|
1179
|
+
// "ts":1651836695254,
|
|
1180
|
+
// "data":{
|
|
1181
|
+
// "balances":{
|
|
1182
|
+
// "USDC":{
|
|
1183
|
+
// "holding":5555815.47398272,
|
|
1184
|
+
// "frozen":0,
|
|
1185
|
+
// "interest":0,
|
|
1186
|
+
// "pendingShortQty":0,
|
|
1187
|
+
// "pendingExposure":0,
|
|
1188
|
+
// "pendingLongQty":0,
|
|
1189
|
+
// "pendingLongExposure":0,
|
|
1190
|
+
// "version":894,
|
|
1191
|
+
// "staked":51370692,
|
|
1192
|
+
// "unbonding":0,
|
|
1193
|
+
// "vault":0,
|
|
1194
|
+
// "averageOpenPrice":0.00000574,
|
|
1195
|
+
// "pnl24H":0,
|
|
1196
|
+
// "fee24H":0.01914,
|
|
1197
|
+
// "markPrice":0.31885
|
|
1198
|
+
// }
|
|
1199
|
+
// }
|
|
1200
|
+
// }
|
|
1201
|
+
// }
|
|
1202
|
+
//
|
|
1203
|
+
const data = this.safeDict(message, 'data', {});
|
|
1204
|
+
const balances = this.safeDict(data, 'balances', {});
|
|
1205
|
+
const keys = Object.keys(balances);
|
|
1206
|
+
const ts = this.safeInteger(message, 'ts');
|
|
1207
|
+
this.balance['info'] = data;
|
|
1208
|
+
this.balance['timestamp'] = ts;
|
|
1209
|
+
this.balance['datetime'] = this.iso8601(ts);
|
|
1210
|
+
for (let i = 0; i < keys.length; i++) {
|
|
1211
|
+
const key = keys[i];
|
|
1212
|
+
const value = balances[key];
|
|
1213
|
+
const code = this.safeCurrencyCode(key);
|
|
1214
|
+
const account = (code in this.balance) ? this.balance[code] : this.account();
|
|
1215
|
+
const total = this.safeString(value, 'holding');
|
|
1216
|
+
const used = this.safeString(value, 'frozen');
|
|
1217
|
+
account['total'] = total;
|
|
1218
|
+
account['used'] = used;
|
|
1219
|
+
account['free'] = Precise.stringSub(total, used);
|
|
1220
|
+
this.balance[code] = account;
|
|
1221
|
+
}
|
|
1222
|
+
this.balance = this.safeBalance(this.balance);
|
|
1223
|
+
client.resolve(this.balance, 'balance');
|
|
1224
|
+
}
|
|
1225
|
+
handleErrorMessage(client, message) {
|
|
1226
|
+
//
|
|
1227
|
+
// {"id":"1","event":"subscribe","success":false,"ts":1710780997216,"errorMsg":"Auth is needed."}
|
|
1228
|
+
//
|
|
1229
|
+
if (!('success' in message)) {
|
|
1230
|
+
return false;
|
|
1231
|
+
}
|
|
1232
|
+
const success = this.safeBool(message, 'success');
|
|
1233
|
+
if (success) {
|
|
1234
|
+
return false;
|
|
1235
|
+
}
|
|
1236
|
+
const errorMessage = this.safeString(message, 'errorMsg');
|
|
1237
|
+
try {
|
|
1238
|
+
if (errorMessage !== undefined) {
|
|
1239
|
+
const feedback = this.id + ' ' + this.json(message);
|
|
1240
|
+
this.throwExactlyMatchedException(this.exceptions['exact'], errorMessage, feedback);
|
|
1241
|
+
}
|
|
1242
|
+
return false;
|
|
1243
|
+
}
|
|
1244
|
+
catch (error) {
|
|
1245
|
+
if (error instanceof AuthenticationError) {
|
|
1246
|
+
const messageHash = 'authenticated';
|
|
1247
|
+
client.reject(error, messageHash);
|
|
1248
|
+
if (messageHash in client.subscriptions) {
|
|
1249
|
+
delete client.subscriptions[messageHash];
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
else {
|
|
1253
|
+
client.reject(error);
|
|
1254
|
+
}
|
|
1255
|
+
return true;
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
handleMessage(client, message) {
|
|
1259
|
+
if (this.handleErrorMessage(client, message)) {
|
|
1260
|
+
return;
|
|
1261
|
+
}
|
|
1262
|
+
const methods = {
|
|
1263
|
+
'ping': this.handlePing,
|
|
1264
|
+
'pong': this.handlePong,
|
|
1265
|
+
'subscribe': this.handleSubscribe,
|
|
1266
|
+
'orderbook': this.handleOrderBook,
|
|
1267
|
+
'ticker': this.handleTicker,
|
|
1268
|
+
'tickers': this.handleTickers,
|
|
1269
|
+
'kline': this.handleOHLCV,
|
|
1270
|
+
'trade': this.handleTrade,
|
|
1271
|
+
'auth': this.handleAuth,
|
|
1272
|
+
'executionreport': this.handleOrderUpdate,
|
|
1273
|
+
'algoexecutionreport': this.handleOrderUpdate,
|
|
1274
|
+
'position': this.handlePositions,
|
|
1275
|
+
'balance': this.handleBalance,
|
|
1276
|
+
'bbos': this.handleBidAsk,
|
|
1277
|
+
};
|
|
1278
|
+
const event = this.safeString(message, 'event');
|
|
1279
|
+
let method = this.safeValue(methods, event);
|
|
1280
|
+
if (method !== undefined) {
|
|
1281
|
+
method.call(this, client, message);
|
|
1282
|
+
return;
|
|
1283
|
+
}
|
|
1284
|
+
const topic = this.safeString(message, 'topic');
|
|
1285
|
+
if (topic !== undefined) {
|
|
1286
|
+
method = this.safeValue(methods, topic);
|
|
1287
|
+
if (method !== undefined) {
|
|
1288
|
+
method.call(this, client, message);
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
const splitTopic = topic.split('@');
|
|
1292
|
+
const splitLength = splitTopic.length;
|
|
1293
|
+
if (splitLength === 2) {
|
|
1294
|
+
const name = this.safeString(splitTopic, 1);
|
|
1295
|
+
method = this.safeValue(methods, name);
|
|
1296
|
+
if (method !== undefined) {
|
|
1297
|
+
method.call(this, client, message);
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
const splitName = name.split('_');
|
|
1301
|
+
const splitNameLength = splitTopic.length;
|
|
1302
|
+
if (splitNameLength === 2) {
|
|
1303
|
+
method = this.safeValue(methods, this.safeString(splitName, 0));
|
|
1304
|
+
if (method !== undefined) {
|
|
1305
|
+
method.call(this, client, message);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
ping(client) {
|
|
1312
|
+
return { 'event': 'ping' };
|
|
1313
|
+
}
|
|
1314
|
+
handlePing(client, message) {
|
|
1315
|
+
return { 'event': 'pong' };
|
|
1316
|
+
}
|
|
1317
|
+
handlePong(client, message) {
|
|
1318
|
+
//
|
|
1319
|
+
// { event: "pong", ts: 1614667590000 }
|
|
1320
|
+
//
|
|
1321
|
+
client.lastPong = this.milliseconds();
|
|
1322
|
+
return message;
|
|
1323
|
+
}
|
|
1324
|
+
handleSubscribe(client, message) {
|
|
1325
|
+
//
|
|
1326
|
+
// {
|
|
1327
|
+
// "id": "666888",
|
|
1328
|
+
// "event": "subscribe",
|
|
1329
|
+
// "success": true,
|
|
1330
|
+
// "ts": 1657117712212
|
|
1331
|
+
// }
|
|
1332
|
+
//
|
|
1333
|
+
return message;
|
|
1334
|
+
}
|
|
1335
|
+
}
|