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
|
@@ -22,8 +22,8 @@ class bybit extends bybit$1 {
|
|
|
22
22
|
'watchTicker': true,
|
|
23
23
|
'watchTickers': true,
|
|
24
24
|
'watchTrades': true,
|
|
25
|
+
'watchPositions': true,
|
|
25
26
|
'watchTradesForSymbols': true,
|
|
26
|
-
'watchPosition': undefined,
|
|
27
27
|
},
|
|
28
28
|
'urls': {
|
|
29
29
|
'api': {
|
|
@@ -67,6 +67,10 @@ class bybit extends bybit$1 {
|
|
|
67
67
|
'watchTicker': {
|
|
68
68
|
'name': 'tickers', // 'tickers' for 24hr statistical ticker or 'tickers_lt' for leverage token ticker
|
|
69
69
|
},
|
|
70
|
+
'watchPositions': {
|
|
71
|
+
'fetchPositionsSnapshot': true,
|
|
72
|
+
'awaitPositionsSnapshot': true, // whether to wait for the positions snapshot before providing updates
|
|
73
|
+
},
|
|
70
74
|
'spot': {
|
|
71
75
|
'timeframes': {
|
|
72
76
|
'1m': '1m',
|
|
@@ -180,7 +184,7 @@ class bybit extends bybit$1 {
|
|
|
180
184
|
}
|
|
181
185
|
topic += '.' + market['id'];
|
|
182
186
|
const topics = [topic];
|
|
183
|
-
return await this.watchTopics(url, messageHash, topics, params);
|
|
187
|
+
return await this.watchTopics(url, messageHash, topics, messageHash, params);
|
|
184
188
|
}
|
|
185
189
|
async watchTickers(symbols = undefined, params = {}) {
|
|
186
190
|
/**
|
|
@@ -377,7 +381,7 @@ class bybit extends bybit$1 {
|
|
|
377
381
|
const timeframeId = this.safeString(this.timeframes, timeframe, timeframe);
|
|
378
382
|
const topics = ['kline.' + timeframeId + '.' + market['id']];
|
|
379
383
|
const messageHash = 'kline' + ':' + timeframeId + ':' + symbol;
|
|
380
|
-
ohlcv = await this.watchTopics(url, messageHash, topics, params);
|
|
384
|
+
ohlcv = await this.watchTopics(url, messageHash, topics, messageHash, params);
|
|
381
385
|
if (this.newUpdates) {
|
|
382
386
|
limit = ohlcv.getLimit(symbol, limit);
|
|
383
387
|
}
|
|
@@ -534,7 +538,7 @@ class bybit extends bybit$1 {
|
|
|
534
538
|
}
|
|
535
539
|
}
|
|
536
540
|
const topics = ['orderbook.' + limit.toString() + '.' + market['id']];
|
|
537
|
-
const orderbook = await this.watchTopics(url, messageHash, topics, params);
|
|
541
|
+
const orderbook = await this.watchTopics(url, messageHash, topics, messageHash, params);
|
|
538
542
|
return orderbook.limit();
|
|
539
543
|
}
|
|
540
544
|
async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
|
|
@@ -672,7 +676,7 @@ class bybit extends bybit$1 {
|
|
|
672
676
|
params = this.cleanParams(params);
|
|
673
677
|
const messageHash = 'trade:' + symbol;
|
|
674
678
|
const topic = 'publicTrade.' + market['id'];
|
|
675
|
-
const trades = await this.watchTopics(url, messageHash, [topic], params);
|
|
679
|
+
const trades = await this.watchTopics(url, messageHash, [topic], messageHash, params);
|
|
676
680
|
if (this.newUpdates) {
|
|
677
681
|
limit = trades.getLimit(symbol, limit);
|
|
678
682
|
}
|
|
@@ -868,7 +872,7 @@ class bybit extends bybit$1 {
|
|
|
868
872
|
'usdc': 'user.openapi.perp.trade',
|
|
869
873
|
};
|
|
870
874
|
const topic = this.safeValue(topicByMarket, this.getPrivateType(url));
|
|
871
|
-
const trades = await this.watchTopics(url, messageHash, [topic], params);
|
|
875
|
+
const trades = await this.watchTopics(url, messageHash, [topic], messageHash, params);
|
|
872
876
|
if (this.newUpdates) {
|
|
873
877
|
limit = trades.getLimit(symbol, limit);
|
|
874
878
|
}
|
|
@@ -966,6 +970,145 @@ class bybit extends bybit$1 {
|
|
|
966
970
|
const messageHash = 'myTrades';
|
|
967
971
|
client.resolve(trades, messageHash);
|
|
968
972
|
}
|
|
973
|
+
async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
|
|
974
|
+
/**
|
|
975
|
+
* @method
|
|
976
|
+
* @name bybit#watchPositions
|
|
977
|
+
* @see https://bybit-exchange.github.io/docs/v5/websocket/private/position
|
|
978
|
+
* @description watch all open positions
|
|
979
|
+
* @param {[string]|undefined} symbols list of unified market symbols
|
|
980
|
+
* @param {object} params extra parameters specific to the bybit api endpoint
|
|
981
|
+
* @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
|
|
982
|
+
*/
|
|
983
|
+
await this.loadMarkets();
|
|
984
|
+
const method = 'watchPositions';
|
|
985
|
+
let messageHash = '';
|
|
986
|
+
if (!this.isEmpty(symbols)) {
|
|
987
|
+
symbols = this.marketSymbols(symbols);
|
|
988
|
+
messageHash = '::' + symbols.join(',');
|
|
989
|
+
}
|
|
990
|
+
const firstSymbol = this.safeString(symbols, 0);
|
|
991
|
+
const url = this.getUrlByMarketType(firstSymbol, true, method, params);
|
|
992
|
+
messageHash = 'positions' + messageHash;
|
|
993
|
+
const client = this.client(url);
|
|
994
|
+
await this.authenticate(url);
|
|
995
|
+
this.setPositionsCache(client, symbols);
|
|
996
|
+
const cache = this.positions;
|
|
997
|
+
const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
|
|
998
|
+
const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
|
|
999
|
+
if (fetchPositionsSnapshot && awaitPositionsSnapshot && cache === undefined) {
|
|
1000
|
+
const snapshot = await client.future('fetchPositionsSnapshot');
|
|
1001
|
+
return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
|
|
1002
|
+
}
|
|
1003
|
+
const topics = ['position'];
|
|
1004
|
+
const newPositions = await this.watchTopics(url, messageHash, topics, 'position', params);
|
|
1005
|
+
if (this.newUpdates) {
|
|
1006
|
+
return newPositions;
|
|
1007
|
+
}
|
|
1008
|
+
return this.filterBySymbolsSinceLimit(cache, symbols, since, limit, true);
|
|
1009
|
+
}
|
|
1010
|
+
setPositionsCache(client, symbols = undefined) {
|
|
1011
|
+
if (this.positions !== undefined) {
|
|
1012
|
+
return this.positions;
|
|
1013
|
+
}
|
|
1014
|
+
const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
|
|
1015
|
+
if (fetchPositionsSnapshot) {
|
|
1016
|
+
const messageHash = 'fetchPositionsSnapshot';
|
|
1017
|
+
if (!(messageHash in client.futures)) {
|
|
1018
|
+
client.future(messageHash);
|
|
1019
|
+
this.spawn(this.loadPositionsSnapshot, client, messageHash);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
else {
|
|
1023
|
+
this.positions = new Cache.ArrayCacheBySymbolBySide();
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
async loadPositionsSnapshot(client, messageHash) {
|
|
1027
|
+
// as only one ws channel gives positions for all types, for snapshot must load all positions
|
|
1028
|
+
const fetchFunctions = [
|
|
1029
|
+
this.fetchPositions(undefined, { 'type': 'swap', 'subType': 'linear' }),
|
|
1030
|
+
this.fetchPositions(undefined, { 'type': 'swap', 'subType': 'inverse' }),
|
|
1031
|
+
];
|
|
1032
|
+
const promises = await Promise.all(fetchFunctions);
|
|
1033
|
+
this.positions = new Cache.ArrayCacheBySymbolBySide();
|
|
1034
|
+
const cache = this.positions;
|
|
1035
|
+
for (let i = 0; i < promises.length; i++) {
|
|
1036
|
+
const positions = promises[i];
|
|
1037
|
+
for (let ii = 0; ii < positions.length; ii++) {
|
|
1038
|
+
const position = positions[ii];
|
|
1039
|
+
cache.append(position);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
// don't remove the future from the .futures cache
|
|
1043
|
+
const future = client.futures[messageHash];
|
|
1044
|
+
future.resolve(cache);
|
|
1045
|
+
client.resolve(cache, 'position');
|
|
1046
|
+
}
|
|
1047
|
+
handlePositions(client, message) {
|
|
1048
|
+
//
|
|
1049
|
+
// {
|
|
1050
|
+
// topic: 'position',
|
|
1051
|
+
// id: '504b2671629b08e3c4f6960382a59363:3bc4028023786545:0:01',
|
|
1052
|
+
// creationTime: 1694566055295,
|
|
1053
|
+
// data: [{
|
|
1054
|
+
// bustPrice: '15.00',
|
|
1055
|
+
// category: 'inverse',
|
|
1056
|
+
// createdTime: '1670083436351',
|
|
1057
|
+
// cumRealisedPnl: '0.00011988',
|
|
1058
|
+
// entryPrice: '19358.58553268',
|
|
1059
|
+
// leverage: '10',
|
|
1060
|
+
// liqPrice: '15.00',
|
|
1061
|
+
// markPrice: '25924.00',
|
|
1062
|
+
// positionBalance: '0.0000156',
|
|
1063
|
+
// positionIdx: 0,
|
|
1064
|
+
// positionMM: '0.001',
|
|
1065
|
+
// positionIM: '0.0000015497',
|
|
1066
|
+
// positionStatus: 'Normal',
|
|
1067
|
+
// positionValue: '0.00015497',
|
|
1068
|
+
// riskId: 1,
|
|
1069
|
+
// riskLimitValue: '150',
|
|
1070
|
+
// side: 'Buy',
|
|
1071
|
+
// size: '3',
|
|
1072
|
+
// stopLoss: '0.00',
|
|
1073
|
+
// symbol: 'BTCUSD',
|
|
1074
|
+
// takeProfit: '0.00',
|
|
1075
|
+
// tpslMode: 'Full',
|
|
1076
|
+
// tradeMode: 0,
|
|
1077
|
+
// autoAddMargin: 1,
|
|
1078
|
+
// trailingStop: '0.00',
|
|
1079
|
+
// unrealisedPnl: '0.00003925',
|
|
1080
|
+
// updatedTime: '1694566055293',
|
|
1081
|
+
// adlRankIndicator: 3
|
|
1082
|
+
// }]
|
|
1083
|
+
// }
|
|
1084
|
+
//
|
|
1085
|
+
// each account is connected to a different endpoint
|
|
1086
|
+
// and has exactly one subscriptionhash which is the account type
|
|
1087
|
+
if (this.positions === undefined) {
|
|
1088
|
+
this.positions = new Cache.ArrayCacheBySymbolBySide();
|
|
1089
|
+
}
|
|
1090
|
+
const cache = this.positions;
|
|
1091
|
+
const newPositions = [];
|
|
1092
|
+
const rawPositions = this.safeValue(message, 'data', []);
|
|
1093
|
+
for (let i = 0; i < rawPositions.length; i++) {
|
|
1094
|
+
const rawPosition = rawPositions[i];
|
|
1095
|
+
const position = this.parsePosition(rawPosition);
|
|
1096
|
+
newPositions.push(position);
|
|
1097
|
+
cache.append(position);
|
|
1098
|
+
}
|
|
1099
|
+
const messageHashes = this.findMessageHashes(client, 'positions::');
|
|
1100
|
+
for (let i = 0; i < messageHashes.length; i++) {
|
|
1101
|
+
const messageHash = messageHashes[i];
|
|
1102
|
+
const parts = messageHash.split('::');
|
|
1103
|
+
const symbolsString = parts[1];
|
|
1104
|
+
const symbols = symbolsString.split(',');
|
|
1105
|
+
const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
|
|
1106
|
+
if (!this.isEmpty(positions)) {
|
|
1107
|
+
client.resolve(positions, messageHash);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
client.resolve(newPositions, 'positions');
|
|
1111
|
+
}
|
|
969
1112
|
async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
970
1113
|
/**
|
|
971
1114
|
* @method
|
|
@@ -993,7 +1136,7 @@ class bybit extends bybit$1 {
|
|
|
993
1136
|
'usdc': ['user.openapi.perp.order'],
|
|
994
1137
|
};
|
|
995
1138
|
const topics = this.safeValue(topicsByMarket, this.getPrivateType(url));
|
|
996
|
-
const orders = await this.watchTopics(url, messageHash, topics, params);
|
|
1139
|
+
const orders = await this.watchTopics(url, messageHash, topics, messageHash, params);
|
|
997
1140
|
if (this.newUpdates) {
|
|
998
1141
|
limit = orders.getLimit(symbol, limit);
|
|
999
1142
|
}
|
|
@@ -1310,7 +1453,7 @@ class bybit extends bybit$1 {
|
|
|
1310
1453
|
}
|
|
1311
1454
|
}
|
|
1312
1455
|
const topics = [this.safeValue(topicByMarket, this.getPrivateType(url))];
|
|
1313
|
-
return await this.watchTopics(url, messageHash, topics, params);
|
|
1456
|
+
return await this.watchTopics(url, messageHash, topics, messageHash, params);
|
|
1314
1457
|
}
|
|
1315
1458
|
handleBalance(client, message) {
|
|
1316
1459
|
//
|
|
@@ -1548,14 +1691,14 @@ class bybit extends bybit$1 {
|
|
|
1548
1691
|
this.balance[code] = account;
|
|
1549
1692
|
}
|
|
1550
1693
|
}
|
|
1551
|
-
async watchTopics(url, messageHash, topics
|
|
1694
|
+
async watchTopics(url, messageHash, topics, subscriptionHash, params = {}) {
|
|
1552
1695
|
const request = {
|
|
1553
1696
|
'op': 'subscribe',
|
|
1554
1697
|
'req_id': this.requestId(),
|
|
1555
1698
|
'args': topics,
|
|
1556
1699
|
};
|
|
1557
1700
|
const message = this.extend(request, params);
|
|
1558
|
-
return await this.watch(url, messageHash, message,
|
|
1701
|
+
return await this.watch(url, messageHash, message, subscriptionHash);
|
|
1559
1702
|
}
|
|
1560
1703
|
async authenticate(url, params = {}) {
|
|
1561
1704
|
this.checkRequiredCredentials();
|
|
@@ -1682,6 +1825,7 @@ class bybit extends bybit$1 {
|
|
|
1682
1825
|
'execution': this.handleMyTrades,
|
|
1683
1826
|
'ticketInfo': this.handleMyTrades,
|
|
1684
1827
|
'user.openapi.perp.trade': this.handleMyTrades,
|
|
1828
|
+
'position': this.handlePositions,
|
|
1685
1829
|
};
|
|
1686
1830
|
const exacMethod = this.safeValue(methods, topic);
|
|
1687
1831
|
if (exacMethod !== undefined) {
|
|
@@ -22,6 +22,7 @@ class cryptocom extends cryptocom$1 {
|
|
|
22
22
|
'watchOrderBookForSymbols': true,
|
|
23
23
|
'watchOrders': true,
|
|
24
24
|
'watchOHLCV': true,
|
|
25
|
+
'watchPositions': true,
|
|
25
26
|
'createOrderWs': true,
|
|
26
27
|
'cancelOrderWs': true,
|
|
27
28
|
'cancelAllOrders': true,
|
|
@@ -38,7 +39,12 @@ class cryptocom extends cryptocom$1 {
|
|
|
38
39
|
'private': 'wss://uat-stream.3ona.co/exchange/v1/user',
|
|
39
40
|
},
|
|
40
41
|
},
|
|
41
|
-
'options': {
|
|
42
|
+
'options': {
|
|
43
|
+
'watchPositions': {
|
|
44
|
+
'fetchPositionsSnapshot': true,
|
|
45
|
+
'awaitPositionsSnapshot': true, // whether to wait for the positions snapshot before providing updates
|
|
46
|
+
},
|
|
47
|
+
},
|
|
42
48
|
'streaming': {},
|
|
43
49
|
});
|
|
44
50
|
}
|
|
@@ -447,6 +453,129 @@ class cryptocom extends cryptocom$1 {
|
|
|
447
453
|
client.resolve(stored, 'user.order');
|
|
448
454
|
}
|
|
449
455
|
}
|
|
456
|
+
async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
|
|
457
|
+
/**
|
|
458
|
+
* @method
|
|
459
|
+
* @name cryptocom#watchPositions
|
|
460
|
+
* @description watch all open positions
|
|
461
|
+
* @see https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#user-position_balance
|
|
462
|
+
* @param {[string]|undefined} symbols list of unified market symbols
|
|
463
|
+
* @param {object} params extra parameters specific to the cryptocom api endpoint
|
|
464
|
+
* @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
|
|
465
|
+
*/
|
|
466
|
+
await this.loadMarkets();
|
|
467
|
+
await this.authenticate();
|
|
468
|
+
const url = this.urls['api']['ws']['private'];
|
|
469
|
+
const id = this.nonce();
|
|
470
|
+
const request = {
|
|
471
|
+
'method': 'subscribe',
|
|
472
|
+
'params': {
|
|
473
|
+
'channels': ['user.position_balance'],
|
|
474
|
+
},
|
|
475
|
+
'nonce': id,
|
|
476
|
+
};
|
|
477
|
+
let messageHash = 'positions';
|
|
478
|
+
symbols = this.marketSymbols(symbols);
|
|
479
|
+
if (!this.isEmpty(symbols)) {
|
|
480
|
+
messageHash = '::' + symbols.join(',');
|
|
481
|
+
}
|
|
482
|
+
const client = this.client(url);
|
|
483
|
+
this.setPositionsCache(client, symbols);
|
|
484
|
+
const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
|
|
485
|
+
const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
|
|
486
|
+
if (fetchPositionsSnapshot && awaitPositionsSnapshot && this.positions === undefined) {
|
|
487
|
+
const snapshot = await client.future('fetchPositionsSnapshot');
|
|
488
|
+
return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
|
|
489
|
+
}
|
|
490
|
+
const newPositions = await this.watch(url, messageHash, this.extend(request, params));
|
|
491
|
+
if (this.newUpdates) {
|
|
492
|
+
return newPositions;
|
|
493
|
+
}
|
|
494
|
+
return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
|
|
495
|
+
}
|
|
496
|
+
setPositionsCache(client, type, symbols = undefined) {
|
|
497
|
+
const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', false);
|
|
498
|
+
if (fetchPositionsSnapshot) {
|
|
499
|
+
const messageHash = 'fetchPositionsSnapshot';
|
|
500
|
+
if (!(messageHash in client.futures)) {
|
|
501
|
+
client.future(messageHash);
|
|
502
|
+
this.spawn(this.loadPositionsSnapshot, client, messageHash);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
this.positions = new Cache.ArrayCacheBySymbolBySide();
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
async loadPositionsSnapshot(client, messageHash) {
|
|
510
|
+
const positions = await this.fetchPositions();
|
|
511
|
+
this.positions = new Cache.ArrayCacheBySymbolBySide();
|
|
512
|
+
const cache = this.positions;
|
|
513
|
+
for (let i = 0; i < positions.length; i++) {
|
|
514
|
+
const position = positions[i];
|
|
515
|
+
const contracts = this.safeNumber(position, 'contracts', 0);
|
|
516
|
+
if (contracts > 0) {
|
|
517
|
+
cache.append(position);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
// don't remove the future from the .futures cache
|
|
521
|
+
const future = client.futures[messageHash];
|
|
522
|
+
future.resolve(cache);
|
|
523
|
+
client.resolve(cache, 'positions');
|
|
524
|
+
}
|
|
525
|
+
handlePositions(client, message) {
|
|
526
|
+
//
|
|
527
|
+
// {
|
|
528
|
+
// subscription: "user.position_balance",
|
|
529
|
+
// channel: "user.position_balance",
|
|
530
|
+
// data: [{
|
|
531
|
+
// balances: [{
|
|
532
|
+
// instrument_name: "USD",
|
|
533
|
+
// quantity: "8.9979961950886",
|
|
534
|
+
// update_timestamp_ms: 1695598760597,
|
|
535
|
+
// }],
|
|
536
|
+
// positions: [{
|
|
537
|
+
// account_id: "96a0edb1-afb5-4c7c-af89-5cb610319e2c",
|
|
538
|
+
// instrument_name: "LTCUSD-PERP",
|
|
539
|
+
// type: "PERPETUAL_SWAP",
|
|
540
|
+
// quantity: "1.8",
|
|
541
|
+
// cost: "114.766",
|
|
542
|
+
// open_position_pnl: "-0.0216206",
|
|
543
|
+
// session_pnl: "0.00962994",
|
|
544
|
+
// update_timestamp_ms: 1695598760597,
|
|
545
|
+
// open_pos_cost: "114.766",
|
|
546
|
+
// }],
|
|
547
|
+
// }],
|
|
548
|
+
// }
|
|
549
|
+
//
|
|
550
|
+
// each account is connected to a different endpoint
|
|
551
|
+
// and has exactly one subscriptionhash which is the account type
|
|
552
|
+
const data = this.safeValue(message, 'data', []);
|
|
553
|
+
const firstData = this.safeValue(data, 0, {});
|
|
554
|
+
const rawPositions = this.safeValue(firstData, 'positions', []);
|
|
555
|
+
if (this.positions === undefined) {
|
|
556
|
+
this.positions = new Cache.ArrayCacheBySymbolBySide();
|
|
557
|
+
}
|
|
558
|
+
const cache = this.positions;
|
|
559
|
+
const newPositions = [];
|
|
560
|
+
for (let i = 0; i < rawPositions.length; i++) {
|
|
561
|
+
const rawPosition = rawPositions[i];
|
|
562
|
+
const position = this.parsePosition(rawPosition);
|
|
563
|
+
newPositions.push(position);
|
|
564
|
+
cache.append(position);
|
|
565
|
+
}
|
|
566
|
+
const messageHashes = this.findMessageHashes(client, 'positions::');
|
|
567
|
+
for (let i = 0; i < messageHashes.length; i++) {
|
|
568
|
+
const messageHash = messageHashes[i];
|
|
569
|
+
const parts = messageHash.split('::');
|
|
570
|
+
const symbolsString = parts[1];
|
|
571
|
+
const symbols = symbolsString.split(',');
|
|
572
|
+
const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
|
|
573
|
+
if (!this.isEmpty(positions)) {
|
|
574
|
+
client.resolve(positions, messageHash);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
client.resolve(newPositions, 'positions');
|
|
578
|
+
}
|
|
450
579
|
async watchBalance(params = {}) {
|
|
451
580
|
/**
|
|
452
581
|
* @method
|
|
@@ -713,6 +842,7 @@ class cryptocom extends cryptocom$1 {
|
|
|
713
842
|
'user.order': this.handleOrders,
|
|
714
843
|
'user.trade': this.handleTrades,
|
|
715
844
|
'user.balance': this.handleBalance,
|
|
845
|
+
'user.position_balance': this.handlePositions,
|
|
716
846
|
};
|
|
717
847
|
const result = this.safeValue2(message, 'result', 'info');
|
|
718
848
|
const channel = this.safeString(result, 'channel');
|
package/dist/cjs/src/pro/gate.js
CHANGED
|
@@ -21,6 +21,7 @@ class gate extends gate$1 {
|
|
|
21
21
|
'watchOHLCV': true,
|
|
22
22
|
'watchBalance': true,
|
|
23
23
|
'watchOrders': true,
|
|
24
|
+
'watchPositions': true,
|
|
24
25
|
},
|
|
25
26
|
'urls': {
|
|
26
27
|
'api': {
|
|
@@ -72,6 +73,10 @@ class gate extends gate$1 {
|
|
|
72
73
|
'settle': 'usdt',
|
|
73
74
|
'spot': 'spot.balances', // spot.margin_balances, spot.funding_balances or spot.cross_balances
|
|
74
75
|
},
|
|
76
|
+
'watchPositions': {
|
|
77
|
+
'fetchPositionsSnapshot': true,
|
|
78
|
+
'awaitPositionsSnapshot': true, // whether to wait for the positions snapshot before providing updates
|
|
79
|
+
},
|
|
75
80
|
},
|
|
76
81
|
'exceptions': {
|
|
77
82
|
'ws': {
|
|
@@ -750,6 +755,145 @@ class gate extends gate$1 {
|
|
|
750
755
|
this.balance = this.safeBalance(this.balance);
|
|
751
756
|
client.resolve(this.balance, messageHash);
|
|
752
757
|
}
|
|
758
|
+
async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
|
|
759
|
+
/**
|
|
760
|
+
* @method
|
|
761
|
+
* @name gate#watchPositions
|
|
762
|
+
* @see https://www.gate.io/docs/developers/futures/ws/en/#positions-subscription
|
|
763
|
+
* @see https://www.gate.io/docs/developers/delivery/ws/en/#positions-subscription
|
|
764
|
+
* @see https://www.gate.io/docs/developers/options/ws/en/#positions-channel
|
|
765
|
+
* @description watch all open positions
|
|
766
|
+
* @param {[string]|undefined} symbols list of unified market symbols
|
|
767
|
+
* @param {object} params extra parameters specific to the gate api endpoint
|
|
768
|
+
* @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
|
|
769
|
+
*/
|
|
770
|
+
await this.loadMarkets();
|
|
771
|
+
let market = undefined;
|
|
772
|
+
symbols = this.marketSymbols(symbols);
|
|
773
|
+
const payload = ['!' + 'all'];
|
|
774
|
+
if (!this.isEmpty(symbols)) {
|
|
775
|
+
market = this.getMarketFromSymbols(symbols);
|
|
776
|
+
}
|
|
777
|
+
let type = undefined;
|
|
778
|
+
let query = undefined;
|
|
779
|
+
[type, query] = this.handleMarketTypeAndParams('watchPositions', market, params);
|
|
780
|
+
if (type === 'spot') {
|
|
781
|
+
type = 'swap';
|
|
782
|
+
}
|
|
783
|
+
const typeId = this.getSupportedMapping(type, {
|
|
784
|
+
'future': 'futures',
|
|
785
|
+
'swap': 'futures',
|
|
786
|
+
'option': 'options',
|
|
787
|
+
});
|
|
788
|
+
let messageHash = type + ':positions';
|
|
789
|
+
if (!this.isEmpty(symbols)) {
|
|
790
|
+
messageHash += '::' + symbols.join(',');
|
|
791
|
+
}
|
|
792
|
+
const channel = typeId + '.positions';
|
|
793
|
+
let subType = undefined;
|
|
794
|
+
[subType, query] = this.handleSubTypeAndParams('watchPositions', market, query);
|
|
795
|
+
const isInverse = (subType === 'inverse');
|
|
796
|
+
const url = this.getUrlByMarketType(type, isInverse);
|
|
797
|
+
const client = this.client(url);
|
|
798
|
+
this.setPositionsCache(client, type, symbols);
|
|
799
|
+
const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
|
|
800
|
+
const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
|
|
801
|
+
const cache = this.safeValue(this.positions, type);
|
|
802
|
+
if (fetchPositionsSnapshot && awaitPositionsSnapshot && cache === undefined) {
|
|
803
|
+
return await client.future(type + ':fetchPositionsSnapshot');
|
|
804
|
+
}
|
|
805
|
+
const positions = await this.subscribePrivate(url, messageHash, payload, channel, query, true);
|
|
806
|
+
if (this.newUpdates) {
|
|
807
|
+
return positions;
|
|
808
|
+
}
|
|
809
|
+
return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
|
|
810
|
+
}
|
|
811
|
+
setPositionsCache(client, type, symbols = undefined) {
|
|
812
|
+
if (this.positions === undefined) {
|
|
813
|
+
this.positions = {};
|
|
814
|
+
}
|
|
815
|
+
if (type in this.positions) {
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', false);
|
|
819
|
+
if (fetchPositionsSnapshot) {
|
|
820
|
+
const messageHash = type + ':fetchPositionsSnapshot';
|
|
821
|
+
if (!(messageHash in client.futures)) {
|
|
822
|
+
client.future(messageHash);
|
|
823
|
+
this.spawn(this.loadPositionsSnapshot, client, messageHash, type);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
else {
|
|
827
|
+
this.positions[type] = new Cache.ArrayCacheBySymbolBySide();
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
async loadPositionsSnapshot(client, messageHash, type) {
|
|
831
|
+
const positions = await this.fetchPositions(undefined, { 'type': type });
|
|
832
|
+
this.positions[type] = new Cache.ArrayCacheBySymbolBySide();
|
|
833
|
+
const cache = this.positions[type];
|
|
834
|
+
for (let i = 0; i < positions.length; i++) {
|
|
835
|
+
const position = positions[i];
|
|
836
|
+
cache.append(position);
|
|
837
|
+
}
|
|
838
|
+
// don't remove the future from the .futures cache
|
|
839
|
+
const future = client.futures[messageHash];
|
|
840
|
+
future.resolve(cache);
|
|
841
|
+
client.resolve(cache, type + ':position');
|
|
842
|
+
}
|
|
843
|
+
handlePositions(client, message) {
|
|
844
|
+
//
|
|
845
|
+
// {
|
|
846
|
+
// time: 1693158497,
|
|
847
|
+
// time_ms: 1693158497204,
|
|
848
|
+
// channel: 'futures.positions',
|
|
849
|
+
// event: 'update',
|
|
850
|
+
// result: [{
|
|
851
|
+
// contract: 'XRP_USDT',
|
|
852
|
+
// cross_leverage_limit: 0,
|
|
853
|
+
// entry_price: 0.5253,
|
|
854
|
+
// history_pnl: 0,
|
|
855
|
+
// history_point: 0,
|
|
856
|
+
// last_close_pnl: 0,
|
|
857
|
+
// leverage: 0,
|
|
858
|
+
// leverage_max: 50,
|
|
859
|
+
// liq_price: 0.0361,
|
|
860
|
+
// maintenance_rate: 0.01,
|
|
861
|
+
// margin: 4.89609962852,
|
|
862
|
+
// mode: 'single',
|
|
863
|
+
// realised_pnl: -0.0026265,
|
|
864
|
+
// realised_point: 0,
|
|
865
|
+
// risk_limit: 500000,
|
|
866
|
+
// size: 1,
|
|
867
|
+
// time: 1693158497,
|
|
868
|
+
// time_ms: 1693158497195,
|
|
869
|
+
// update_id: 1,
|
|
870
|
+
// user: '10444586'
|
|
871
|
+
// }]
|
|
872
|
+
// }
|
|
873
|
+
//
|
|
874
|
+
const type = this.getMarketTypeByUrl(client.url);
|
|
875
|
+
const data = this.safeValue(message, 'result', []);
|
|
876
|
+
const cache = this.positions[type];
|
|
877
|
+
const newPositions = [];
|
|
878
|
+
for (let i = 0; i < data.length; i++) {
|
|
879
|
+
const rawPosition = data[i];
|
|
880
|
+
const position = this.parsePosition(rawPosition);
|
|
881
|
+
newPositions.push(position);
|
|
882
|
+
cache.append(position);
|
|
883
|
+
}
|
|
884
|
+
const messageHashes = this.findMessageHashes(client, type + ':positions::');
|
|
885
|
+
for (let i = 0; i < messageHashes.length; i++) {
|
|
886
|
+
const messageHash = messageHashes[i];
|
|
887
|
+
const parts = messageHash.split('::');
|
|
888
|
+
const symbolsString = parts[1];
|
|
889
|
+
const symbols = symbolsString.split(',');
|
|
890
|
+
const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
|
|
891
|
+
if (!this.isEmpty(positions)) {
|
|
892
|
+
client.resolve(positions, messageHash);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
client.resolve(newPositions, type + ':positions');
|
|
896
|
+
}
|
|
753
897
|
async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
754
898
|
/**
|
|
755
899
|
* @method
|
|
@@ -1036,6 +1180,7 @@ class gate extends gate$1 {
|
|
|
1036
1180
|
'usertrades': this.handleMyTrades,
|
|
1037
1181
|
'candlesticks': this.handleOHLCV,
|
|
1038
1182
|
'orders': this.handleOrder,
|
|
1183
|
+
'positions': this.handlePositions,
|
|
1039
1184
|
'tickers': this.handleTicker,
|
|
1040
1185
|
'book_ticker': this.handleTicker,
|
|
1041
1186
|
'trades': this.handleTrades,
|
|
@@ -1077,6 +1222,22 @@ class gate extends gate$1 {
|
|
|
1077
1222
|
return url;
|
|
1078
1223
|
}
|
|
1079
1224
|
}
|
|
1225
|
+
getMarketTypeByUrl(url) {
|
|
1226
|
+
const findBy = {
|
|
1227
|
+
'op-': 'option',
|
|
1228
|
+
'delivery': 'future',
|
|
1229
|
+
'fx': 'swap',
|
|
1230
|
+
};
|
|
1231
|
+
const keys = Object.keys(findBy);
|
|
1232
|
+
for (let i = 0; i < keys.length; i++) {
|
|
1233
|
+
const key = keys[i];
|
|
1234
|
+
const value = findBy[key];
|
|
1235
|
+
if (url.indexOf(key) >= 0) {
|
|
1236
|
+
return value;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
return 'spot';
|
|
1240
|
+
}
|
|
1080
1241
|
requestId() {
|
|
1081
1242
|
// their support said that reqid must be an int32, not documented
|
|
1082
1243
|
const reqid = this.sum(this.safeInteger(this.options, 'reqid', 0), 1);
|