ccxt 4.1.45 → 4.1.46
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 +3 -3
- package/dist/ccxt.browser.js +1591 -188
- package/dist/ccxt.browser.min.js +2 -2
- package/dist/cjs/ccxt.js +1 -1
- package/dist/cjs/src/base/Exchange.js +11 -3
- package/dist/cjs/src/base/ws/Cache.js +50 -0
- package/dist/cjs/src/bitvavo.js +6 -5
- package/dist/cjs/src/bybit.js +84 -132
- package/dist/cjs/src/cryptocom.js +1 -1
- package/dist/cjs/src/gate.js +3 -1
- package/dist/cjs/src/huobi.js +1 -2
- package/dist/cjs/src/okx.js +19 -2
- package/dist/cjs/src/pro/binance.js +203 -1
- package/dist/cjs/src/pro/bitget.js +181 -0
- package/dist/cjs/src/pro/bybit.js +154 -10
- package/dist/cjs/src/pro/cryptocom.js +131 -1
- package/dist/cjs/src/pro/gate.js +161 -0
- package/dist/cjs/src/pro/huobi.js +128 -4
- package/dist/cjs/src/pro/krakenfutures.js +129 -0
- package/dist/cjs/src/pro/kucoinfutures.js +182 -0
- package/dist/cjs/src/pro/okx.js +121 -0
- package/js/ccxt.d.ts +1 -1
- package/js/ccxt.js +1 -1
- package/js/src/base/Exchange.d.ts +4 -1
- package/js/src/base/Exchange.js +11 -3
- package/js/src/base/ws/Cache.d.ts +5 -1
- package/js/src/base/ws/Cache.js +50 -1
- package/js/src/bitvavo.js +6 -5
- package/js/src/bybit.d.ts +0 -2
- package/js/src/bybit.js +84 -132
- package/js/src/cryptocom.js +1 -1
- package/js/src/gate.js +3 -1
- package/js/src/huobi.js +1 -2
- package/js/src/okx.js +19 -2
- package/js/src/pro/binance.d.ts +6 -0
- package/js/src/pro/binance.js +204 -2
- package/js/src/pro/bitget.d.ts +3 -0
- package/js/src/pro/bitget.js +182 -1
- package/js/src/pro/bybit.d.ts +5 -1
- package/js/src/pro/bybit.js +156 -12
- package/js/src/pro/cryptocom.d.ts +4 -0
- package/js/src/pro/cryptocom.js +132 -2
- package/js/src/pro/gate.d.ts +5 -0
- package/js/src/pro/gate.js +162 -1
- package/js/src/pro/huobi.d.ts +2 -0
- package/js/src/pro/huobi.js +129 -5
- package/js/src/pro/krakenfutures.d.ts +3 -0
- package/js/src/pro/krakenfutures.js +129 -0
- package/js/src/pro/kucoinfutures.d.ts +5 -0
- package/js/src/pro/kucoinfutures.js +182 -0
- package/js/src/pro/okx.d.ts +2 -0
- package/js/src/pro/okx.js +123 -2
- package/package.json +1 -1
- package/skip-tests.json +3 -1
|
@@ -67,14 +67,14 @@ class huobi extends huobi$1 {
|
|
|
67
67
|
},
|
|
68
68
|
},
|
|
69
69
|
'swap': {
|
|
70
|
-
'inverse': {
|
|
71
|
-
'public': 'wss://api.hbdm.vn/swap-ws',
|
|
72
|
-
'private': 'wss://api.hbdm.vn/swap-notification',
|
|
73
|
-
},
|
|
74
70
|
'linear': {
|
|
75
71
|
'public': 'wss://api.hbdm.vn/linear-swap-ws',
|
|
76
72
|
'private': 'wss://api.hbdm.vn/linear-swap-notification',
|
|
77
73
|
},
|
|
74
|
+
'inverse': {
|
|
75
|
+
'public': 'wss://api.hbdm.vn/swap-ws',
|
|
76
|
+
'private': 'wss://api.hbdm.vn/swap-notification',
|
|
77
|
+
},
|
|
78
78
|
},
|
|
79
79
|
},
|
|
80
80
|
},
|
|
@@ -1187,6 +1187,127 @@ class huobi extends huobi$1 {
|
|
|
1187
1187
|
'fee': undefined,
|
|
1188
1188
|
}, market);
|
|
1189
1189
|
}
|
|
1190
|
+
async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1191
|
+
/**
|
|
1192
|
+
* @method
|
|
1193
|
+
* @name huobi#watchPositions
|
|
1194
|
+
* @see https://www.huobi.com/en-in/opend/newApiPages/?id=8cb7de1c-77b5-11ed-9966-0242ac110003
|
|
1195
|
+
* @see https://www.huobi.com/en-in/opend/newApiPages/?id=8cb7df0f-77b5-11ed-9966-0242ac110003
|
|
1196
|
+
* @see https://www.huobi.com/en-in/opend/newApiPages/?id=28c34a7d-77ae-11ed-9966-0242ac110003
|
|
1197
|
+
* @see https://www.huobi.com/en-in/opend/newApiPages/?id=5d5156b5-77b6-11ed-9966-0242ac110003
|
|
1198
|
+
* @description watch all open positions. Note: huobi has one channel for each marginMode and type
|
|
1199
|
+
* @param {[string]|undefined} symbols list of unified market symbols
|
|
1200
|
+
* @param {object} params extra parameters specific to the huobi api endpoint
|
|
1201
|
+
* @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
|
|
1202
|
+
*/
|
|
1203
|
+
await this.loadMarkets();
|
|
1204
|
+
let market = undefined;
|
|
1205
|
+
let messageHash = '';
|
|
1206
|
+
if (!this.isEmpty(symbols)) {
|
|
1207
|
+
market = this.getMarketFromSymbols(symbols);
|
|
1208
|
+
messageHash = '::' + symbols.join(',');
|
|
1209
|
+
}
|
|
1210
|
+
let type = undefined;
|
|
1211
|
+
let subType = undefined;
|
|
1212
|
+
if (market !== undefined) {
|
|
1213
|
+
type = market['type'];
|
|
1214
|
+
subType = market['linear'] ? 'linear' : 'inverse';
|
|
1215
|
+
}
|
|
1216
|
+
else {
|
|
1217
|
+
[type, params] = this.handleMarketTypeAndParams('watchPositions', market, params);
|
|
1218
|
+
if (type === 'spot') {
|
|
1219
|
+
type = 'future';
|
|
1220
|
+
}
|
|
1221
|
+
[subType, params] = this.handleOptionAndParams(params, 'watchPositions', 'subType', subType);
|
|
1222
|
+
}
|
|
1223
|
+
symbols = this.marketSymbols(symbols);
|
|
1224
|
+
let marginMode = undefined;
|
|
1225
|
+
[marginMode, params] = this.handleMarginModeAndParams('watchPositions', params, 'cross');
|
|
1226
|
+
const isLinear = (subType === 'linear');
|
|
1227
|
+
const url = this.getUrlByMarketType(type, isLinear, true);
|
|
1228
|
+
messageHash = marginMode + ':positions' + messageHash;
|
|
1229
|
+
const channel = (marginMode === 'cross') ? 'positions_cross.*' : 'positions.*';
|
|
1230
|
+
const newPositions = await this.subscribePrivate(channel, messageHash, type, subType, params);
|
|
1231
|
+
if (this.newUpdates) {
|
|
1232
|
+
return newPositions;
|
|
1233
|
+
}
|
|
1234
|
+
return this.filterBySymbolsSinceLimit(this.positions[url][marginMode], symbols, since, limit, false);
|
|
1235
|
+
}
|
|
1236
|
+
handlePositions(client, message) {
|
|
1237
|
+
//
|
|
1238
|
+
// {
|
|
1239
|
+
// op: 'notify',
|
|
1240
|
+
// topic: 'positions_cross',
|
|
1241
|
+
// ts: 1696767149650,
|
|
1242
|
+
// event: 'snapshot',
|
|
1243
|
+
// data: [
|
|
1244
|
+
// {
|
|
1245
|
+
// contract_type: 'swap',
|
|
1246
|
+
// pair: 'BTC-USDT',
|
|
1247
|
+
// business_type: 'swap',
|
|
1248
|
+
// liquidation_price: null,
|
|
1249
|
+
// symbol: 'BTC',
|
|
1250
|
+
// contract_code: 'BTC-USDT',
|
|
1251
|
+
// volume: 1,
|
|
1252
|
+
// available: 1,
|
|
1253
|
+
// frozen: 0,
|
|
1254
|
+
// cost_open: 27802.2,
|
|
1255
|
+
// cost_hold: 27802.2,
|
|
1256
|
+
// profit_unreal: 0.0175,
|
|
1257
|
+
// profit_rate: 0.000629446590557581,
|
|
1258
|
+
// profit: 0.0175,
|
|
1259
|
+
// margin_asset: 'USDT',
|
|
1260
|
+
// position_margin: 27.8197,
|
|
1261
|
+
// lever_rate: 1,
|
|
1262
|
+
// direction: 'buy',
|
|
1263
|
+
// last_price: 27819.7,
|
|
1264
|
+
// margin_mode: 'cross',
|
|
1265
|
+
// margin_account: 'USDT',
|
|
1266
|
+
// trade_partition: 'USDT',
|
|
1267
|
+
// position_mode: 'dual_side'
|
|
1268
|
+
// },
|
|
1269
|
+
// ]
|
|
1270
|
+
// }
|
|
1271
|
+
//
|
|
1272
|
+
const url = client.url;
|
|
1273
|
+
const topic = this.safeString(message, 'topic', '');
|
|
1274
|
+
const marginMode = (topic === 'positions_cross') ? 'cross' : 'isolated';
|
|
1275
|
+
if (this.positions === undefined) {
|
|
1276
|
+
this.positions = {};
|
|
1277
|
+
}
|
|
1278
|
+
const clientPositions = this.safeValue(this.positions, url);
|
|
1279
|
+
if (clientPositions === undefined) {
|
|
1280
|
+
this.positions[url] = {};
|
|
1281
|
+
}
|
|
1282
|
+
const clientMarginModePositions = this.safeValue(clientPositions, marginMode);
|
|
1283
|
+
if (clientMarginModePositions === undefined) {
|
|
1284
|
+
this.positions[url][marginMode] = new Cache.ArrayCacheBySymbolBySide();
|
|
1285
|
+
}
|
|
1286
|
+
const cache = this.positions[url][marginMode];
|
|
1287
|
+
const rawPositions = this.safeValue(message, 'data', []);
|
|
1288
|
+
const newPositions = [];
|
|
1289
|
+
const timestamp = this.safeInteger(message, 'ts');
|
|
1290
|
+
for (let i = 0; i < rawPositions.length; i++) {
|
|
1291
|
+
const rawPosition = rawPositions[i];
|
|
1292
|
+
const position = this.parsePosition(rawPosition);
|
|
1293
|
+
position['timestamp'] = timestamp;
|
|
1294
|
+
position['datetime'] = this.iso8601(timestamp);
|
|
1295
|
+
newPositions.push(position);
|
|
1296
|
+
cache.append(position);
|
|
1297
|
+
}
|
|
1298
|
+
const messageHashes = this.findMessageHashes(client, marginMode + ':positions::');
|
|
1299
|
+
for (let i = 0; i < messageHashes.length; i++) {
|
|
1300
|
+
const messageHash = messageHashes[i];
|
|
1301
|
+
const parts = messageHash.split('::');
|
|
1302
|
+
const symbolsString = parts[1];
|
|
1303
|
+
const symbols = symbolsString.split(',');
|
|
1304
|
+
const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
|
|
1305
|
+
if (!this.isEmpty(positions)) {
|
|
1306
|
+
client.resolve(positions, messageHash);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
client.resolve(newPositions, marginMode + ':positions');
|
|
1310
|
+
}
|
|
1190
1311
|
async watchBalance(params = {}) {
|
|
1191
1312
|
/**
|
|
1192
1313
|
* @method
|
|
@@ -1690,6 +1811,9 @@ class huobi extends huobi$1 {
|
|
|
1690
1811
|
if (topic.indexOf('account') >= 0) {
|
|
1691
1812
|
this.handleBalance(client, message);
|
|
1692
1813
|
}
|
|
1814
|
+
if (topic.indexOf('positions') >= 0) {
|
|
1815
|
+
this.handlePositions(client, message);
|
|
1816
|
+
}
|
|
1693
1817
|
}
|
|
1694
1818
|
}
|
|
1695
1819
|
async pong(client, message) {
|
|
@@ -23,6 +23,7 @@ class krakenfutures extends krakenfutures$1 {
|
|
|
23
23
|
// 'watchStatus': true, // https://docs.futures.kraken.com/#websocket-api-public-feeds-heartbeat
|
|
24
24
|
'watchOrders': true,
|
|
25
25
|
'watchMyTrades': true,
|
|
26
|
+
'watchPositions': true,
|
|
26
27
|
},
|
|
27
28
|
'urls': {
|
|
28
29
|
'api': {
|
|
@@ -204,6 +205,133 @@ class krakenfutures extends krakenfutures$1 {
|
|
|
204
205
|
const orderbook = await this.subscribePublic('book', [symbol], params);
|
|
205
206
|
return orderbook.limit();
|
|
206
207
|
}
|
|
208
|
+
async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
|
|
209
|
+
/**
|
|
210
|
+
* @method
|
|
211
|
+
* @name krakenfutures#watchPositions
|
|
212
|
+
* @see https://docs.futures.kraken.com/#websocket-api-private-feeds-open-positions
|
|
213
|
+
* @description watch all open positions
|
|
214
|
+
* @param {[string]|undefined} symbols list of unified market symbols
|
|
215
|
+
* @param {object} params extra parameters specific to the krakenfutures api endpoint
|
|
216
|
+
* @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
|
|
217
|
+
*/
|
|
218
|
+
await this.loadMarkets();
|
|
219
|
+
let messageHash = '';
|
|
220
|
+
symbols = this.marketSymbols(symbols);
|
|
221
|
+
if (!this.isEmpty(symbols)) {
|
|
222
|
+
messageHash = '::' + symbols.join(',');
|
|
223
|
+
}
|
|
224
|
+
messageHash = 'positions' + messageHash;
|
|
225
|
+
const newPositions = await this.subscribePrivate('open_positions', messageHash, params);
|
|
226
|
+
if (this.newUpdates) {
|
|
227
|
+
return newPositions;
|
|
228
|
+
}
|
|
229
|
+
return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
|
|
230
|
+
}
|
|
231
|
+
handlePositions(client, message) {
|
|
232
|
+
//
|
|
233
|
+
// {
|
|
234
|
+
// feed: 'open_positions',
|
|
235
|
+
// account: '3b111acc-4fcc-45be-a622-57e611fe9f7f',
|
|
236
|
+
// positions: [
|
|
237
|
+
// {
|
|
238
|
+
// instrument: 'PF_LTCUSD',
|
|
239
|
+
// balance: 0.5,
|
|
240
|
+
// pnl: -0.8628305877699987,
|
|
241
|
+
// entry_price: 70.53,
|
|
242
|
+
// mark_price: 68.80433882446,
|
|
243
|
+
// index_price: 68.8091,
|
|
244
|
+
// liquidation_threshold: 0,
|
|
245
|
+
// effective_leverage: 0.007028866753648637,
|
|
246
|
+
// return_on_equity: -1.2233525985679834,
|
|
247
|
+
// unrealized_funding: 0.0000690610530935388,
|
|
248
|
+
// initial_margin: 0.7053,
|
|
249
|
+
// initial_margin_with_orders: 0.7053,
|
|
250
|
+
// maintenance_margin: 0.35265,
|
|
251
|
+
// pnl_currency: 'USD'
|
|
252
|
+
// }
|
|
253
|
+
// ],
|
|
254
|
+
// seq: 0,
|
|
255
|
+
// timestamp: 1698608414910
|
|
256
|
+
// }
|
|
257
|
+
//
|
|
258
|
+
if (this.positions === undefined) {
|
|
259
|
+
this.positions = new Cache.ArrayCacheBySymbolById();
|
|
260
|
+
}
|
|
261
|
+
const cache = this.positions;
|
|
262
|
+
const rawPositions = this.safeValue(message, 'positions', []);
|
|
263
|
+
const newPositions = [];
|
|
264
|
+
for (let i = 0; i < rawPositions.length; i++) {
|
|
265
|
+
const rawPosition = rawPositions[i];
|
|
266
|
+
const position = this.parseWsPosition(rawPosition);
|
|
267
|
+
const timestamp = this.safeInteger(message, 'timestamp');
|
|
268
|
+
position['timestamp'] = timestamp;
|
|
269
|
+
position['datetime'] = this.iso8601(timestamp);
|
|
270
|
+
newPositions.push(position);
|
|
271
|
+
cache.append(position);
|
|
272
|
+
}
|
|
273
|
+
const messageHashes = this.findMessageHashes(client, 'positions::');
|
|
274
|
+
for (let i = 0; i < messageHashes.length; i++) {
|
|
275
|
+
const messageHash = messageHashes[i];
|
|
276
|
+
const parts = messageHash.split('::');
|
|
277
|
+
const symbolsString = parts[1];
|
|
278
|
+
const symbols = symbolsString.split(',');
|
|
279
|
+
const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
|
|
280
|
+
if (!this.isEmpty(positions)) {
|
|
281
|
+
client.resolve(positions, messageHash);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
client.resolve(newPositions, 'positions');
|
|
285
|
+
}
|
|
286
|
+
parseWsPosition(position, market = undefined) {
|
|
287
|
+
//
|
|
288
|
+
// {
|
|
289
|
+
// instrument: 'PF_LTCUSD',
|
|
290
|
+
// balance: 0.5,
|
|
291
|
+
// pnl: -0.8628305877699987,
|
|
292
|
+
// entry_price: 70.53,
|
|
293
|
+
// mark_price: 68.80433882446,
|
|
294
|
+
// index_price: 68.8091,
|
|
295
|
+
// liquidation_threshold: 0,
|
|
296
|
+
// effective_leverage: 0.007028866753648637,
|
|
297
|
+
// return_on_equity: -1.2233525985679834,
|
|
298
|
+
// unrealized_funding: 0.0000690610530935388,
|
|
299
|
+
// initial_margin: 0.7053,
|
|
300
|
+
// initial_margin_with_orders: 0.7053,
|
|
301
|
+
// maintenance_margin: 0.35265,
|
|
302
|
+
// pnl_currency: 'USD'
|
|
303
|
+
// }
|
|
304
|
+
//
|
|
305
|
+
const marketId = this.safeString(position, 'instrument');
|
|
306
|
+
const hedged = 'both';
|
|
307
|
+
const balance = this.safeNumber(position, 'balance');
|
|
308
|
+
const side = (balance > 0) ? 'long' : 'short';
|
|
309
|
+
return this.safePosition({
|
|
310
|
+
'info': position,
|
|
311
|
+
'id': undefined,
|
|
312
|
+
'symbol': this.safeSymbol(marketId),
|
|
313
|
+
'notional': undefined,
|
|
314
|
+
'marginMode': undefined,
|
|
315
|
+
'liquidationPrice': this.safeNumber(position, 'liquidation_threshold'),
|
|
316
|
+
'entryPrice': this.safeNumber(position, 'entry_price'),
|
|
317
|
+
'unrealizedPnl': this.safeNumber(position, 'pnl'),
|
|
318
|
+
'percentage': this.safeNumber(position, 'return_on_equity'),
|
|
319
|
+
'contracts': this.parseNumber(Precise["default"].stringAbs(this.numberToString(balance))),
|
|
320
|
+
'contractSize': undefined,
|
|
321
|
+
'markPrice': this.safeNumber(position, 'mark_price'),
|
|
322
|
+
'side': side,
|
|
323
|
+
'hedged': hedged,
|
|
324
|
+
'timestamp': undefined,
|
|
325
|
+
'datetime': undefined,
|
|
326
|
+
'maintenanceMargin': this.safeNumber(position, 'maintenance_margin'),
|
|
327
|
+
'maintenanceMarginPercentage': undefined,
|
|
328
|
+
'collateral': undefined,
|
|
329
|
+
'initialMargin': this.safeNumber(position, 'initial_margin'),
|
|
330
|
+
'initialMarginPercentage': undefined,
|
|
331
|
+
'leverage': undefined,
|
|
332
|
+
'marginRatio': undefined,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
207
335
|
async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
208
336
|
/**
|
|
209
337
|
* @method
|
|
@@ -1279,6 +1407,7 @@ class krakenfutures extends krakenfutures$1 {
|
|
|
1279
1407
|
'open_orders_snapshot': this.handleOrderSnapshot,
|
|
1280
1408
|
'balances': this.handleBalance,
|
|
1281
1409
|
'balances_snapshot': this.handleBalance,
|
|
1410
|
+
'open_positions': this.handlePositions,
|
|
1282
1411
|
};
|
|
1283
1412
|
const method = this.safeValue(methods, feed);
|
|
1284
1413
|
if (method !== undefined) {
|
|
@@ -16,6 +16,9 @@ class kucoinfutures extends kucoinfutures$1 {
|
|
|
16
16
|
'watchOrderBook': true,
|
|
17
17
|
'watchOrders': true,
|
|
18
18
|
'watchBalance': true,
|
|
19
|
+
'watchPosition': true,
|
|
20
|
+
'watchPositions': false,
|
|
21
|
+
'watchPositionForSymbols': false,
|
|
19
22
|
'watchTradesForSymbols': true,
|
|
20
23
|
'watchOrderBookForSymbols': true,
|
|
21
24
|
},
|
|
@@ -41,6 +44,10 @@ class kucoinfutures extends kucoinfutures$1 {
|
|
|
41
44
|
'watchTicker': {
|
|
42
45
|
'name': 'contractMarket/tickerV2', // market/ticker
|
|
43
46
|
},
|
|
47
|
+
'watchPosition': {
|
|
48
|
+
'fetchPositionSnapshot': true,
|
|
49
|
+
'awaitPositionSnapshot': true, // whether to wait for the position snapshot before providing updates
|
|
50
|
+
},
|
|
44
51
|
},
|
|
45
52
|
'streaming': {
|
|
46
53
|
// kucoin does not support built-in ws protocol-level ping-pong
|
|
@@ -177,6 +184,178 @@ class kucoinfutures extends kucoinfutures$1 {
|
|
|
177
184
|
client.resolve(ticker, messageHash);
|
|
178
185
|
return message;
|
|
179
186
|
}
|
|
187
|
+
async watchPosition(symbol = undefined, params = {}) {
|
|
188
|
+
/**
|
|
189
|
+
* @method
|
|
190
|
+
* @name kucoinfutures#watchPosition
|
|
191
|
+
* @description watch open positions for a specific symbol
|
|
192
|
+
* @see https://docs.kucoin.com/futures/#position-change-events
|
|
193
|
+
* @param {string|undefined} symbol unified market symbol
|
|
194
|
+
* @param {object} params extra parameters specific to the kucoinfutures api endpoint
|
|
195
|
+
* @returns {object} a [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
|
|
196
|
+
*/
|
|
197
|
+
this.checkRequiredSymbol('watchPosition', symbol);
|
|
198
|
+
await this.loadMarkets();
|
|
199
|
+
const url = await this.negotiate(true);
|
|
200
|
+
const market = this.market(symbol);
|
|
201
|
+
const topic = '/contract/position:' + market['id'];
|
|
202
|
+
const request = {
|
|
203
|
+
'privateChannel': true,
|
|
204
|
+
};
|
|
205
|
+
const messageHash = 'position:' + market['symbol'];
|
|
206
|
+
const client = this.client(url);
|
|
207
|
+
this.setPositionCache(client, symbol);
|
|
208
|
+
const fetchPositionSnapshot = this.handleOption('watchPosition', 'fetchPositionSnapshot', true);
|
|
209
|
+
const awaitPositionSnapshot = this.safeValue('watchPosition', 'awaitPositionSnapshot', true);
|
|
210
|
+
const currentPosition = this.getCurrentPosition(symbol);
|
|
211
|
+
if (fetchPositionSnapshot && awaitPositionSnapshot && currentPosition === undefined) {
|
|
212
|
+
const snapshot = await client.future('fetchPositionSnapshot:' + symbol);
|
|
213
|
+
return snapshot;
|
|
214
|
+
}
|
|
215
|
+
return await this.subscribe(url, messageHash, topic, undefined, this.extend(request, params));
|
|
216
|
+
}
|
|
217
|
+
getCurrentPosition(symbol) {
|
|
218
|
+
if (this.positions === undefined) {
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
const cache = this.positions.hashmap;
|
|
222
|
+
const symbolCache = this.safeValue(cache, symbol, {});
|
|
223
|
+
const values = Object.values(symbolCache);
|
|
224
|
+
return this.safeValue(values, 0);
|
|
225
|
+
}
|
|
226
|
+
setPositionCache(client, symbol) {
|
|
227
|
+
const fetchPositionSnapshot = this.handleOption('watchPosition', 'fetchPositionSnapshot', false);
|
|
228
|
+
if (fetchPositionSnapshot) {
|
|
229
|
+
const messageHash = 'fetchPositionSnapshot:' + symbol;
|
|
230
|
+
if (!(messageHash in client.futures)) {
|
|
231
|
+
client.future(messageHash);
|
|
232
|
+
this.spawn(this.loadPositionSnapshot, client, messageHash, symbol);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
async loadPositionSnapshot(client, messageHash, symbol) {
|
|
237
|
+
const position = await this.fetchPosition(symbol);
|
|
238
|
+
this.positions = new Cache.ArrayCacheBySymbolById();
|
|
239
|
+
const cache = this.positions;
|
|
240
|
+
cache.append(position);
|
|
241
|
+
// don't remove the future from the .futures cache
|
|
242
|
+
const future = client.futures[messageHash];
|
|
243
|
+
future.resolve(cache);
|
|
244
|
+
client.resolve(position, 'position:' + symbol);
|
|
245
|
+
}
|
|
246
|
+
handlePosition(client, message) {
|
|
247
|
+
//
|
|
248
|
+
// Position Changes Caused Operations
|
|
249
|
+
// {
|
|
250
|
+
// "type": "message",
|
|
251
|
+
// "userId": "5c32d69203aa676ce4b543c7", // Deprecated, will detele later
|
|
252
|
+
// "channelType": "private",
|
|
253
|
+
// "topic": "/contract/position:XBTUSDM",
|
|
254
|
+
// "subject": "position.change",
|
|
255
|
+
// "data": {
|
|
256
|
+
// "realisedGrossPnl": 0E-8, //Accumulated realised profit and loss
|
|
257
|
+
// "symbol": "XBTUSDM", //Symbol
|
|
258
|
+
// "crossMode": false, //Cross mode or not
|
|
259
|
+
// "liquidationPrice": 1000000.0, //Liquidation price
|
|
260
|
+
// "posLoss": 0E-8, //Manually added margin amount
|
|
261
|
+
// "avgEntryPrice": 7508.22, //Average entry price
|
|
262
|
+
// "unrealisedPnl": -0.00014735, //Unrealised profit and loss
|
|
263
|
+
// "markPrice": 7947.83, //Mark price
|
|
264
|
+
// "posMargin": 0.00266779, //Position margin
|
|
265
|
+
// "autoDeposit": false, //Auto deposit margin or not
|
|
266
|
+
// "riskLimit": 100000, //Risk limit
|
|
267
|
+
// "unrealisedCost": 0.00266375, //Unrealised value
|
|
268
|
+
// "posComm": 0.00000392, //Bankruptcy cost
|
|
269
|
+
// "posMaint": 0.00001724, //Maintenance margin
|
|
270
|
+
// "posCost": 0.00266375, //Position value
|
|
271
|
+
// "maintMarginReq": 0.005, //Maintenance margin rate
|
|
272
|
+
// "bankruptPrice": 1000000.0, //Bankruptcy price
|
|
273
|
+
// "realisedCost": 0.00000271, //Currently accumulated realised position value
|
|
274
|
+
// "markValue": 0.00251640, //Mark value
|
|
275
|
+
// "posInit": 0.00266375, //Position margin
|
|
276
|
+
// "realisedPnl": -0.00000253, //Realised profit and losts
|
|
277
|
+
// "maintMargin": 0.00252044, //Position margin
|
|
278
|
+
// "realLeverage": 1.06, //Leverage of the order
|
|
279
|
+
// "changeReason": "positionChange", //changeReason:marginChange、positionChange、liquidation、autoAppendMarginStatusChange、adl
|
|
280
|
+
// "currentCost": 0.00266375, //Current position value
|
|
281
|
+
// "openingTimestamp": 1558433191000, //Open time
|
|
282
|
+
// "currentQty": -20, //Current position
|
|
283
|
+
// "delevPercentage": 0.52, //ADL ranking percentile
|
|
284
|
+
// "currentComm": 0.00000271, //Current commission
|
|
285
|
+
// "realisedGrossCost": 0E-8, //Accumulated reliased gross profit value
|
|
286
|
+
// "isOpen": true, //Opened position or not
|
|
287
|
+
// "posCross": 1.2E-7, //Manually added margin
|
|
288
|
+
// "currentTimestamp": 1558506060394, //Current timestamp
|
|
289
|
+
// "unrealisedRoePcnt": -0.0553, //Rate of return on investment
|
|
290
|
+
// "unrealisedPnlPcnt": -0.0553, //Position profit and loss ratio
|
|
291
|
+
// "settleCurrency": "XBT" //Currency used to clear and settle the trades
|
|
292
|
+
// }
|
|
293
|
+
// }
|
|
294
|
+
// Position Changes Caused by Mark Price
|
|
295
|
+
// {
|
|
296
|
+
// "userId": "5cd3f1a7b7ebc19ae9558591", // Deprecated, will detele later
|
|
297
|
+
// "topic": "/contract/position:XBTUSDM",
|
|
298
|
+
// "subject": "position.change",
|
|
299
|
+
// "data": {
|
|
300
|
+
// "markPrice": 7947.83, //Mark price
|
|
301
|
+
// "markValue": 0.00251640, //Mark value
|
|
302
|
+
// "maintMargin": 0.00252044, //Position margin
|
|
303
|
+
// "realLeverage": 10.06, //Leverage of the order
|
|
304
|
+
// "unrealisedPnl": -0.00014735, //Unrealised profit and lost
|
|
305
|
+
// "unrealisedRoePcnt": -0.0553, //Rate of return on investment
|
|
306
|
+
// "unrealisedPnlPcnt": -0.0553, //Position profit and loss ratio
|
|
307
|
+
// "delevPercentage": 0.52, //ADL ranking percentile
|
|
308
|
+
// "currentTimestamp": 1558087175068, //Current timestamp
|
|
309
|
+
// "settleCurrency": "XBT" //Currency used to clear and settle the trades
|
|
310
|
+
// }
|
|
311
|
+
// }
|
|
312
|
+
// Funding Settlement
|
|
313
|
+
// {
|
|
314
|
+
// "userId": "xbc453tg732eba53a88ggyt8c", // Deprecated, will detele later
|
|
315
|
+
// "topic": "/contract/position:XBTUSDM",
|
|
316
|
+
// "subject": "position.settlement",
|
|
317
|
+
// "data": {
|
|
318
|
+
// "fundingTime": 1551770400000, //Funding time
|
|
319
|
+
// "qty": 100, //Position siz
|
|
320
|
+
// "markPrice": 3610.85, //Settlement price
|
|
321
|
+
// "fundingRate": -0.002966, //Funding rate
|
|
322
|
+
// "fundingFee": -296, //Funding fees
|
|
323
|
+
// "ts": 1547697294838004923, //Current time (nanosecond)
|
|
324
|
+
// "settleCurrency": "XBT" //Currency used to clear and settle the trades
|
|
325
|
+
// }
|
|
326
|
+
// }
|
|
327
|
+
// Adjustmet result of risk limit level
|
|
328
|
+
// {
|
|
329
|
+
// "userId": "xbc453tg732eba53a88ggyt8c",
|
|
330
|
+
// "topic": "/contract/position:ADAUSDTM",
|
|
331
|
+
// "subject": "position.adjustRiskLimit",
|
|
332
|
+
// "data": {
|
|
333
|
+
// "success": true, // Successful or not
|
|
334
|
+
// "riskLimitLevel": 1, // Current risk limit level
|
|
335
|
+
// "msg": "" // Failure reason
|
|
336
|
+
// }
|
|
337
|
+
// }
|
|
338
|
+
//
|
|
339
|
+
const topic = this.safeString(message, 'topic', '');
|
|
340
|
+
const parts = topic.split(':');
|
|
341
|
+
const marketId = this.safeString(parts, 1);
|
|
342
|
+
const symbol = this.safeSymbol(marketId, undefined, '');
|
|
343
|
+
const cache = this.positions;
|
|
344
|
+
const currentPosition = this.getCurrentPosition(symbol);
|
|
345
|
+
const messageHash = 'position:' + symbol;
|
|
346
|
+
const data = this.safeValue(message, 'data', {});
|
|
347
|
+
const newPosition = this.parsePosition(data);
|
|
348
|
+
const keys = Object.keys(newPosition);
|
|
349
|
+
for (let i = 0; i < keys.length; i++) {
|
|
350
|
+
const key = keys[i];
|
|
351
|
+
if (newPosition[key] === undefined) {
|
|
352
|
+
delete newPosition[key];
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
const position = this.extend(currentPosition, newPosition);
|
|
356
|
+
cache.append(position);
|
|
357
|
+
client.resolve(position, messageHash);
|
|
358
|
+
}
|
|
180
359
|
async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
|
|
181
360
|
/**
|
|
182
361
|
* @method
|
|
@@ -729,6 +908,9 @@ class kucoinfutures extends kucoinfutures$1 {
|
|
|
729
908
|
'match': this.handleTrade,
|
|
730
909
|
'orderChange': this.handleOrder,
|
|
731
910
|
'orderUpdated': this.handleOrder,
|
|
911
|
+
'position.change': this.handlePosition,
|
|
912
|
+
'position.settlement': this.handlePosition,
|
|
913
|
+
'position.adjustRiskLimit': this.handlePosition,
|
|
732
914
|
};
|
|
733
915
|
const method = this.safeValue(methods, subject);
|
|
734
916
|
if (method === undefined) {
|
package/dist/cjs/src/pro/okx.js
CHANGED
|
@@ -22,6 +22,7 @@ class okx extends okx$1 {
|
|
|
22
22
|
'watchOHLCV': true,
|
|
23
23
|
'watchOrders': true,
|
|
24
24
|
'watchMyTrades': true,
|
|
25
|
+
'watchPositions': true,
|
|
25
26
|
'createOrderWs': true,
|
|
26
27
|
'editOrderWs': true,
|
|
27
28
|
'cancelOrderWs': true,
|
|
@@ -850,6 +851,125 @@ class okx extends okx$1 {
|
|
|
850
851
|
}
|
|
851
852
|
return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
|
|
852
853
|
}
|
|
854
|
+
async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
|
|
855
|
+
/**
|
|
856
|
+
* @method
|
|
857
|
+
* @name okx#watchPositions
|
|
858
|
+
* @see https://www.okx.com/docs-v5/en/#trading-account-websocket-positions-channel
|
|
859
|
+
* @description watch all open positions
|
|
860
|
+
* @param {[string]|undefined} symbols list of unified market symbols
|
|
861
|
+
* @param {object} params extra parameters specific to the okx api endpoint
|
|
862
|
+
* @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
|
|
863
|
+
*/
|
|
864
|
+
if (this.isEmpty(symbols)) {
|
|
865
|
+
throw new errors.ArgumentsRequired(this.id + ' watchPositions requires a list of symbols');
|
|
866
|
+
}
|
|
867
|
+
await this.loadMarkets();
|
|
868
|
+
await this.authenticate(params);
|
|
869
|
+
symbols = this.marketSymbols(symbols);
|
|
870
|
+
const request = {
|
|
871
|
+
'instType': 'ANY',
|
|
872
|
+
};
|
|
873
|
+
const channel = 'positions';
|
|
874
|
+
const newPositions = await this.subscribeMultiple('private', channel, symbols, this.extend(request, params));
|
|
875
|
+
if (this.newUpdates) {
|
|
876
|
+
return newPositions;
|
|
877
|
+
}
|
|
878
|
+
return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
|
|
879
|
+
}
|
|
880
|
+
handlePositions(client, message) {
|
|
881
|
+
//
|
|
882
|
+
// {
|
|
883
|
+
// arg: {
|
|
884
|
+
// channel: 'positions',
|
|
885
|
+
// instType: 'ANY',
|
|
886
|
+
// instId: 'XRP-USDT-SWAP',
|
|
887
|
+
// uid: '464737184507959869'
|
|
888
|
+
// },
|
|
889
|
+
// data: [{
|
|
890
|
+
// adl: '1',
|
|
891
|
+
// availPos: '',
|
|
892
|
+
// avgPx: '0.52668',
|
|
893
|
+
// baseBal: '',
|
|
894
|
+
// baseBorrowed: '',
|
|
895
|
+
// baseInterest: '',
|
|
896
|
+
// bizRefId: '',
|
|
897
|
+
// bizRefType: '',
|
|
898
|
+
// cTime: '1693151444408',
|
|
899
|
+
// ccy: 'USDT',
|
|
900
|
+
// closeOrderAlgo: [],
|
|
901
|
+
// deltaBS: '',
|
|
902
|
+
// deltaPA: '',
|
|
903
|
+
// gammaBS: '',
|
|
904
|
+
// gammaPA: '',
|
|
905
|
+
// idxPx: '0.52683',
|
|
906
|
+
// imr: '17.564000000000004',
|
|
907
|
+
// instId: 'XRP-USDT-SWAP',
|
|
908
|
+
// instType: 'SWAP',
|
|
909
|
+
// interest: '',
|
|
910
|
+
// last: '0.52691',
|
|
911
|
+
// lever: '3',
|
|
912
|
+
// liab: '',
|
|
913
|
+
// liabCcy: '',
|
|
914
|
+
// liqPx: '0.3287514731020614',
|
|
915
|
+
// margin: '',
|
|
916
|
+
// markPx: '0.52692',
|
|
917
|
+
// mgnMode: 'cross',
|
|
918
|
+
// mgnRatio: '69.00363001456147',
|
|
919
|
+
// mmr: '0.26346',
|
|
920
|
+
// notionalUsd: '52.68620388000001',
|
|
921
|
+
// optVal: '',
|
|
922
|
+
// pTime: '1693151906023',
|
|
923
|
+
// pendingCloseOrdLiabVal: '',
|
|
924
|
+
// pos: '1',
|
|
925
|
+
// posCcy: '',
|
|
926
|
+
// posId: '616057041198907393',
|
|
927
|
+
// posSide: 'net',
|
|
928
|
+
// quoteBal: '',
|
|
929
|
+
// quoteBorrowed: '',
|
|
930
|
+
// quoteInterest: '',
|
|
931
|
+
// spotInUseAmt: '',
|
|
932
|
+
// spotInUseCcy: '',
|
|
933
|
+
// thetaBS: '',
|
|
934
|
+
// thetaPA: '',
|
|
935
|
+
// tradeId: '138745402',
|
|
936
|
+
// uTime: '1693151444408',
|
|
937
|
+
// upl: '0.0240000000000018',
|
|
938
|
+
// uplLastPx: '0.0229999999999952',
|
|
939
|
+
// uplRatio: '0.0013670539986328',
|
|
940
|
+
// uplRatioLastPx: '0.001310093415356',
|
|
941
|
+
// usdPx: '',
|
|
942
|
+
// vegaBS: '',
|
|
943
|
+
// vegaPA: ''
|
|
944
|
+
// }]
|
|
945
|
+
// }
|
|
946
|
+
//
|
|
947
|
+
const arg = this.safeValue(message, 'arg', {});
|
|
948
|
+
const channel = this.safeString(arg, 'channel', '');
|
|
949
|
+
const data = this.safeValue(message, 'data', []);
|
|
950
|
+
if (this.positions === undefined) {
|
|
951
|
+
this.positions = new Cache.ArrayCacheBySymbolBySide();
|
|
952
|
+
}
|
|
953
|
+
const cache = this.positions;
|
|
954
|
+
const newPositions = [];
|
|
955
|
+
for (let i = 0; i < data.length; i++) {
|
|
956
|
+
const rawPosition = data[i];
|
|
957
|
+
const position = this.parsePosition(rawPosition);
|
|
958
|
+
newPositions.push(position);
|
|
959
|
+
cache.append(position);
|
|
960
|
+
}
|
|
961
|
+
const messageHashes = this.findMessageHashes(client, channel + '::');
|
|
962
|
+
for (let i = 0; i < messageHashes.length; i++) {
|
|
963
|
+
const messageHash = messageHashes[i];
|
|
964
|
+
const parts = messageHash.split('::');
|
|
965
|
+
const symbolsString = parts[1];
|
|
966
|
+
const symbols = symbolsString.split(',');
|
|
967
|
+
const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
|
|
968
|
+
if (!this.isEmpty(positions)) {
|
|
969
|
+
client.resolve(positions, messageHash);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
853
973
|
async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
854
974
|
/**
|
|
855
975
|
* @method
|
|
@@ -1422,6 +1542,7 @@ class okx extends okx$1 {
|
|
|
1422
1542
|
'books50-l2-tbt': this.handleOrderBook,
|
|
1423
1543
|
'books-l2-tbt': this.handleOrderBook,
|
|
1424
1544
|
'tickers': this.handleTicker,
|
|
1545
|
+
'positions': this.handlePositions,
|
|
1425
1546
|
'index-tickers': this.handleTicker,
|
|
1426
1547
|
'sprd-tickers': this.handleTicker,
|
|
1427
1548
|
'block-tickers': this.handleTicker,
|
package/js/ccxt.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import * as functions from './src/base/functions.js';
|
|
|
4
4
|
import * as errors from './src/base/errors.js';
|
|
5
5
|
import { Market, Trade, Fee, Ticker, OrderBook, Order, Transaction, Tickers, Currency, Balance, DepositAddress, WithdrawalResponse, DepositAddressResponse, OHLCV, Balances, PartialBalances, Dictionary, MinMax, Position, FundingRateHistory, Liquidation, FundingHistory } from './src/base/types.js';
|
|
6
6
|
import { BaseError, ExchangeError, PermissionDenied, AccountNotEnabled, AccountSuspended, ArgumentsRequired, BadRequest, BadSymbol, MarginModeAlreadySet, BadResponse, NullResponse, InsufficientFunds, InvalidAddress, InvalidOrder, OrderNotFound, OrderNotCached, CancelPending, OrderImmediatelyFillable, OrderNotFillable, DuplicateOrderId, NotSupported, NetworkError, DDoSProtection, RateLimitExceeded, ExchangeNotAvailable, OnMaintenance, InvalidNonce, RequestTimeout, AuthenticationError, AddressPending, NoChange } from './src/base/errors.js';
|
|
7
|
-
declare const version = "4.1.
|
|
7
|
+
declare const version = "4.1.45";
|
|
8
8
|
import ace from './src/ace.js';
|
|
9
9
|
import alpaca from './src/alpaca.js';
|
|
10
10
|
import ascendex from './src/ascendex.js';
|