ccxt 4.5.30 → 4.5.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/ccxt.browser.min.js +18 -18
- package/dist/cjs/ccxt.js +6 -4
- package/dist/cjs/src/aster.js +3802 -0
- package/dist/cjs/src/backpack.js +1 -1
- package/dist/cjs/src/base/Exchange.js +35 -2
- package/dist/cjs/src/base/ws/WsClient.js +1 -0
- package/dist/cjs/src/bigone.js +1 -1
- package/dist/cjs/src/binance.js +1 -0
- package/dist/cjs/src/bingx.js +73 -0
- package/dist/cjs/src/cryptomus.js +1 -1
- package/dist/cjs/src/gate.js +52 -6
- package/dist/cjs/src/hyperliquid.js +9 -1
- package/dist/cjs/src/kucoin.js +63 -64
- package/dist/cjs/src/okx.js +14 -5
- package/dist/cjs/src/pro/apex.js +2 -2
- package/dist/cjs/src/pro/ascendex.js +1 -1
- package/dist/cjs/src/pro/aster.js +1046 -0
- package/dist/cjs/src/pro/bingx.js +1 -1
- package/dist/cjs/src/pro/bybit.js +1 -1
- package/dist/cjs/src/pro/cryptocom.js +1 -1
- package/dist/cjs/src/pro/dydx.js +1 -1
- package/dist/cjs/src/pro/htx.js +1 -1
- package/dist/cjs/src/pro/hyperliquid.js +1 -1
- package/dist/cjs/src/pro/p2b.js +1 -1
- package/dist/cjs/src/pro/toobit.js +1 -1
- package/js/ccxt.d.ts +8 -5
- package/js/ccxt.js +6 -4
- package/js/src/abstract/aster.d.ts +88 -0
- package/js/src/abstract/binance.d.ts +1 -0
- package/js/src/abstract/binancecoinm.d.ts +1 -0
- package/js/src/abstract/binanceus.d.ts +1 -0
- package/js/src/abstract/binanceusdm.d.ts +1 -0
- package/js/src/abstract/kucoin.d.ts +2 -0
- package/js/src/abstract/kucoinfutures.d.ts +2 -0
- package/js/src/aster.d.ts +563 -0
- package/js/src/aster.js +3801 -0
- package/js/src/backpack.js +1 -1
- package/js/src/base/Exchange.d.ts +4 -0
- package/js/src/base/Exchange.js +35 -1
- package/js/src/base/ws/WsClient.js +1 -0
- package/js/src/bigone.js +1 -1
- package/js/src/binance.d.ts +1 -1
- package/js/src/binance.js +1 -0
- package/js/src/bingx.d.ts +12 -1
- package/js/src/bingx.js +73 -0
- package/js/src/cryptomus.js +1 -1
- package/js/src/exmo.d.ts +1 -1
- package/js/src/gate.js +52 -6
- package/js/src/hyperliquid.d.ts +1 -0
- package/js/src/hyperliquid.js +9 -1
- package/js/src/kucoin.d.ts +5 -3
- package/js/src/kucoin.js +63 -64
- package/js/src/okx.js +14 -5
- package/js/src/pro/apex.js +2 -2
- package/js/src/pro/ascendex.js +1 -1
- package/js/src/pro/aster.d.ts +273 -0
- package/js/src/pro/aster.js +1045 -0
- package/js/src/pro/bingx.js +1 -1
- package/js/src/pro/bybit.js +1 -1
- package/js/src/pro/cryptocom.js +1 -1
- package/js/src/pro/dydx.js +1 -1
- package/js/src/pro/htx.js +1 -1
- package/js/src/pro/hyperliquid.js +1 -1
- package/js/src/pro/p2b.js +1 -1
- package/js/src/pro/toobit.js +1 -1
- package/package.json +1 -1
- package/dist/cjs/src/oceanex.js +0 -1125
- package/js/src/abstract/oceanex.d.ts +0 -30
- package/js/src/oceanex.d.ts +0 -231
- package/js/src/oceanex.js +0 -1124
- /package/dist/cjs/src/abstract/{oceanex.js → aster.js} +0 -0
- /package/js/src/abstract/{oceanex.js → aster.js} +0 -0
|
@@ -0,0 +1,1045 @@
|
|
|
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 asterRest from '../aster.js';
|
|
9
|
+
import { ArgumentsRequired } from '../base/errors.js';
|
|
10
|
+
import { ArrayCache, ArrayCacheByTimestamp } from '../base/ws/Cache.js';
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
export default class aster extends asterRest {
|
|
13
|
+
describe() {
|
|
14
|
+
return this.deepExtend(super.describe(), {
|
|
15
|
+
'has': {
|
|
16
|
+
'ws': true,
|
|
17
|
+
'watchBalance': false,
|
|
18
|
+
'watchBidsAsks': true,
|
|
19
|
+
'watchTicker': true,
|
|
20
|
+
'watchTickers': true,
|
|
21
|
+
'watchMarkPrice': true,
|
|
22
|
+
'watchMarkPrices': true,
|
|
23
|
+
'watchTrades': true,
|
|
24
|
+
'watchTradesForSymbols': true,
|
|
25
|
+
'watchOrderBook': true,
|
|
26
|
+
'watchOrderBookForSymbols': true,
|
|
27
|
+
'watchOHLCV': true,
|
|
28
|
+
'watchOHLCVForSymbols': true,
|
|
29
|
+
'unWatchTicker': true,
|
|
30
|
+
'unWatchTickers': true,
|
|
31
|
+
'unWatchMarkPrice': true,
|
|
32
|
+
'unWatchMarkPrices': true,
|
|
33
|
+
'unWatchBidsAsks': true,
|
|
34
|
+
'unWatchTrades': true,
|
|
35
|
+
'unWatchTradesForSymbols': true,
|
|
36
|
+
'unWatchOrderBook': true,
|
|
37
|
+
'unWatchOrderBookForSymbols': true,
|
|
38
|
+
'unWatchOHLCV': true,
|
|
39
|
+
'unWatchOHLCVForSymbols': true,
|
|
40
|
+
},
|
|
41
|
+
'urls': {
|
|
42
|
+
'api': {
|
|
43
|
+
'ws': {
|
|
44
|
+
'spot': 'wss://sstream.asterdex.com/stream',
|
|
45
|
+
'swap': 'wss://fstream.asterdex.com/stream',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
'options': {},
|
|
50
|
+
'streaming': {},
|
|
51
|
+
'exceptions': {},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
getAccountTypeFromSubscriptions(subscriptions) {
|
|
55
|
+
let accountType = '';
|
|
56
|
+
for (let i = 0; i < subscriptions.length; i++) {
|
|
57
|
+
const subscription = subscriptions[i];
|
|
58
|
+
if ((subscription === 'spot') || (subscription === 'swap')) {
|
|
59
|
+
accountType = subscription;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return accountType;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* @method
|
|
67
|
+
* @name aster#watchTicker
|
|
68
|
+
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
69
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#full-ticker-per-symbol
|
|
70
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#individual-symbol-ticker-streams
|
|
71
|
+
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
72
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
73
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
74
|
+
*/
|
|
75
|
+
async watchTicker(symbol, params = {}) {
|
|
76
|
+
params['callerMethodName'] = 'watchTicker';
|
|
77
|
+
await this.loadMarkets();
|
|
78
|
+
symbol = this.safeSymbol(symbol);
|
|
79
|
+
const tickers = await this.watchTickers([symbol], params);
|
|
80
|
+
return tickers[symbol];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* @method
|
|
84
|
+
* @name aster#unWatchTicker
|
|
85
|
+
* @description unWatches a price ticker
|
|
86
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#full-ticker-per-symbol
|
|
87
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#individual-symbol-ticker-streams
|
|
88
|
+
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
89
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
90
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
91
|
+
*/
|
|
92
|
+
async unWatchTicker(symbol, params = {}) {
|
|
93
|
+
params['callerMethodName'] = 'unWatchTicker';
|
|
94
|
+
return await this.unWatchTickers([symbol], params);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* @method
|
|
98
|
+
* @name aster#watchTickers
|
|
99
|
+
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
|
100
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#full-ticker-per-symbol
|
|
101
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#individual-symbol-ticker-streams
|
|
102
|
+
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
|
|
103
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
104
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
105
|
+
*/
|
|
106
|
+
async watchTickers(symbols = undefined, params = {}) {
|
|
107
|
+
await this.loadMarkets();
|
|
108
|
+
symbols = this.marketSymbols(symbols, undefined, true, true, true);
|
|
109
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
110
|
+
const type = this.safeString(firstMarket, 'type', 'swap');
|
|
111
|
+
const symbolsLength = symbols.length;
|
|
112
|
+
let methodName = undefined;
|
|
113
|
+
[methodName, params] = this.handleParamString(params, 'callerMethodName', 'watchTickers');
|
|
114
|
+
params = this.omit(params, 'callerMethodName');
|
|
115
|
+
if (symbolsLength === 0) {
|
|
116
|
+
throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
|
|
117
|
+
}
|
|
118
|
+
const url = this.urls['api']['ws'][type];
|
|
119
|
+
const subscriptionArgs = [];
|
|
120
|
+
const messageHashes = [];
|
|
121
|
+
const request = {
|
|
122
|
+
'method': 'SUBSCRIBE',
|
|
123
|
+
'params': subscriptionArgs,
|
|
124
|
+
};
|
|
125
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
126
|
+
const symbol = symbols[i];
|
|
127
|
+
const market = this.market(symbol);
|
|
128
|
+
subscriptionArgs.push(this.safeStringLower(market, 'id') + '@ticker');
|
|
129
|
+
messageHashes.push('ticker:' + market['symbol']);
|
|
130
|
+
}
|
|
131
|
+
const newTicker = await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
|
|
132
|
+
if (this.newUpdates) {
|
|
133
|
+
const result = {};
|
|
134
|
+
result[newTicker['symbol']] = newTicker;
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
return this.filterByArray(this.tickers, 'symbol', symbols);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* @method
|
|
141
|
+
* @name aster#unWatchTickers
|
|
142
|
+
* @description unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
|
143
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#full-ticker-per-symbol
|
|
144
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#individual-symbol-ticker-streams
|
|
145
|
+
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
|
|
146
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
147
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
148
|
+
*/
|
|
149
|
+
async unWatchTickers(symbols = undefined, params = {}) {
|
|
150
|
+
await this.loadMarkets();
|
|
151
|
+
symbols = this.marketSymbols(symbols, undefined, true, true, true);
|
|
152
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
153
|
+
const type = this.safeString(firstMarket, 'type', 'swap');
|
|
154
|
+
const symbolsLength = symbols.length;
|
|
155
|
+
let methodName = undefined;
|
|
156
|
+
[methodName, params] = this.handleParamString(params, 'callerMethodName', 'unWatchTickers');
|
|
157
|
+
params = this.omit(params, 'callerMethodName');
|
|
158
|
+
if (symbolsLength === 0) {
|
|
159
|
+
throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
|
|
160
|
+
}
|
|
161
|
+
const url = this.urls['api']['ws'][type];
|
|
162
|
+
const subscriptionArgs = [];
|
|
163
|
+
const messageHashes = [];
|
|
164
|
+
const request = {
|
|
165
|
+
'method': 'UNSUBSCRIBE',
|
|
166
|
+
'params': subscriptionArgs,
|
|
167
|
+
};
|
|
168
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
169
|
+
const symbol = symbols[i];
|
|
170
|
+
const market = this.market(symbol);
|
|
171
|
+
subscriptionArgs.push(this.safeStringLower(market, 'id') + '@ticker');
|
|
172
|
+
messageHashes.push('unsubscribe:ticker:' + market['symbol']);
|
|
173
|
+
}
|
|
174
|
+
return await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* @method
|
|
178
|
+
* @name aster#watchMarkPrice
|
|
179
|
+
* @description watches a mark price for a specific market
|
|
180
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#mark-price-stream
|
|
181
|
+
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
182
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
183
|
+
* @param {boolean} [params.use1sFreq] *default is true* if set to true, the mark price will be updated every second, otherwise every 3 seconds
|
|
184
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
185
|
+
*/
|
|
186
|
+
async watchMarkPrice(symbol, params = {}) {
|
|
187
|
+
params['callerMethodName'] = 'watchMarkPrice';
|
|
188
|
+
await this.loadMarkets();
|
|
189
|
+
symbol = this.safeSymbol(symbol);
|
|
190
|
+
const tickers = await this.watchMarkPrices([symbol], params);
|
|
191
|
+
return tickers[symbol];
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* @method
|
|
195
|
+
* @name aster#unWatchMarkPrice
|
|
196
|
+
* @description unWatches a mark price for a specific market
|
|
197
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#mark-price-stream
|
|
198
|
+
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
199
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
200
|
+
* @param {boolean} [params.use1sFreq] *default is true* if set to true, the mark price will be updated every second, otherwise every 3 seconds
|
|
201
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
202
|
+
*/
|
|
203
|
+
async unWatchMarkPrice(symbol, params = {}) {
|
|
204
|
+
params['callerMethodName'] = 'unWatchMarkPrice';
|
|
205
|
+
return await this.unWatchMarkPrices([symbol], params);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* @method
|
|
209
|
+
* @name aster#watchMarkPrices
|
|
210
|
+
* @description watches the mark price for all markets
|
|
211
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#mark-price-stream
|
|
212
|
+
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
|
|
213
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
214
|
+
* @param {boolean} [params.use1sFreq] *default is true* if set to true, the mark price will be updated every second, otherwise every 3 seconds
|
|
215
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
216
|
+
*/
|
|
217
|
+
async watchMarkPrices(symbols = undefined, params = {}) {
|
|
218
|
+
await this.loadMarkets();
|
|
219
|
+
symbols = this.marketSymbols(symbols, undefined, true, true, true);
|
|
220
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
221
|
+
const type = this.safeString(firstMarket, 'type', 'swap');
|
|
222
|
+
const symbolsLength = symbols.length;
|
|
223
|
+
let methodName = undefined;
|
|
224
|
+
[methodName, params] = this.handleParamString(params, 'callerMethodName', 'watchMarkPrices');
|
|
225
|
+
params = this.omit(params, 'callerMethodName');
|
|
226
|
+
if (symbolsLength === 0) {
|
|
227
|
+
throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
|
|
228
|
+
}
|
|
229
|
+
const url = this.urls['api']['ws'][type];
|
|
230
|
+
const subscriptionArgs = [];
|
|
231
|
+
const messageHashes = [];
|
|
232
|
+
const request = {
|
|
233
|
+
'method': 'SUBSCRIBE',
|
|
234
|
+
'params': subscriptionArgs,
|
|
235
|
+
};
|
|
236
|
+
const use1sFreq = this.safeBool(params, 'use1sFreq', true);
|
|
237
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
238
|
+
const symbol = symbols[i];
|
|
239
|
+
const market = this.market(symbol);
|
|
240
|
+
const suffix = (use1sFreq) ? '@1s' : '';
|
|
241
|
+
subscriptionArgs.push(this.safeStringLower(market, 'id') + '@markPrice' + suffix);
|
|
242
|
+
messageHashes.push('ticker:' + market['symbol']);
|
|
243
|
+
}
|
|
244
|
+
const newTicker = await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
|
|
245
|
+
if (this.newUpdates) {
|
|
246
|
+
const result = {};
|
|
247
|
+
result[newTicker['symbol']] = newTicker;
|
|
248
|
+
return result;
|
|
249
|
+
}
|
|
250
|
+
return this.filterByArray(this.tickers, 'symbol', symbols);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* @method
|
|
254
|
+
* @name aster#unWatchMarkPrices
|
|
255
|
+
* @description watches the mark price for all markets
|
|
256
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#mark-price-stream
|
|
257
|
+
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
|
|
258
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
259
|
+
* @param {boolean} [params.use1sFreq] *default is true* if set to true, the mark price will be updated every second, otherwise every 3 seconds
|
|
260
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
261
|
+
*/
|
|
262
|
+
async unWatchMarkPrices(symbols = undefined, params = {}) {
|
|
263
|
+
await this.loadMarkets();
|
|
264
|
+
symbols = this.marketSymbols(symbols, undefined, true, true, true);
|
|
265
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
266
|
+
const type = this.safeString(firstMarket, 'type', 'swap');
|
|
267
|
+
const symbolsLength = symbols.length;
|
|
268
|
+
let methodName = undefined;
|
|
269
|
+
[methodName, params] = this.handleParamString(params, 'callerMethodName', 'unWatchMarkPrices');
|
|
270
|
+
params = this.omit(params, 'callerMethodName');
|
|
271
|
+
if (symbolsLength === 0) {
|
|
272
|
+
throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
|
|
273
|
+
}
|
|
274
|
+
const url = this.urls['api']['ws'][type];
|
|
275
|
+
const subscriptionArgs = [];
|
|
276
|
+
const messageHashes = [];
|
|
277
|
+
const request = {
|
|
278
|
+
'method': 'UNSUBSCRIBE',
|
|
279
|
+
'params': subscriptionArgs,
|
|
280
|
+
};
|
|
281
|
+
const use1sFreq = this.safeBool(params, 'use1sFreq', true);
|
|
282
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
283
|
+
const symbol = symbols[i];
|
|
284
|
+
const market = this.market(symbol);
|
|
285
|
+
const suffix = (use1sFreq) ? '@1s' : '';
|
|
286
|
+
subscriptionArgs.push(this.safeStringLower(market, 'id') + '@markPrice' + suffix);
|
|
287
|
+
messageHashes.push('unsubscribe:ticker:' + market['symbol']);
|
|
288
|
+
}
|
|
289
|
+
return await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
|
|
290
|
+
}
|
|
291
|
+
handleTicker(client, message) {
|
|
292
|
+
//
|
|
293
|
+
// {
|
|
294
|
+
// "stream": "trumpusdt@ticker",
|
|
295
|
+
// "data": {
|
|
296
|
+
// "e": "24hrTicker",
|
|
297
|
+
// "E": 1754451187277,
|
|
298
|
+
// "s": "CAKEUSDT",
|
|
299
|
+
// "p": "-0.08800",
|
|
300
|
+
// "P": "-3.361",
|
|
301
|
+
// "w": "2.58095",
|
|
302
|
+
// "c": "2.53000",
|
|
303
|
+
// "Q": "5",
|
|
304
|
+
// "o": "2.61800",
|
|
305
|
+
// "h": "2.64700",
|
|
306
|
+
// "l": "2.52400",
|
|
307
|
+
// "v": "15775",
|
|
308
|
+
// "q": "40714.46000",
|
|
309
|
+
// "O": 1754364780000,
|
|
310
|
+
// "C": 1754451187274,
|
|
311
|
+
// "F": 6571389,
|
|
312
|
+
// "L": 6574507,
|
|
313
|
+
// "n": 3119
|
|
314
|
+
// }
|
|
315
|
+
// }
|
|
316
|
+
// {
|
|
317
|
+
// "stream": "btcusdt@markPrice",
|
|
318
|
+
// "data": {
|
|
319
|
+
// "e": "markPriceUpdate",
|
|
320
|
+
// "E": 1754660466000,
|
|
321
|
+
// "s": "BTCUSDT",
|
|
322
|
+
// "p": "116809.60000000",
|
|
323
|
+
// "P": "116595.54012838",
|
|
324
|
+
// "i": "116836.93534884",
|
|
325
|
+
// "r": "0.00010000",
|
|
326
|
+
// "T": 1754668800000
|
|
327
|
+
// }
|
|
328
|
+
// }
|
|
329
|
+
//
|
|
330
|
+
const subscriptions = client.subscriptions;
|
|
331
|
+
const subscriptionsKeys = Object.keys(subscriptions);
|
|
332
|
+
const marketType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
|
|
333
|
+
const ticker = this.safeDict(message, 'data');
|
|
334
|
+
const parsed = this.parseWsTicker(ticker, marketType);
|
|
335
|
+
const symbol = parsed['symbol'];
|
|
336
|
+
const messageHash = 'ticker:' + symbol;
|
|
337
|
+
this.tickers[symbol] = parsed;
|
|
338
|
+
client.resolve(this.tickers[symbol], messageHash);
|
|
339
|
+
}
|
|
340
|
+
parseWsTicker(message, marketType) {
|
|
341
|
+
const event = this.safeString(message, 'e');
|
|
342
|
+
const part = event.split('@');
|
|
343
|
+
const channel = this.safeString(part, 1);
|
|
344
|
+
const marketId = this.safeString(message, 's');
|
|
345
|
+
const timestamp = this.safeInteger(message, 'E');
|
|
346
|
+
const market = this.safeMarket(marketId, undefined, undefined, marketType);
|
|
347
|
+
const last = this.safeString(message, 'c');
|
|
348
|
+
if (channel === 'markPriceUpdate') {
|
|
349
|
+
return this.safeTicker({
|
|
350
|
+
'symbol': market['symbol'],
|
|
351
|
+
'timestamp': timestamp,
|
|
352
|
+
'datetime': this.iso8601(timestamp),
|
|
353
|
+
'info': message,
|
|
354
|
+
'markPrice': this.safeString(message, 'p'),
|
|
355
|
+
'indexPrice': this.safeString(message, 'i'),
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
return this.safeTicker({
|
|
359
|
+
'symbol': market['symbol'],
|
|
360
|
+
'timestamp': timestamp,
|
|
361
|
+
'datetime': this.iso8601(timestamp),
|
|
362
|
+
'high': this.safeString(message, 'h'),
|
|
363
|
+
'low': this.safeString(message, 'l'),
|
|
364
|
+
'bid': undefined,
|
|
365
|
+
'bidVolume': undefined,
|
|
366
|
+
'ask': undefined,
|
|
367
|
+
'askVolume': undefined,
|
|
368
|
+
'vwap': this.safeString(message, 'w'),
|
|
369
|
+
'open': this.safeString(message, 'o'),
|
|
370
|
+
'close': last,
|
|
371
|
+
'last': last,
|
|
372
|
+
'previousClose': undefined,
|
|
373
|
+
'change': this.safeString(message, 'p'),
|
|
374
|
+
'percentage': this.safeString(message, 'P'),
|
|
375
|
+
'average': undefined,
|
|
376
|
+
'baseVolume': this.safeString(message, 'v'),
|
|
377
|
+
'quoteVolume': this.safeString(message, 'q'),
|
|
378
|
+
'info': message,
|
|
379
|
+
}, market);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* @method
|
|
383
|
+
* @name aster#watchBidsAsks
|
|
384
|
+
* @description watches best bid & ask for symbols
|
|
385
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#best-order-book-information-by-symbol
|
|
386
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#individual-symbol-book-ticker-streams
|
|
387
|
+
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
|
|
388
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
389
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
390
|
+
*/
|
|
391
|
+
async watchBidsAsks(symbols = undefined, params = {}) {
|
|
392
|
+
await this.loadMarkets();
|
|
393
|
+
symbols = this.marketSymbols(symbols, undefined, true, true, true);
|
|
394
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
395
|
+
const type = this.safeString(firstMarket, 'type', 'swap');
|
|
396
|
+
const symbolsLength = symbols.length;
|
|
397
|
+
if (symbolsLength === 0) {
|
|
398
|
+
throw new ArgumentsRequired(this.id + ' watchBidsAsks() requires a non-empty array of symbols');
|
|
399
|
+
}
|
|
400
|
+
const url = this.urls['api']['ws'][type];
|
|
401
|
+
const subscriptionArgs = [];
|
|
402
|
+
const messageHashes = [];
|
|
403
|
+
const request = {
|
|
404
|
+
'method': 'SUBSCRIBE',
|
|
405
|
+
'params': subscriptionArgs,
|
|
406
|
+
};
|
|
407
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
408
|
+
const symbol = symbols[i];
|
|
409
|
+
const market = this.market(symbol);
|
|
410
|
+
subscriptionArgs.push(this.safeStringLower(market, 'id') + '@bookTicker');
|
|
411
|
+
messageHashes.push('bidask:' + market['symbol']);
|
|
412
|
+
}
|
|
413
|
+
const newTicker = await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
|
|
414
|
+
if (this.newUpdates) {
|
|
415
|
+
const result = {};
|
|
416
|
+
result[newTicker['symbol']] = newTicker;
|
|
417
|
+
return result;
|
|
418
|
+
}
|
|
419
|
+
return this.filterByArray(this.bidsasks, 'symbol', symbols);
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* @method
|
|
423
|
+
* @name aster#unWatchBidsAsks
|
|
424
|
+
* @description unWatches best bid & ask for symbols
|
|
425
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#best-order-book-information-by-symbol
|
|
426
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#individual-symbol-book-ticker-streams
|
|
427
|
+
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
|
|
428
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
429
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
430
|
+
*/
|
|
431
|
+
async unWatchBidsAsks(symbols = undefined, params = {}) {
|
|
432
|
+
await this.loadMarkets();
|
|
433
|
+
symbols = this.marketSymbols(symbols, undefined, true, true, true);
|
|
434
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
435
|
+
const type = this.safeString(firstMarket, 'type', 'swap');
|
|
436
|
+
const symbolsLength = symbols.length;
|
|
437
|
+
if (symbolsLength === 0) {
|
|
438
|
+
throw new ArgumentsRequired(this.id + ' unWatchBidsAsks() requires a non-empty array of symbols');
|
|
439
|
+
}
|
|
440
|
+
const url = this.urls['api']['ws'][type];
|
|
441
|
+
const subscriptionArgs = [];
|
|
442
|
+
const messageHashes = [];
|
|
443
|
+
const request = {
|
|
444
|
+
'method': 'UNSUBSCRIBE',
|
|
445
|
+
'params': subscriptionArgs,
|
|
446
|
+
};
|
|
447
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
448
|
+
const symbol = symbols[i];
|
|
449
|
+
const market = this.market(symbol);
|
|
450
|
+
subscriptionArgs.push(this.safeStringLower(market, 'id') + '@bookTicker');
|
|
451
|
+
messageHashes.push('unsubscribe:bidask:' + market['symbol']);
|
|
452
|
+
}
|
|
453
|
+
return await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
|
|
454
|
+
}
|
|
455
|
+
handleBidAsk(client, message) {
|
|
456
|
+
//
|
|
457
|
+
// {
|
|
458
|
+
// "stream": "btcusdt@bookTicker",
|
|
459
|
+
// "data": {
|
|
460
|
+
// "e": "bookTicker",
|
|
461
|
+
// "u": 157240846459,
|
|
462
|
+
// "s": "BTCUSDT",
|
|
463
|
+
// "b": "122046.7",
|
|
464
|
+
// "B": "1.084",
|
|
465
|
+
// "a": "122046.8",
|
|
466
|
+
// "A": "0.001",
|
|
467
|
+
// "T": 1754896692922,
|
|
468
|
+
// "E": 1754896692926
|
|
469
|
+
// }
|
|
470
|
+
// }
|
|
471
|
+
//
|
|
472
|
+
const subscriptions = client.subscriptions;
|
|
473
|
+
const subscriptionsKeys = Object.keys(subscriptions);
|
|
474
|
+
const marketType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
|
|
475
|
+
const data = this.safeDict(message, 'data', {});
|
|
476
|
+
const marketId = this.safeString(data, 's');
|
|
477
|
+
const market = this.safeMarket(marketId, undefined, undefined, marketType);
|
|
478
|
+
const ticker = this.parseWsBidAsk(data, market);
|
|
479
|
+
const symbol = ticker['symbol'];
|
|
480
|
+
this.bidsasks[symbol] = ticker;
|
|
481
|
+
const messageHash = 'bidask:' + symbol;
|
|
482
|
+
client.resolve(ticker, messageHash);
|
|
483
|
+
}
|
|
484
|
+
parseWsBidAsk(message, market = undefined) {
|
|
485
|
+
const timestamp = this.safeInteger(message, 'T');
|
|
486
|
+
return this.safeTicker({
|
|
487
|
+
'symbol': market['symbol'],
|
|
488
|
+
'timestamp': timestamp,
|
|
489
|
+
'datetime': this.iso8601(timestamp),
|
|
490
|
+
'ask': this.safeString(message, 'a'),
|
|
491
|
+
'askVolume': this.safeString(message, 'A'),
|
|
492
|
+
'bid': this.safeString(message, 'b'),
|
|
493
|
+
'bidVolume': this.safeString(message, 'B'),
|
|
494
|
+
'info': message,
|
|
495
|
+
}, market);
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* @method
|
|
499
|
+
* @name aster#watchTrades
|
|
500
|
+
* @description watches information on multiple trades made in a market
|
|
501
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#collection-transaction-flow
|
|
502
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#aggregate-trade-streams
|
|
503
|
+
* @param {string} symbol unified market symbol of the market trades were made in
|
|
504
|
+
* @param {int} [since] the earliest time in ms to fetch trades for
|
|
505
|
+
* @param {int} [limit] the maximum number of trade structures to retrieve
|
|
506
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
507
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
|
|
508
|
+
*/
|
|
509
|
+
async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
|
|
510
|
+
params['callerMethodName'] = 'watchTrades';
|
|
511
|
+
return await this.watchTradesForSymbols([symbol], since, limit, params);
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* @method
|
|
515
|
+
* @name aster#unWatchTrades
|
|
516
|
+
* @description unsubscribe from the trades channel
|
|
517
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#collection-transaction-flow
|
|
518
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#aggregate-trade-streams
|
|
519
|
+
* @param {string} symbol unified market symbol of the market trades were made in
|
|
520
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
521
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
|
|
522
|
+
*/
|
|
523
|
+
async unWatchTrades(symbol, params = {}) {
|
|
524
|
+
params['callerMethodName'] = 'unWatchTrades';
|
|
525
|
+
return await this.unWatchTradesForSymbols([symbol], params);
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* @method
|
|
529
|
+
* @name aster#watchTradesForSymbols
|
|
530
|
+
* @description get the list of most recent trades for a list of symbols
|
|
531
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#collection-transaction-flow
|
|
532
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#aggregate-trade-streams
|
|
533
|
+
* @param {string[]} symbols unified symbol of the market to fetch trades for
|
|
534
|
+
* @param {int} [since] timestamp in ms of the earliest trade to fetch
|
|
535
|
+
* @param {int} [limit] the maximum amount of trades to fetch
|
|
536
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
537
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
|
|
538
|
+
*/
|
|
539
|
+
async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
|
|
540
|
+
await this.loadMarkets();
|
|
541
|
+
symbols = this.marketSymbols(symbols, undefined, true, true, true);
|
|
542
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
543
|
+
const type = this.safeString(firstMarket, 'type', 'swap');
|
|
544
|
+
const symbolsLength = symbols.length;
|
|
545
|
+
let methodName = undefined;
|
|
546
|
+
[methodName, params] = this.handleParamString(params, 'callerMethodName', 'watchTradesForSymbols');
|
|
547
|
+
params = this.omit(params, 'callerMethodName');
|
|
548
|
+
if (symbolsLength === 0) {
|
|
549
|
+
throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
|
|
550
|
+
}
|
|
551
|
+
const url = this.urls['api']['ws'][type];
|
|
552
|
+
const subscriptionArgs = [];
|
|
553
|
+
const messageHashes = [];
|
|
554
|
+
const request = {
|
|
555
|
+
'method': 'SUBSCRIBE',
|
|
556
|
+
'params': subscriptionArgs,
|
|
557
|
+
};
|
|
558
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
559
|
+
const symbol = symbols[i];
|
|
560
|
+
const market = this.market(symbol);
|
|
561
|
+
subscriptionArgs.push(this.safeStringLower(market, 'id') + '@aggTrade');
|
|
562
|
+
messageHashes.push('trade:' + market['symbol']);
|
|
563
|
+
}
|
|
564
|
+
const trades = await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
|
|
565
|
+
if (this.newUpdates) {
|
|
566
|
+
const first = this.safeValue(trades, 0);
|
|
567
|
+
const tradeSymbol = this.safeString(first, 'symbol');
|
|
568
|
+
limit = trades.getLimit(tradeSymbol, limit);
|
|
569
|
+
}
|
|
570
|
+
return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* @method
|
|
574
|
+
* @name aster#unWatchTradesForSymbols
|
|
575
|
+
* @description unsubscribe from the trades channel
|
|
576
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#collection-transaction-flow
|
|
577
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#aggregate-trade-streams
|
|
578
|
+
* @param {string[]} symbols unified symbol of the market to fetch trades for
|
|
579
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
580
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
|
|
581
|
+
*/
|
|
582
|
+
async unWatchTradesForSymbols(symbols, params = {}) {
|
|
583
|
+
await this.loadMarkets();
|
|
584
|
+
symbols = this.marketSymbols(symbols, undefined, true, true, true);
|
|
585
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
586
|
+
const type = this.safeString(firstMarket, 'type', 'swap');
|
|
587
|
+
const symbolsLength = symbols.length;
|
|
588
|
+
let methodName = undefined;
|
|
589
|
+
[methodName, params] = this.handleParamString(params, 'callerMethodName', 'unWatchTradesForSymbols');
|
|
590
|
+
params = this.omit(params, 'callerMethodName');
|
|
591
|
+
if (symbolsLength === 0) {
|
|
592
|
+
throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
|
|
593
|
+
}
|
|
594
|
+
const url = this.urls['api']['ws'][type];
|
|
595
|
+
const subscriptionArgs = [];
|
|
596
|
+
const messageHashes = [];
|
|
597
|
+
const request = {
|
|
598
|
+
'method': 'UNSUBSCRIBE',
|
|
599
|
+
'params': subscriptionArgs,
|
|
600
|
+
};
|
|
601
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
602
|
+
const symbol = symbols[i];
|
|
603
|
+
const market = this.market(symbol);
|
|
604
|
+
subscriptionArgs.push(this.safeStringLower(market, 'id') + '@aggTrade');
|
|
605
|
+
messageHashes.push('unsubscribe:trade:' + market['symbol']);
|
|
606
|
+
}
|
|
607
|
+
return await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
|
|
608
|
+
}
|
|
609
|
+
handleTrade(client, message) {
|
|
610
|
+
//
|
|
611
|
+
// {
|
|
612
|
+
// "stream": "btcusdt@aggTrade",
|
|
613
|
+
// "data": {
|
|
614
|
+
// "e": "aggTrade",
|
|
615
|
+
// "E": 1754551358681,
|
|
616
|
+
// "a": 20505890,
|
|
617
|
+
// "s": "BTCUSDT",
|
|
618
|
+
// "p": "114783.7",
|
|
619
|
+
// "q": "0.020",
|
|
620
|
+
// "f": 26024678,
|
|
621
|
+
// "l": 26024682,
|
|
622
|
+
// "T": 1754551358528,
|
|
623
|
+
// "m": false
|
|
624
|
+
// }
|
|
625
|
+
// }
|
|
626
|
+
//
|
|
627
|
+
const subscriptions = client.subscriptions;
|
|
628
|
+
const subscriptionsKeys = Object.keys(subscriptions);
|
|
629
|
+
const marketType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
|
|
630
|
+
const trade = this.safeDict(message, 'data');
|
|
631
|
+
const marketId = this.safeString(trade, 's');
|
|
632
|
+
const market = this.safeMarket(marketId, undefined, undefined, marketType);
|
|
633
|
+
const parsed = this.parseWsTrade(trade, market);
|
|
634
|
+
const symbol = parsed['symbol'];
|
|
635
|
+
let stored = this.safeValue(this.trades, symbol);
|
|
636
|
+
if (stored === undefined) {
|
|
637
|
+
const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
|
|
638
|
+
stored = new ArrayCache(limit);
|
|
639
|
+
this.trades[symbol] = stored;
|
|
640
|
+
}
|
|
641
|
+
stored.append(parsed);
|
|
642
|
+
const messageHash = 'trade' + ':' + symbol;
|
|
643
|
+
client.resolve(stored, messageHash);
|
|
644
|
+
}
|
|
645
|
+
parseWsTrade(trade, market = undefined) {
|
|
646
|
+
const timestamp = this.safeInteger(trade, 'T');
|
|
647
|
+
const symbol = market['symbol'];
|
|
648
|
+
const amountString = this.safeString(trade, 'q');
|
|
649
|
+
const priceString = this.safeString(trade, 'p');
|
|
650
|
+
const isMaker = this.safeBool(trade, 'm');
|
|
651
|
+
let takerOrMaker = undefined;
|
|
652
|
+
if (isMaker !== undefined) {
|
|
653
|
+
takerOrMaker = isMaker ? 'maker' : 'taker';
|
|
654
|
+
}
|
|
655
|
+
return this.safeTrade({
|
|
656
|
+
'id': this.safeString(trade, 'a'),
|
|
657
|
+
'info': trade,
|
|
658
|
+
'timestamp': timestamp,
|
|
659
|
+
'datetime': this.iso8601(timestamp),
|
|
660
|
+
'symbol': symbol,
|
|
661
|
+
'order': undefined,
|
|
662
|
+
'type': undefined,
|
|
663
|
+
'side': undefined,
|
|
664
|
+
'takerOrMaker': takerOrMaker,
|
|
665
|
+
'price': priceString,
|
|
666
|
+
'amount': amountString,
|
|
667
|
+
'cost': undefined,
|
|
668
|
+
'fee': undefined,
|
|
669
|
+
}, market);
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* @method
|
|
673
|
+
* @name aster#watchOrderBook
|
|
674
|
+
* @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
675
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#limited-depth-information
|
|
676
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#partial-book-depth-streams
|
|
677
|
+
* @param {string} symbol unified symbol of the market to fetch the order book for
|
|
678
|
+
* @param {int} [limit] the maximum amount of order book entries to return.
|
|
679
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
680
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
681
|
+
*/
|
|
682
|
+
async watchOrderBook(symbol, limit = undefined, params = {}) {
|
|
683
|
+
params['callerMethodName'] = 'watchOrderBook';
|
|
684
|
+
return await this.watchOrderBookForSymbols([symbol], limit, params);
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* @method
|
|
688
|
+
* @name aster#unWatchOrderBook
|
|
689
|
+
* @description unsubscribe from the orderbook channel
|
|
690
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#limited-depth-information
|
|
691
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#partial-book-depth-streams
|
|
692
|
+
* @param {string} symbol symbol of the market to unwatch the trades for
|
|
693
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
694
|
+
* @param {int} [params.limit] orderbook limit, default is undefined
|
|
695
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
696
|
+
*/
|
|
697
|
+
async unWatchOrderBook(symbol, params = {}) {
|
|
698
|
+
params['callerMethodName'] = 'unWatchOrderBook';
|
|
699
|
+
return await this.unWatchOrderBookForSymbols([symbol], params);
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* @method
|
|
703
|
+
* @name aster#watchOrderBookForSymbols
|
|
704
|
+
* @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
705
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#limited-depth-information
|
|
706
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#partial-book-depth-streams
|
|
707
|
+
* @param {string[]} symbols unified array of symbols
|
|
708
|
+
* @param {int} [limit] the maximum amount of order book entries to return.
|
|
709
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
710
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
711
|
+
*/
|
|
712
|
+
async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
|
|
713
|
+
await this.loadMarkets();
|
|
714
|
+
symbols = this.marketSymbols(symbols, undefined, true, true, true);
|
|
715
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
716
|
+
const type = this.safeString(firstMarket, 'type', 'swap');
|
|
717
|
+
const symbolsLength = symbols.length;
|
|
718
|
+
let methodName = undefined;
|
|
719
|
+
[methodName, params] = this.handleParamString(params, 'callerMethodName', 'watchOrderBookForSymbols');
|
|
720
|
+
params = this.omit(params, 'callerMethodName');
|
|
721
|
+
if (symbolsLength === 0) {
|
|
722
|
+
throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
|
|
723
|
+
}
|
|
724
|
+
const url = this.urls['api']['ws'][type];
|
|
725
|
+
const subscriptionArgs = [];
|
|
726
|
+
const messageHashes = [];
|
|
727
|
+
const request = {
|
|
728
|
+
'method': 'SUBSCRIBE',
|
|
729
|
+
'params': subscriptionArgs,
|
|
730
|
+
};
|
|
731
|
+
if (limit === undefined || (limit !== 5 && limit !== 10 && limit !== 20)) {
|
|
732
|
+
limit = 20;
|
|
733
|
+
}
|
|
734
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
735
|
+
const symbol = symbols[i];
|
|
736
|
+
const market = this.market(symbol);
|
|
737
|
+
subscriptionArgs.push(this.safeStringLower(market, 'id') + '@depth' + limit);
|
|
738
|
+
messageHashes.push('orderbook:' + market['symbol']);
|
|
739
|
+
}
|
|
740
|
+
const orderbook = await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
|
|
741
|
+
return orderbook.limit();
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* @method
|
|
745
|
+
* @name aster#unWatchOrderBookForSymbols
|
|
746
|
+
* @description unsubscribe from the orderbook channel
|
|
747
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#limited-depth-information
|
|
748
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#partial-book-depth-streams
|
|
749
|
+
* @param {string[]} symbols unified symbol of the market to unwatch the trades for
|
|
750
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
751
|
+
* @param {int} [params.limit] orderbook limit, default is undefined
|
|
752
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
753
|
+
*/
|
|
754
|
+
async unWatchOrderBookForSymbols(symbols, params = {}) {
|
|
755
|
+
await this.loadMarkets();
|
|
756
|
+
symbols = this.marketSymbols(symbols, undefined, true, true, true);
|
|
757
|
+
const firstMarket = this.getMarketFromSymbols(symbols);
|
|
758
|
+
const type = this.safeString(firstMarket, 'type', 'swap');
|
|
759
|
+
const symbolsLength = symbols.length;
|
|
760
|
+
let methodName = undefined;
|
|
761
|
+
[methodName, params] = this.handleParamString(params, 'callerMethodName', 'unWatchOrderBookForSymbols');
|
|
762
|
+
params = this.omit(params, 'callerMethodName');
|
|
763
|
+
if (symbolsLength === 0) {
|
|
764
|
+
throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
|
|
765
|
+
}
|
|
766
|
+
const url = this.urls['api']['ws'][type];
|
|
767
|
+
const subscriptionArgs = [];
|
|
768
|
+
const messageHashes = [];
|
|
769
|
+
const request = {
|
|
770
|
+
'method': 'UNSUBSCRIBE',
|
|
771
|
+
'params': subscriptionArgs,
|
|
772
|
+
};
|
|
773
|
+
let limit = this.safeNumber(params, 'limit');
|
|
774
|
+
params = this.omit(params, 'limit');
|
|
775
|
+
if (limit === undefined || (limit !== 5 && limit !== 10 && limit !== 20)) {
|
|
776
|
+
limit = 20;
|
|
777
|
+
}
|
|
778
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
779
|
+
const symbol = symbols[i];
|
|
780
|
+
const market = this.market(symbol);
|
|
781
|
+
subscriptionArgs.push(this.safeStringLower(market, 'id') + '@depth' + limit);
|
|
782
|
+
messageHashes.push('unsubscribe:orderbook:' + market['symbol']);
|
|
783
|
+
}
|
|
784
|
+
return await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
|
|
785
|
+
}
|
|
786
|
+
handleOrderBook(client, message) {
|
|
787
|
+
//
|
|
788
|
+
// {
|
|
789
|
+
// "stream": "btcusdt@depth20",
|
|
790
|
+
// "data": {
|
|
791
|
+
// "e": "depthUpdate",
|
|
792
|
+
// "E": 1754556878284,
|
|
793
|
+
// "T": 1754556878031,
|
|
794
|
+
// "s": "BTCUSDT",
|
|
795
|
+
// "U": 156391349814,
|
|
796
|
+
// "u": 156391349814,
|
|
797
|
+
// "pu": 156391348236,
|
|
798
|
+
// "b": [
|
|
799
|
+
// [
|
|
800
|
+
// "114988.3",
|
|
801
|
+
// "0.147"
|
|
802
|
+
// ]
|
|
803
|
+
// ],
|
|
804
|
+
// "a": [
|
|
805
|
+
// [
|
|
806
|
+
// "114988.4",
|
|
807
|
+
// "1.060"
|
|
808
|
+
// ]
|
|
809
|
+
// ]
|
|
810
|
+
// }
|
|
811
|
+
// }
|
|
812
|
+
//
|
|
813
|
+
const subscriptions = client.subscriptions;
|
|
814
|
+
const subscriptionsKeys = Object.keys(subscriptions);
|
|
815
|
+
const marketType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
|
|
816
|
+
const data = this.safeDict(message, 'data');
|
|
817
|
+
const marketId = this.safeString(data, 's');
|
|
818
|
+
const timestamp = this.safeInteger(data, 'T');
|
|
819
|
+
const market = this.safeMarket(marketId, undefined, undefined, marketType);
|
|
820
|
+
const symbol = market['symbol'];
|
|
821
|
+
if (!(symbol in this.orderbooks)) {
|
|
822
|
+
this.orderbooks[symbol] = this.orderBook();
|
|
823
|
+
}
|
|
824
|
+
const orderbook = this.orderbooks[symbol];
|
|
825
|
+
const snapshot = this.parseOrderBook(data, symbol, timestamp, 'b', 'a');
|
|
826
|
+
orderbook.reset(snapshot);
|
|
827
|
+
const messageHash = 'orderbook' + ':' + symbol;
|
|
828
|
+
this.orderbooks[symbol] = orderbook;
|
|
829
|
+
client.resolve(orderbook, messageHash);
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* @method
|
|
833
|
+
* @name aster#watchOHLCV
|
|
834
|
+
* @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
835
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#k-line-streams
|
|
836
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#klinecandlestick-streams
|
|
837
|
+
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
838
|
+
* @param {string} timeframe the length of time each candle represents
|
|
839
|
+
* @param {int} [since] timestamp in ms of the earliest candle to fetch
|
|
840
|
+
* @param {int} [limit] the maximum amount of candles to fetch
|
|
841
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
842
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
843
|
+
*/
|
|
844
|
+
async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
|
845
|
+
params['callerMethodName'] = 'watchOHLCV';
|
|
846
|
+
await this.loadMarkets();
|
|
847
|
+
symbol = this.safeSymbol(symbol);
|
|
848
|
+
const result = await this.watchOHLCVForSymbols([[symbol, timeframe]], since, limit, params);
|
|
849
|
+
return result[symbol][timeframe];
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* @method
|
|
853
|
+
* @name aster#unWatchOHLCV
|
|
854
|
+
* @description unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
855
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#k-line-streams
|
|
856
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#klinecandlestick-streams
|
|
857
|
+
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
858
|
+
* @param {string} timeframe the length of time each candle represents
|
|
859
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
860
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
861
|
+
*/
|
|
862
|
+
async unWatchOHLCV(symbol, timeframe = '1m', params = {}) {
|
|
863
|
+
params['callerMethodName'] = 'unWatchOHLCV';
|
|
864
|
+
return await this.unWatchOHLCVForSymbols([[symbol, timeframe]], params);
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* @method
|
|
868
|
+
* @name aster#watchOHLCVForSymbols
|
|
869
|
+
* @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
870
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#k-line-streams
|
|
871
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#klinecandlestick-streams
|
|
872
|
+
* @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
|
|
873
|
+
* @param {int} [since] timestamp in ms of the earliest candle to fetch
|
|
874
|
+
* @param {int} [limit] the maximum amount of candles to fetch
|
|
875
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
876
|
+
* @returns {object} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
877
|
+
*/
|
|
878
|
+
async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
|
|
879
|
+
await this.loadMarkets();
|
|
880
|
+
const symbolsLength = symbolsAndTimeframes.length;
|
|
881
|
+
let methodName = undefined;
|
|
882
|
+
[methodName, params] = this.handleParamString(params, 'callerMethodName', 'watchOHLCVForSymbols');
|
|
883
|
+
params = this.omit(params, 'callerMethodName');
|
|
884
|
+
if (symbolsLength === 0) {
|
|
885
|
+
throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
|
|
886
|
+
}
|
|
887
|
+
const symbols = this.getListFromObjectValues(symbolsAndTimeframes, 0);
|
|
888
|
+
const marketSymbols = this.marketSymbols(symbols, undefined, false, true, true);
|
|
889
|
+
const firstMarket = this.market(marketSymbols[0]);
|
|
890
|
+
const type = this.safeString(firstMarket, 'type', 'swap');
|
|
891
|
+
const url = this.urls['api']['ws'][type];
|
|
892
|
+
const subscriptionArgs = [];
|
|
893
|
+
const messageHashes = [];
|
|
894
|
+
const request = {
|
|
895
|
+
'method': 'SUBSCRIBE',
|
|
896
|
+
'params': subscriptionArgs,
|
|
897
|
+
};
|
|
898
|
+
for (let i = 0; i < symbolsAndTimeframes.length; i++) {
|
|
899
|
+
const data = symbolsAndTimeframes[i];
|
|
900
|
+
let symbolString = this.safeString(data, 0);
|
|
901
|
+
const market = this.market(symbolString);
|
|
902
|
+
symbolString = market['symbol'];
|
|
903
|
+
const unfiedTimeframe = this.safeString(data, 1);
|
|
904
|
+
const timeframeId = this.safeString(this.timeframes, unfiedTimeframe, unfiedTimeframe);
|
|
905
|
+
subscriptionArgs.push(this.safeStringLower(market, 'id') + '@kline_' + timeframeId);
|
|
906
|
+
messageHashes.push('ohlcv:' + market['symbol'] + ':' + unfiedTimeframe);
|
|
907
|
+
}
|
|
908
|
+
const [symbol, timeframe, stored] = await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
|
|
909
|
+
if (this.newUpdates) {
|
|
910
|
+
limit = stored.getLimit(symbol, limit);
|
|
911
|
+
}
|
|
912
|
+
const filtered = this.filterBySinceLimit(stored, since, limit, 0, true);
|
|
913
|
+
return this.createOHLCVObject(symbol, timeframe, filtered);
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* @method
|
|
917
|
+
* @name aster#unWatchOHLCVForSymbols
|
|
918
|
+
* @description unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
919
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#k-line-streams
|
|
920
|
+
* @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#klinecandlestick-streams
|
|
921
|
+
* @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
|
|
922
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
923
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
924
|
+
*/
|
|
925
|
+
async unWatchOHLCVForSymbols(symbolsAndTimeframes, params = {}) {
|
|
926
|
+
await this.loadMarkets();
|
|
927
|
+
const symbolsLength = symbolsAndTimeframes.length;
|
|
928
|
+
let methodName = undefined;
|
|
929
|
+
[methodName, params] = this.handleParamString(params, 'callerMethodName', 'unWatchOHLCVForSymbols');
|
|
930
|
+
params = this.omit(params, 'callerMethodName');
|
|
931
|
+
if (symbolsLength === 0) {
|
|
932
|
+
throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a non-empty array of symbols');
|
|
933
|
+
}
|
|
934
|
+
const symbols = this.getListFromObjectValues(symbolsAndTimeframes, 0);
|
|
935
|
+
const marketSymbols = this.marketSymbols(symbols, undefined, false, true, true);
|
|
936
|
+
const firstMarket = this.market(marketSymbols[0]);
|
|
937
|
+
const type = this.safeString(firstMarket, 'type', 'swap');
|
|
938
|
+
const url = this.urls['api']['ws'][type];
|
|
939
|
+
const subscriptionArgs = [];
|
|
940
|
+
const messageHashes = [];
|
|
941
|
+
const request = {
|
|
942
|
+
'method': 'UNSUBSCRIBE',
|
|
943
|
+
'params': subscriptionArgs,
|
|
944
|
+
};
|
|
945
|
+
for (let i = 0; i < symbolsAndTimeframes.length; i++) {
|
|
946
|
+
const data = symbolsAndTimeframes[i];
|
|
947
|
+
let symbolString = this.safeString(data, 0);
|
|
948
|
+
const market = this.market(symbolString);
|
|
949
|
+
symbolString = market['symbol'];
|
|
950
|
+
const unfiedTimeframe = this.safeString(data, 1);
|
|
951
|
+
const timeframeId = this.safeString(this.timeframes, unfiedTimeframe, unfiedTimeframe);
|
|
952
|
+
subscriptionArgs.push(this.safeStringLower(market, 'id') + '@kline_' + timeframeId);
|
|
953
|
+
messageHashes.push('unsubscribe:ohlcv:' + market['symbol'] + ':' + unfiedTimeframe);
|
|
954
|
+
}
|
|
955
|
+
return await this.watchMultiple(url, messageHashes, this.extend(request, params), [type]);
|
|
956
|
+
}
|
|
957
|
+
handleOHLCV(client, message) {
|
|
958
|
+
//
|
|
959
|
+
// {
|
|
960
|
+
// "stream": "btcusdt@kline_1m",
|
|
961
|
+
// "data": {
|
|
962
|
+
// "e": "kline",
|
|
963
|
+
// "E": 1754655777119,
|
|
964
|
+
// "s": "BTCUSDT",
|
|
965
|
+
// "k": {
|
|
966
|
+
// "t": 1754655720000,
|
|
967
|
+
// "T": 1754655779999,
|
|
968
|
+
// "s": "BTCUSDT",
|
|
969
|
+
// "i": "1m",
|
|
970
|
+
// "f": 26032629,
|
|
971
|
+
// "L": 26032629,
|
|
972
|
+
// "o": "116546.9",
|
|
973
|
+
// "c": "116546.9",
|
|
974
|
+
// "h": "116546.9",
|
|
975
|
+
// "l": "116546.9",
|
|
976
|
+
// "v": "0.011",
|
|
977
|
+
// "n": 1,
|
|
978
|
+
// "x": false,
|
|
979
|
+
// "q": "1282.0159",
|
|
980
|
+
// "V": "0.000",
|
|
981
|
+
// "Q": "0.0000",
|
|
982
|
+
// "B": "0"
|
|
983
|
+
// }
|
|
984
|
+
// }
|
|
985
|
+
// }
|
|
986
|
+
//
|
|
987
|
+
const subscriptions = client.subscriptions;
|
|
988
|
+
const subscriptionsKeys = Object.keys(subscriptions);
|
|
989
|
+
const marketType = this.getAccountTypeFromSubscriptions(subscriptionsKeys);
|
|
990
|
+
const data = this.safeDict(message, 'data');
|
|
991
|
+
const marketId = this.safeString(data, 's');
|
|
992
|
+
const market = this.safeMarket(marketId, undefined, undefined, marketType);
|
|
993
|
+
const symbol = market['symbol'];
|
|
994
|
+
const kline = this.safeDict(data, 'k');
|
|
995
|
+
const timeframeId = this.safeString(kline, 'i');
|
|
996
|
+
const timeframe = this.findTimeframe(timeframeId);
|
|
997
|
+
const ohlcvsByTimeframe = this.safeValue(this.ohlcvs, symbol);
|
|
998
|
+
if (ohlcvsByTimeframe === undefined) {
|
|
999
|
+
this.ohlcvs[symbol] = {};
|
|
1000
|
+
}
|
|
1001
|
+
if (this.safeValue(ohlcvsByTimeframe, timeframe) === undefined) {
|
|
1002
|
+
const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
|
|
1003
|
+
this.ohlcvs[symbol][timeframe] = new ArrayCacheByTimestamp(limit);
|
|
1004
|
+
}
|
|
1005
|
+
const stored = this.ohlcvs[symbol][timeframe];
|
|
1006
|
+
const parsed = this.parseWsOHLCV(kline);
|
|
1007
|
+
stored.append(parsed);
|
|
1008
|
+
const messageHash = 'ohlcv:' + symbol + ':' + timeframe;
|
|
1009
|
+
const resolveData = [symbol, timeframe, stored];
|
|
1010
|
+
client.resolve(resolveData, messageHash);
|
|
1011
|
+
}
|
|
1012
|
+
parseWsOHLCV(ohlcv, market = undefined) {
|
|
1013
|
+
return [
|
|
1014
|
+
this.safeInteger(ohlcv, 't'),
|
|
1015
|
+
this.safeNumber(ohlcv, 'o'),
|
|
1016
|
+
this.safeNumber(ohlcv, 'h'),
|
|
1017
|
+
this.safeNumber(ohlcv, 'l'),
|
|
1018
|
+
this.safeNumber(ohlcv, 'c'),
|
|
1019
|
+
this.safeNumber(ohlcv, 'v'),
|
|
1020
|
+
];
|
|
1021
|
+
}
|
|
1022
|
+
handleMessage(client, message) {
|
|
1023
|
+
const stream = this.safeString(message, 'stream');
|
|
1024
|
+
if (stream !== undefined) {
|
|
1025
|
+
const part = stream.split('@');
|
|
1026
|
+
let topic = this.safeString(part, 1, '');
|
|
1027
|
+
const part2 = topic.split('_');
|
|
1028
|
+
topic = this.safeString(part2, 0, '');
|
|
1029
|
+
const methods = {
|
|
1030
|
+
'ticker': this.handleTicker,
|
|
1031
|
+
'aggTrade': this.handleTrade,
|
|
1032
|
+
'depth5': this.handleOrderBook,
|
|
1033
|
+
'depth10': this.handleOrderBook,
|
|
1034
|
+
'depth20': this.handleOrderBook,
|
|
1035
|
+
'kline': this.handleOHLCV,
|
|
1036
|
+
'markPrice': this.handleTicker,
|
|
1037
|
+
'bookTicker': this.handleBidAsk,
|
|
1038
|
+
};
|
|
1039
|
+
const method = this.safeValue(methods, topic);
|
|
1040
|
+
if (method !== undefined) {
|
|
1041
|
+
method.call(this, client, message);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
}
|