ccxt 4.3.44 → 4.3.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 +130 -130
- package/dist/ccxt.browser.min.js +3 -3
- package/dist/cjs/ccxt.js +6 -1
- package/dist/cjs/src/abstract/oxfun.js +9 -0
- package/dist/cjs/src/base/Exchange.js +1 -0
- package/dist/cjs/src/binance.js +2 -0
- package/dist/cjs/src/bingx.js +25 -17
- package/dist/cjs/src/bitmart.js +5 -0
- package/dist/cjs/src/bitstamp.js +18 -2
- package/dist/cjs/src/bitteam.js +5 -7
- package/dist/cjs/src/coinmetro.js +8 -17
- package/dist/cjs/src/hyperliquid.js +29 -21
- package/dist/cjs/src/idex.js +1 -0
- package/dist/cjs/src/kucoin.js +28 -1
- package/dist/cjs/src/luno.js +9 -1
- package/dist/cjs/src/mexc.js +8 -6
- package/dist/cjs/src/okx.js +1 -0
- package/dist/cjs/src/oxfun.js +2900 -0
- package/dist/cjs/src/pro/binanceus.js +0 -8
- package/dist/cjs/src/pro/oxfun.js +1034 -0
- package/dist/cjs/src/tokocrypto.js +8 -10
- package/dist/cjs/src/wavesexchange.js +122 -110
- package/dist/cjs/src/woofipro.js +1 -0
- package/dist/cjs/src/xt.js +1 -1
- package/js/ccxt.d.ts +8 -2
- package/js/ccxt.js +6 -2
- package/js/src/abstract/binance.d.ts +2 -0
- package/js/src/abstract/binancecoinm.d.ts +2 -0
- package/js/src/abstract/binanceus.d.ts +2 -0
- package/js/src/abstract/binanceusdm.d.ts +2 -0
- package/js/src/abstract/bitstamp.d.ts +16 -0
- package/js/src/abstract/kucoin.d.ts +14 -0
- package/js/src/abstract/kucoinfutures.d.ts +14 -0
- package/js/src/abstract/mexc.d.ts +2 -0
- package/js/src/abstract/oxfun.d.ts +37 -0
- package/js/src/abstract/oxfun.js +11 -0
- package/js/src/base/Exchange.d.ts +1 -0
- package/js/src/base/Exchange.js +1 -0
- package/js/src/binance.js +2 -0
- package/js/src/bingx.js +26 -18
- package/js/src/bitmart.js +5 -0
- package/js/src/bitstamp.js +18 -2
- package/js/src/bitteam.js +6 -8
- package/js/src/coinmetro.js +9 -18
- package/js/src/hyperliquid.d.ts +3 -3
- package/js/src/hyperliquid.js +29 -21
- package/js/src/idex.js +1 -0
- package/js/src/kucoin.js +28 -1
- package/js/src/luno.d.ts +1 -1
- package/js/src/luno.js +9 -1
- package/js/src/mexc.js +8 -6
- package/js/src/okx.js +1 -0
- package/js/src/oxfun.d.ts +129 -0
- package/js/src/oxfun.js +2901 -0
- package/js/src/pro/binanceus.js +0 -8
- package/js/src/pro/oxfun.d.ts +38 -0
- package/js/src/pro/oxfun.js +1035 -0
- package/js/src/static_dependencies/jsencrypt/lib/jsbn/jsbn.d.ts +1 -1
- package/js/src/tokocrypto.js +9 -11
- package/js/src/wavesexchange.d.ts +7 -7
- package/js/src/wavesexchange.js +123 -111
- package/js/src/woofipro.js +1 -0
- package/js/src/xt.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,1035 @@
|
|
|
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 oxfunRest from '../oxfun.js';
|
|
9
|
+
import { ArgumentsRequired, AuthenticationError, BadRequest } from '../base/errors.js';
|
|
10
|
+
import { sha256 } from '../static_dependencies/noble-hashes/sha256.js';
|
|
11
|
+
import { ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp } from '../base/ws/Cache.js';
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
export default class oxfun extends oxfunRest {
|
|
14
|
+
describe() {
|
|
15
|
+
return this.deepExtend(super.describe(), {
|
|
16
|
+
'has': {
|
|
17
|
+
'ws': true,
|
|
18
|
+
'watchTrades': true,
|
|
19
|
+
'watchTradesForSymbols': true,
|
|
20
|
+
'watchOrderBook': true,
|
|
21
|
+
'watchOrderBookForSymbols': true,
|
|
22
|
+
'watchOHLCV': true,
|
|
23
|
+
'watchOHLCVForSymbols': true,
|
|
24
|
+
'watchOrders': true,
|
|
25
|
+
'watchMyTrades': false,
|
|
26
|
+
'watchTicker': true,
|
|
27
|
+
'watchTickers': true,
|
|
28
|
+
'watchBalance': true,
|
|
29
|
+
'createOrderWs': true,
|
|
30
|
+
'editOrderWs': true,
|
|
31
|
+
'cancelOrderWs': true,
|
|
32
|
+
'cancelOrdersWs': true,
|
|
33
|
+
},
|
|
34
|
+
'urls': {
|
|
35
|
+
'api': {
|
|
36
|
+
'ws': 'wss://api.ox.fun/v2/websocket',
|
|
37
|
+
'test': 'wss://stgapi.ox.fun/v2/websocket',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
'options': {
|
|
41
|
+
'timeframes': {
|
|
42
|
+
'1m': '60s',
|
|
43
|
+
'3m': '180s',
|
|
44
|
+
'5m': '300s',
|
|
45
|
+
'15m': '900s',
|
|
46
|
+
'30m': '1800s',
|
|
47
|
+
'1h': '3600s',
|
|
48
|
+
'2h': '7200s',
|
|
49
|
+
'4h': '14400s',
|
|
50
|
+
'6h': '21600s',
|
|
51
|
+
'12h': '43200s',
|
|
52
|
+
'1d': '86400s',
|
|
53
|
+
},
|
|
54
|
+
'watchOrderBook': {
|
|
55
|
+
'channel': 'depth', // depth, depthL5, depthL10, depthL25
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
'streaming': {
|
|
59
|
+
'ping': this.ping,
|
|
60
|
+
'keepAlive': 50000,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async subscribeMultiple(messageHashes, argsArray, params = {}) {
|
|
65
|
+
const url = this.urls['api']['ws'];
|
|
66
|
+
const request = {
|
|
67
|
+
'op': 'subscribe',
|
|
68
|
+
'args': argsArray,
|
|
69
|
+
};
|
|
70
|
+
return await this.watchMultiple(url, messageHashes, this.extend(request, params), messageHashes);
|
|
71
|
+
}
|
|
72
|
+
async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
|
|
73
|
+
/**
|
|
74
|
+
* @method
|
|
75
|
+
* @name oxfun#watchTrades
|
|
76
|
+
* @description watches information on multiple trades made in a market
|
|
77
|
+
* @see https://docs.ox.fun/?json#trade
|
|
78
|
+
* @param {string} symbol unified market symbol of the market trades were made in
|
|
79
|
+
* @param {int} [since] the earliest time in ms to fetch orders for
|
|
80
|
+
* @param {int} [limit] the maximum number of trade structures to retrieve
|
|
81
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
82
|
+
* @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
|
|
83
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure
|
|
84
|
+
*/
|
|
85
|
+
return await this.watchTradesForSymbols([symbol], since, limit, params);
|
|
86
|
+
}
|
|
87
|
+
async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
|
|
88
|
+
/**
|
|
89
|
+
* @method
|
|
90
|
+
* @name oxfun#watchTradesForSymbols
|
|
91
|
+
* @description get the list of most recent trades for a particular symbol
|
|
92
|
+
* @see https://docs.ox.fun/?json#trade
|
|
93
|
+
* @param {string} symbol unified symbol of the market to fetch trades for
|
|
94
|
+
* @param {int} [since] timestamp in ms of the earliest trade to fetch
|
|
95
|
+
* @param {int} [limit] the maximum amount of trades to fetch
|
|
96
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
97
|
+
* @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
|
|
98
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
|
|
99
|
+
*/
|
|
100
|
+
await this.loadMarkets();
|
|
101
|
+
symbols = this.marketSymbols(symbols, undefined, false);
|
|
102
|
+
const args = [];
|
|
103
|
+
const messageHashes = [];
|
|
104
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
105
|
+
const symbol = symbols[i];
|
|
106
|
+
const messageHash = 'trades' + ':' + symbol;
|
|
107
|
+
messageHashes.push(messageHash);
|
|
108
|
+
const marketId = this.marketId(symbol);
|
|
109
|
+
const arg = 'trade:' + marketId;
|
|
110
|
+
args.push(arg);
|
|
111
|
+
}
|
|
112
|
+
const trades = await this.subscribeMultiple(messageHashes, args, params);
|
|
113
|
+
if (this.newUpdates) {
|
|
114
|
+
const first = this.safeDict(trades, 0, {});
|
|
115
|
+
const tradeSymbol = this.safeString(first, 'symbol');
|
|
116
|
+
limit = trades.getLimit(tradeSymbol, limit);
|
|
117
|
+
}
|
|
118
|
+
return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
|
|
119
|
+
}
|
|
120
|
+
handleTrades(client, message) {
|
|
121
|
+
//
|
|
122
|
+
// {
|
|
123
|
+
// table: 'trade',
|
|
124
|
+
// data: [
|
|
125
|
+
// {
|
|
126
|
+
// side: 'SELL',
|
|
127
|
+
// quantity: '0.074',
|
|
128
|
+
// matchType: 'TAKER',
|
|
129
|
+
// price: '3079.5',
|
|
130
|
+
// marketCode: 'ETH-USD-SWAP-LIN',
|
|
131
|
+
// tradeId: '400017157974517783',
|
|
132
|
+
// timestamp: '1716124156643'
|
|
133
|
+
// }
|
|
134
|
+
// ]
|
|
135
|
+
// }
|
|
136
|
+
//
|
|
137
|
+
const data = this.safeList(message, 'data', []);
|
|
138
|
+
for (let i = 0; i < data.length; i++) {
|
|
139
|
+
const trade = this.safeDict(data, i, {});
|
|
140
|
+
const parsedTrade = this.parseWsTrade(trade);
|
|
141
|
+
const symbol = this.safeString(parsedTrade, 'symbol');
|
|
142
|
+
const messageHash = 'trades:' + symbol;
|
|
143
|
+
if (!(symbol in this.trades)) {
|
|
144
|
+
const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
|
|
145
|
+
this.trades[symbol] = new ArrayCache(tradesLimit);
|
|
146
|
+
}
|
|
147
|
+
const stored = this.trades[symbol];
|
|
148
|
+
stored.append(parsedTrade);
|
|
149
|
+
client.resolve(stored, messageHash);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
parseWsTrade(trade, market = undefined) {
|
|
153
|
+
//
|
|
154
|
+
// {
|
|
155
|
+
// side: 'SELL',
|
|
156
|
+
// quantity: '0.074',
|
|
157
|
+
// matchType: 'TAKER',
|
|
158
|
+
// price: '3079.5',
|
|
159
|
+
// marketCode: 'ETH-USD-SWAP-LIN',
|
|
160
|
+
// tradeId: '400017157974517783',
|
|
161
|
+
// timestamp: '1716124156643'
|
|
162
|
+
// }
|
|
163
|
+
//
|
|
164
|
+
const marketId = this.safeString(trade, 'marketCode');
|
|
165
|
+
market = this.safeMarket(marketId, market);
|
|
166
|
+
const timestamp = this.safeInteger(trade, 'timestamp');
|
|
167
|
+
return this.safeTrade({
|
|
168
|
+
'info': trade,
|
|
169
|
+
'timestamp': timestamp,
|
|
170
|
+
'datetime': this.iso8601(timestamp),
|
|
171
|
+
'symbol': market['symbol'],
|
|
172
|
+
'id': this.safeString(trade, 'tradeId'),
|
|
173
|
+
'order': undefined,
|
|
174
|
+
'type': undefined,
|
|
175
|
+
'takerOrMaker': this.safeStringLower(trade, 'matchType'),
|
|
176
|
+
'side': this.safeStringLower(trade, 'side'),
|
|
177
|
+
'price': this.safeNumber(trade, 'price'),
|
|
178
|
+
'amount': this.safeNumber(trade, 'quantity'),
|
|
179
|
+
'cost': undefined,
|
|
180
|
+
'fee': undefined,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
|
184
|
+
/**
|
|
185
|
+
* @method
|
|
186
|
+
* @name oxfun#watchOHLCV
|
|
187
|
+
* @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
188
|
+
* @see https://docs.ox.fun/?json#candles
|
|
189
|
+
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
190
|
+
* @param {string} timeframe the length of time each candle represents
|
|
191
|
+
* @param {int} [since] timestamp in ms of the earliest candle to fetch
|
|
192
|
+
* @param {int} [limit] the maximum amount of candles to fetch
|
|
193
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
194
|
+
* @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
|
|
195
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
196
|
+
*/
|
|
197
|
+
await this.loadMarkets();
|
|
198
|
+
const market = this.market(symbol);
|
|
199
|
+
const timeframes = this.safeDict(this.options, 'timeframes', {});
|
|
200
|
+
const interval = this.safeString(timeframes, timeframe, timeframe);
|
|
201
|
+
const args = 'candles' + interval + ':' + market['id'];
|
|
202
|
+
const messageHash = 'ohlcv:' + symbol + ':' + timeframe;
|
|
203
|
+
const url = this.urls['api']['ws'];
|
|
204
|
+
const request = {
|
|
205
|
+
'op': 'subscribe',
|
|
206
|
+
'args': [args],
|
|
207
|
+
};
|
|
208
|
+
const ohlcvs = await this.watch(url, messageHash, this.extend(request, params), messageHash);
|
|
209
|
+
if (this.newUpdates) {
|
|
210
|
+
limit = ohlcvs.getLimit(symbol, limit);
|
|
211
|
+
}
|
|
212
|
+
return this.filterBySinceLimit(ohlcvs, since, limit, 0, true);
|
|
213
|
+
}
|
|
214
|
+
async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
|
|
215
|
+
/**
|
|
216
|
+
* @method
|
|
217
|
+
* @name oxfun#watchOHLCVForSymbols
|
|
218
|
+
* @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
219
|
+
* @see https://docs.ox.fun/?json#candles
|
|
220
|
+
* @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
|
|
221
|
+
* @param {int} [since] timestamp in ms of the earliest candle to fetch
|
|
222
|
+
* @param {int} [limit] the maximum amount of candles to fetch
|
|
223
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
224
|
+
* @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
|
|
225
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
226
|
+
*/
|
|
227
|
+
const symbolsLength = symbolsAndTimeframes.length;
|
|
228
|
+
if (symbolsLength === 0 || !Array.isArray(symbolsAndTimeframes[0])) {
|
|
229
|
+
throw new ArgumentsRequired(this.id + " watchOHLCVForSymbols() requires a an array of symbols and timeframes, like [['BTC/USDT:OX', '1m'], ['OX/USDT', '5m']]");
|
|
230
|
+
}
|
|
231
|
+
await this.loadMarkets();
|
|
232
|
+
const args = [];
|
|
233
|
+
const messageHashes = [];
|
|
234
|
+
const timeframes = this.safeDict(this.options, 'timeframes', {});
|
|
235
|
+
for (let i = 0; i < symbolsAndTimeframes.length; i++) {
|
|
236
|
+
const symbolAndTimeframe = symbolsAndTimeframes[i];
|
|
237
|
+
const sym = symbolAndTimeframe[0];
|
|
238
|
+
const tf = symbolAndTimeframe[1];
|
|
239
|
+
const marketId = this.marketId(sym);
|
|
240
|
+
const interval = this.safeString(timeframes, tf, tf);
|
|
241
|
+
const arg = 'candles' + interval + ':' + marketId;
|
|
242
|
+
args.push(arg);
|
|
243
|
+
const messageHash = 'multi:ohlcv:' + sym + ':' + tf;
|
|
244
|
+
messageHashes.push(messageHash);
|
|
245
|
+
}
|
|
246
|
+
const [symbol, timeframe, candles] = await this.subscribeMultiple(messageHashes, args, params);
|
|
247
|
+
if (this.newUpdates) {
|
|
248
|
+
limit = candles.getLimit(symbol, limit);
|
|
249
|
+
}
|
|
250
|
+
const filtered = this.filterBySinceLimit(candles, since, limit, 0, true);
|
|
251
|
+
return this.createOHLCVObject(symbol, timeframe, filtered);
|
|
252
|
+
}
|
|
253
|
+
handleOHLCV(client, message) {
|
|
254
|
+
//
|
|
255
|
+
// {
|
|
256
|
+
// "table": "candles60s",
|
|
257
|
+
// "data": [
|
|
258
|
+
// {
|
|
259
|
+
// "marketCode": "BTC-USD-SWAP-LIN",
|
|
260
|
+
// "candle": [
|
|
261
|
+
// "1594313762698", //timestamp
|
|
262
|
+
// "9633.1", //open
|
|
263
|
+
// "9693.9", //high
|
|
264
|
+
// "9238.1", //low
|
|
265
|
+
// "9630.2", //close
|
|
266
|
+
// "45247", //volume in OX
|
|
267
|
+
// "5.3" //volume in Contracts
|
|
268
|
+
// ]
|
|
269
|
+
// }
|
|
270
|
+
// ]
|
|
271
|
+
// }
|
|
272
|
+
//
|
|
273
|
+
const table = this.safeString(message, 'table');
|
|
274
|
+
const parts = table.split('candles');
|
|
275
|
+
const timeframeId = this.safeString(parts, 1, '');
|
|
276
|
+
const timeframe = this.findTimeframe(timeframeId);
|
|
277
|
+
const messageData = this.safeList(message, 'data', []);
|
|
278
|
+
const data = this.safeDict(messageData, 0, {});
|
|
279
|
+
const marketId = this.safeString(data, 'marketCode');
|
|
280
|
+
const market = this.safeMarket(marketId);
|
|
281
|
+
const symbol = this.safeSymbol(marketId, market);
|
|
282
|
+
if (!(symbol in this.ohlcvs)) {
|
|
283
|
+
this.ohlcvs[symbol] = {};
|
|
284
|
+
}
|
|
285
|
+
if (!(timeframe in this.ohlcvs[symbol])) {
|
|
286
|
+
const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
|
|
287
|
+
this.ohlcvs[symbol][timeframe] = new ArrayCacheByTimestamp(limit);
|
|
288
|
+
}
|
|
289
|
+
const candle = this.safeList(data, 'candle', []);
|
|
290
|
+
const parsed = this.parseWsOHLCV(candle, market);
|
|
291
|
+
const stored = this.ohlcvs[symbol][timeframe];
|
|
292
|
+
stored.append(parsed);
|
|
293
|
+
const messageHash = 'ohlcv:' + symbol + ':' + timeframe;
|
|
294
|
+
client.resolve(stored, messageHash);
|
|
295
|
+
// for multiOHLCV we need special object, as opposed to other "multi"
|
|
296
|
+
// methods, because OHLCV response item does not contain symbol
|
|
297
|
+
// or timeframe, thus otherwise it would be unrecognizable
|
|
298
|
+
const messageHashForMulti = 'multi:' + messageHash;
|
|
299
|
+
client.resolve([symbol, timeframe, stored], messageHashForMulti);
|
|
300
|
+
}
|
|
301
|
+
parseWsOHLCV(ohlcv, market = undefined) {
|
|
302
|
+
//
|
|
303
|
+
// [
|
|
304
|
+
// "1594313762698", //timestamp
|
|
305
|
+
// "9633.1", //open
|
|
306
|
+
// "9693.9", //high
|
|
307
|
+
// "9238.1", //low
|
|
308
|
+
// "9630.2", //close
|
|
309
|
+
// "45247", //volume in OX
|
|
310
|
+
// "5.3" //volume in Contracts
|
|
311
|
+
// ]
|
|
312
|
+
//
|
|
313
|
+
return [
|
|
314
|
+
this.safeInteger(ohlcv, 0),
|
|
315
|
+
this.safeNumber(ohlcv, 1),
|
|
316
|
+
this.safeNumber(ohlcv, 2),
|
|
317
|
+
this.safeNumber(ohlcv, 3),
|
|
318
|
+
this.safeNumber(ohlcv, 4),
|
|
319
|
+
this.safeNumber(ohlcv, 6),
|
|
320
|
+
];
|
|
321
|
+
}
|
|
322
|
+
async watchOrderBook(symbol, limit = undefined, params = {}) {
|
|
323
|
+
/**
|
|
324
|
+
* @method
|
|
325
|
+
* @name oxfun#watchOrderBook
|
|
326
|
+
* @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
327
|
+
* @see https://docs.ox.fun/?json#fixed-size-order-book
|
|
328
|
+
* @see https://docs.ox.fun/?json#full-order-book
|
|
329
|
+
* @param {string} symbol unified symbol of the market to fetch the order book for
|
|
330
|
+
* @param {int} [limit] the maximum amount of order book entries to return
|
|
331
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
332
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
333
|
+
*/
|
|
334
|
+
return await this.watchOrderBookForSymbols([symbol], limit, params);
|
|
335
|
+
}
|
|
336
|
+
async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
|
|
337
|
+
/**
|
|
338
|
+
* @method
|
|
339
|
+
* @name oxfun#watchOrderBookForSymbols
|
|
340
|
+
* @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
341
|
+
* @see https://docs.ox.fun/?json#fixed-size-order-book
|
|
342
|
+
* @see https://docs.ox.fun/?json#full-order-book
|
|
343
|
+
* @param {string[]} symbols unified array of symbols
|
|
344
|
+
* @param {int} [limit] the maximum amount of order book entries to return
|
|
345
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
346
|
+
* @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
|
|
347
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
348
|
+
*/
|
|
349
|
+
await this.loadMarkets();
|
|
350
|
+
symbols = this.marketSymbols(symbols);
|
|
351
|
+
let channel = 'depth';
|
|
352
|
+
const options = this.safeDict(this.options, 'watchOrderBook', {});
|
|
353
|
+
const defaultChannel = this.safeString(options, 'channel');
|
|
354
|
+
if (defaultChannel !== undefined) {
|
|
355
|
+
channel = defaultChannel;
|
|
356
|
+
}
|
|
357
|
+
else if (limit !== undefined) {
|
|
358
|
+
if (limit <= 5) {
|
|
359
|
+
channel = 'depthL5';
|
|
360
|
+
}
|
|
361
|
+
else if (limit <= 10) {
|
|
362
|
+
channel = 'depthL10';
|
|
363
|
+
}
|
|
364
|
+
else if (limit <= 25) {
|
|
365
|
+
channel = 'depthL25';
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
const args = [];
|
|
369
|
+
const messageHashes = [];
|
|
370
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
371
|
+
const symbol = symbols[i];
|
|
372
|
+
const messageHash = 'orderbook:' + symbol;
|
|
373
|
+
messageHashes.push(messageHash);
|
|
374
|
+
const marketId = this.marketId(symbol);
|
|
375
|
+
const arg = channel + ':' + marketId;
|
|
376
|
+
args.push(arg);
|
|
377
|
+
}
|
|
378
|
+
const orderbook = await this.subscribeMultiple(messageHashes, args, params);
|
|
379
|
+
return orderbook.limit();
|
|
380
|
+
}
|
|
381
|
+
handleOrderBook(client, message) {
|
|
382
|
+
//
|
|
383
|
+
// {
|
|
384
|
+
// "table": "depth",
|
|
385
|
+
// "data": {
|
|
386
|
+
// "seqNum": "100170478917895032",
|
|
387
|
+
// "asks": [
|
|
388
|
+
// [ 0.01, 100500 ],
|
|
389
|
+
// ...
|
|
390
|
+
// ],
|
|
391
|
+
// "bids": [
|
|
392
|
+
// [ 69.69696, 69 ],
|
|
393
|
+
// ...
|
|
394
|
+
// ],
|
|
395
|
+
// "checksum": 261021645,
|
|
396
|
+
// "marketCode": "OX-USDT",
|
|
397
|
+
// "timestamp": 1716204786184
|
|
398
|
+
// },
|
|
399
|
+
// "action": "partial"
|
|
400
|
+
// }
|
|
401
|
+
//
|
|
402
|
+
const data = this.safeDict(message, 'data', {});
|
|
403
|
+
const marketId = this.safeString(data, 'marketCode');
|
|
404
|
+
const symbol = this.safeSymbol(marketId);
|
|
405
|
+
const timestamp = this.safeInteger(data, 'timestamp');
|
|
406
|
+
const messageHash = 'orderbook:' + symbol;
|
|
407
|
+
if (!(symbol in this.orderbooks)) {
|
|
408
|
+
this.orderbooks[symbol] = this.orderBook({});
|
|
409
|
+
}
|
|
410
|
+
const orderbook = this.orderbooks[symbol];
|
|
411
|
+
const snapshot = this.parseOrderBook(data, symbol, timestamp, 'asks', 'bids');
|
|
412
|
+
orderbook.reset(snapshot);
|
|
413
|
+
orderbook['nonce'] = this.safeInteger(data, 'seqNum');
|
|
414
|
+
this.orderbooks[symbol] = orderbook;
|
|
415
|
+
client.resolve(orderbook, messageHash);
|
|
416
|
+
}
|
|
417
|
+
async watchTicker(symbol, params = {}) {
|
|
418
|
+
/**
|
|
419
|
+
* @method
|
|
420
|
+
* @name oxfun#watchTicker
|
|
421
|
+
* @see https://docs.ox.fun/?json#ticker
|
|
422
|
+
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
423
|
+
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
424
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
425
|
+
* @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
|
|
426
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
427
|
+
*/
|
|
428
|
+
const ticker = await this.watchTickers([symbol], params);
|
|
429
|
+
return this.safeValue(ticker, symbol);
|
|
430
|
+
}
|
|
431
|
+
async watchTickers(symbols = undefined, params = {}) {
|
|
432
|
+
/**
|
|
433
|
+
* @method
|
|
434
|
+
* @name oxfun#watchTickers
|
|
435
|
+
* @see https://docs.ox.fun/?json#ticker
|
|
436
|
+
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
|
437
|
+
* @param {string[]} [symbols] unified symbol of the market to fetch the ticker for
|
|
438
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
439
|
+
* @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
|
|
440
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
441
|
+
*/
|
|
442
|
+
await this.loadMarkets();
|
|
443
|
+
const allSymbols = (symbols === undefined);
|
|
444
|
+
let sym = symbols;
|
|
445
|
+
const args = [];
|
|
446
|
+
if (allSymbols) {
|
|
447
|
+
sym = this.symbols;
|
|
448
|
+
args.push('ticker:all');
|
|
449
|
+
}
|
|
450
|
+
const messageHashes = [];
|
|
451
|
+
for (let i = 0; i < sym.length; i++) {
|
|
452
|
+
const symbol = sym[i];
|
|
453
|
+
const messageHash = 'tickers' + ':' + symbol;
|
|
454
|
+
messageHashes.push(messageHash);
|
|
455
|
+
const marketId = this.marketId(symbol);
|
|
456
|
+
if (!allSymbols) {
|
|
457
|
+
args.push('ticker:' + marketId);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
const newTicker = await this.subscribeMultiple(messageHashes, args, params);
|
|
461
|
+
if (this.newUpdates) {
|
|
462
|
+
const result = {};
|
|
463
|
+
result[newTicker['symbol']] = newTicker;
|
|
464
|
+
return result;
|
|
465
|
+
}
|
|
466
|
+
return this.filterByArray(this.tickers, 'symbol', symbols);
|
|
467
|
+
}
|
|
468
|
+
handleTicker(client, message) {
|
|
469
|
+
//
|
|
470
|
+
// {
|
|
471
|
+
// "table": "ticker",
|
|
472
|
+
// "data": [
|
|
473
|
+
// {
|
|
474
|
+
// "last": "3088.6",
|
|
475
|
+
// "open24h": "3087.2",
|
|
476
|
+
// "high24h": "3142.0",
|
|
477
|
+
// "low24h": "3053.9",
|
|
478
|
+
// "volume24h": "450512672.1800",
|
|
479
|
+
// "currencyVolume24h": "1458.579",
|
|
480
|
+
// "openInterest": "3786.801",
|
|
481
|
+
// "marketCode": "ETH-USD-SWAP-LIN",
|
|
482
|
+
// "timestamp": "1716212747050",
|
|
483
|
+
// "lastQty": "0.813",
|
|
484
|
+
// "markPrice": "3088.6",
|
|
485
|
+
// "lastMarkPrice": "3088.6",
|
|
486
|
+
// "indexPrice": "3086.5"
|
|
487
|
+
// },
|
|
488
|
+
// ...
|
|
489
|
+
// ]
|
|
490
|
+
// }
|
|
491
|
+
//
|
|
492
|
+
const data = this.safeList(message, 'data', []);
|
|
493
|
+
for (let i = 0; i < data.length; i++) {
|
|
494
|
+
const rawTicker = this.safeDict(data, i, {});
|
|
495
|
+
const ticker = this.parseTicker(rawTicker);
|
|
496
|
+
const symbol = ticker['symbol'];
|
|
497
|
+
const messageHash = 'tickers:' + symbol;
|
|
498
|
+
this.tickers[symbol] = ticker;
|
|
499
|
+
client.resolve(ticker, messageHash);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
async watchBalance(params = {}) {
|
|
503
|
+
/**
|
|
504
|
+
* @method
|
|
505
|
+
* @name oxfun#watchBalance
|
|
506
|
+
* @see https://docs.ox.fun/?json#balance-channel
|
|
507
|
+
* @description watch balance and get the amount of funds available for trading or funds locked in orders
|
|
508
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
509
|
+
* @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
|
|
510
|
+
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
|
|
511
|
+
*/
|
|
512
|
+
await this.loadMarkets();
|
|
513
|
+
this.authenticate();
|
|
514
|
+
const args = 'balance:all';
|
|
515
|
+
const messageHash = 'balance';
|
|
516
|
+
const url = this.urls['api']['ws'];
|
|
517
|
+
const request = {
|
|
518
|
+
'op': 'subscribe',
|
|
519
|
+
'args': [args],
|
|
520
|
+
};
|
|
521
|
+
return await this.watch(url, messageHash, this.extend(request, params), messageHash);
|
|
522
|
+
}
|
|
523
|
+
handleBalance(client, message) {
|
|
524
|
+
//
|
|
525
|
+
// {
|
|
526
|
+
// "table": "balance",
|
|
527
|
+
// "accountId": "106464",
|
|
528
|
+
// "timestamp": "1716549132780",
|
|
529
|
+
// "tradeType": "PORTFOLIO",
|
|
530
|
+
// "data": [
|
|
531
|
+
// {
|
|
532
|
+
// "instrumentId": "xOX",
|
|
533
|
+
// "total": "23.375591220",
|
|
534
|
+
// "available": "23.375591220",
|
|
535
|
+
// "reserved": "0",
|
|
536
|
+
// "quantityLastUpdated": "1716509744262",
|
|
537
|
+
// "locked": "0"
|
|
538
|
+
// },
|
|
539
|
+
// ...
|
|
540
|
+
// ]
|
|
541
|
+
// }
|
|
542
|
+
//
|
|
543
|
+
const balances = this.safeList(message, 'data');
|
|
544
|
+
const timestamp = this.safeInteger(message, 'timestamp');
|
|
545
|
+
this.balance['info'] = message;
|
|
546
|
+
this.balance['timestamp'] = timestamp;
|
|
547
|
+
this.balance['datetime'] = this.iso8601(timestamp);
|
|
548
|
+
for (let i = 0; i < balances.length; i++) {
|
|
549
|
+
const balance = this.safeDict(balances, i, {});
|
|
550
|
+
const currencyId = this.safeString(balance, 'instrumentId');
|
|
551
|
+
const code = this.safeCurrencyCode(currencyId);
|
|
552
|
+
if (!(code in this.balance)) {
|
|
553
|
+
this.balance[code] = this.account();
|
|
554
|
+
}
|
|
555
|
+
const account = this.balance[code];
|
|
556
|
+
account['total'] = this.safeString(balance, 'total');
|
|
557
|
+
account['used'] = this.safeString(balance, 'reserved');
|
|
558
|
+
account['free'] = this.safeString(balance, 'available');
|
|
559
|
+
this.balance[code] = account;
|
|
560
|
+
}
|
|
561
|
+
this.balance = this.safeBalance(this.balance);
|
|
562
|
+
client.resolve(this.balance, 'balance');
|
|
563
|
+
}
|
|
564
|
+
async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
|
|
565
|
+
/**
|
|
566
|
+
* @method
|
|
567
|
+
* @name oxfun#watchPositions
|
|
568
|
+
* @see https://docs.ox.fun/?json#position-channel
|
|
569
|
+
* @description watch all open positions
|
|
570
|
+
* @param {string[]|undefined} symbols list of unified market symbols
|
|
571
|
+
* @param {object} params extra parameters specific to the exchange API endpoint
|
|
572
|
+
* @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
|
|
573
|
+
* @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
|
|
574
|
+
*/
|
|
575
|
+
await this.loadMarkets();
|
|
576
|
+
await this.authenticate();
|
|
577
|
+
const allSymbols = (symbols === undefined);
|
|
578
|
+
let sym = symbols;
|
|
579
|
+
const args = [];
|
|
580
|
+
if (allSymbols) {
|
|
581
|
+
sym = this.symbols;
|
|
582
|
+
args.push('position:all');
|
|
583
|
+
}
|
|
584
|
+
const messageHashes = [];
|
|
585
|
+
for (let i = 0; i < sym.length; i++) {
|
|
586
|
+
const symbol = sym[i];
|
|
587
|
+
const messageHash = 'positions' + ':' + symbol;
|
|
588
|
+
messageHashes.push(messageHash);
|
|
589
|
+
const marketId = this.marketId(symbol);
|
|
590
|
+
if (!allSymbols) {
|
|
591
|
+
args.push('position:' + marketId);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
const newPositions = await this.subscribeMultiple(messageHashes, args, params);
|
|
595
|
+
if (this.newUpdates) {
|
|
596
|
+
return newPositions;
|
|
597
|
+
}
|
|
598
|
+
return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
|
|
599
|
+
}
|
|
600
|
+
handlePositions(client, message) {
|
|
601
|
+
//
|
|
602
|
+
// {
|
|
603
|
+
// "table": "position",
|
|
604
|
+
// "accountId": "106464",
|
|
605
|
+
// "timestamp": "1716550771582",
|
|
606
|
+
// "data": [
|
|
607
|
+
// {
|
|
608
|
+
// "instrumentId": "ETH-USD-SWAP-LIN",
|
|
609
|
+
// "quantity": "0.01",
|
|
610
|
+
// "lastUpdated": "1716550757299",
|
|
611
|
+
// "contractValCurrency": "ETH",
|
|
612
|
+
// "entryPrice": "3709.6",
|
|
613
|
+
// "positionPnl": "-5.000",
|
|
614
|
+
// "estLiquidationPrice": "743.4",
|
|
615
|
+
// "margin": "0",
|
|
616
|
+
// "leverage": "0"
|
|
617
|
+
// }
|
|
618
|
+
// ]
|
|
619
|
+
// }
|
|
620
|
+
//
|
|
621
|
+
if (this.positions === undefined) {
|
|
622
|
+
this.positions = new ArrayCacheBySymbolBySide();
|
|
623
|
+
}
|
|
624
|
+
const cache = this.positions;
|
|
625
|
+
const data = this.safeList(message, 'data', []);
|
|
626
|
+
for (let i = 0; i < data.length; i++) {
|
|
627
|
+
const rawPosition = this.safeDict(data, i, {});
|
|
628
|
+
const position = this.parseWsPosition(rawPosition);
|
|
629
|
+
const symbol = position['symbol'];
|
|
630
|
+
const messageHash = 'positions:' + symbol;
|
|
631
|
+
cache.append(position);
|
|
632
|
+
client.resolve(position, messageHash);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
parseWsPosition(position, market = undefined) {
|
|
636
|
+
//
|
|
637
|
+
// {
|
|
638
|
+
// "instrumentId": "ETH-USD-SWAP-LIN",
|
|
639
|
+
// "quantity": "0.01",
|
|
640
|
+
// "lastUpdated": "1716550757299",
|
|
641
|
+
// "contractValCurrency": "ETH",
|
|
642
|
+
// "entryPrice": "3709.6",
|
|
643
|
+
// "positionPnl": "-5.000",
|
|
644
|
+
// "estLiquidationPrice": "743.4",
|
|
645
|
+
// "margin": "0", // Currently always reports 0
|
|
646
|
+
// "leverage": "0" // Currently always reports 0
|
|
647
|
+
// }
|
|
648
|
+
//
|
|
649
|
+
const marketId = this.safeString(position, 'instrumentId');
|
|
650
|
+
market = this.safeMarket(marketId, market);
|
|
651
|
+
return this.safePosition({
|
|
652
|
+
'info': position,
|
|
653
|
+
'id': undefined,
|
|
654
|
+
'symbol': market['symbol'],
|
|
655
|
+
'notional': undefined,
|
|
656
|
+
'marginMode': 'cross',
|
|
657
|
+
'liquidationPrice': this.safeNumber(position, 'estLiquidationPrice'),
|
|
658
|
+
'entryPrice': this.safeNumber(position, 'entryPrice'),
|
|
659
|
+
'unrealizedPnl': this.safeNumber(position, 'positionPnl'),
|
|
660
|
+
'realizedPnl': undefined,
|
|
661
|
+
'percentage': undefined,
|
|
662
|
+
'contracts': this.safeNumber(position, 'quantity'),
|
|
663
|
+
'contractSize': undefined,
|
|
664
|
+
'markPrice': undefined,
|
|
665
|
+
'lastPrice': undefined,
|
|
666
|
+
'side': undefined,
|
|
667
|
+
'hedged': undefined,
|
|
668
|
+
'timestamp': undefined,
|
|
669
|
+
'datetime': undefined,
|
|
670
|
+
'lastUpdateTimestamp': this.safeInteger(position, 'lastUpdated'),
|
|
671
|
+
'maintenanceMargin': undefined,
|
|
672
|
+
'maintenanceMarginPercentage': undefined,
|
|
673
|
+
'collateral': undefined,
|
|
674
|
+
'initialMargin': undefined,
|
|
675
|
+
'initialMarginPercentage': undefined,
|
|
676
|
+
'leverage': undefined,
|
|
677
|
+
'marginRatio': undefined,
|
|
678
|
+
'stopLossPrice': undefined,
|
|
679
|
+
'takeProfitPrice': undefined,
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
683
|
+
/**
|
|
684
|
+
* @method
|
|
685
|
+
* @name oxfun#watchOrders
|
|
686
|
+
* @description watches information on multiple orders made by the user
|
|
687
|
+
* @see https://docs.ox.fun/?json#order-channel
|
|
688
|
+
* @param {string} symbol unified market symbol of the market orders were made in
|
|
689
|
+
* @param {int} [since] the earliest time in ms to fetch orders for
|
|
690
|
+
* @param {int} [limit] the maximum number of order structures to retrieve
|
|
691
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
692
|
+
* @param {int|string} [params.tag] If given it will be echoed in the reply and the max size of tag is 32
|
|
693
|
+
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
694
|
+
*/
|
|
695
|
+
await this.loadMarkets();
|
|
696
|
+
await this.authenticate();
|
|
697
|
+
let messageHash = 'orders';
|
|
698
|
+
let args = 'order:';
|
|
699
|
+
const market = this.safeMarket(symbol);
|
|
700
|
+
if (symbol === undefined) {
|
|
701
|
+
args += 'all';
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
messageHash += ':' + symbol;
|
|
705
|
+
args += ':' + market['id'];
|
|
706
|
+
}
|
|
707
|
+
const request = {
|
|
708
|
+
'op': 'subscribe',
|
|
709
|
+
'args': [
|
|
710
|
+
args,
|
|
711
|
+
],
|
|
712
|
+
};
|
|
713
|
+
const url = this.urls['api']['ws'];
|
|
714
|
+
const orders = await this.watch(url, messageHash, request, messageHash);
|
|
715
|
+
if (this.newUpdates) {
|
|
716
|
+
limit = orders.getLimit(symbol, limit);
|
|
717
|
+
}
|
|
718
|
+
return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
|
|
719
|
+
}
|
|
720
|
+
handleOrders(client, message) {
|
|
721
|
+
//
|
|
722
|
+
// {
|
|
723
|
+
// "table": "order",
|
|
724
|
+
// "data": [
|
|
725
|
+
// {
|
|
726
|
+
// "accountId": "106464",
|
|
727
|
+
// "clientOrderId": "1716713676233",
|
|
728
|
+
// "orderId": "1000116921319",
|
|
729
|
+
// "price": "1000.0",
|
|
730
|
+
// "quantity": "0.01",
|
|
731
|
+
// "amount": "0.0",
|
|
732
|
+
// "side": "BUY",
|
|
733
|
+
// "status": "OPEN",
|
|
734
|
+
// "marketCode": "ETH-USD-SWAP-LIN",
|
|
735
|
+
// "timeInForce": "MAKER_ONLY",
|
|
736
|
+
// "timestamp": "1716713677834",
|
|
737
|
+
// "remainQuantity": "0.01",
|
|
738
|
+
// "limitPrice": "1000.0",
|
|
739
|
+
// "notice": "OrderOpened",
|
|
740
|
+
// "orderType": "LIMIT",
|
|
741
|
+
// "isTriggered": "false",
|
|
742
|
+
// "displayQuantity": "0.01"
|
|
743
|
+
// }
|
|
744
|
+
// ]
|
|
745
|
+
// }
|
|
746
|
+
//
|
|
747
|
+
const data = this.safeList(message, 'data', []);
|
|
748
|
+
let messageHash = 'orders';
|
|
749
|
+
if (this.orders === undefined) {
|
|
750
|
+
const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
|
|
751
|
+
this.orders = new ArrayCacheBySymbolById(limit);
|
|
752
|
+
}
|
|
753
|
+
const orders = this.orders;
|
|
754
|
+
for (let i = 0; i < data.length; i++) {
|
|
755
|
+
const order = this.safeDict(data, i, {});
|
|
756
|
+
const parsedOrder = this.parseOrder(order);
|
|
757
|
+
orders.append(parsedOrder);
|
|
758
|
+
messageHash += ':' + parsedOrder['symbol'];
|
|
759
|
+
client.resolve(this.orders, messageHash);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
async createOrderWs(symbol, type, side, amount, price = undefined, params = {}) {
|
|
763
|
+
/**
|
|
764
|
+
* @method
|
|
765
|
+
* @name oxfun#createOrderWs
|
|
766
|
+
* @see https://docs.ox.fun/?json#order-commands
|
|
767
|
+
* @description create a trade order
|
|
768
|
+
* @param {string} symbol unified symbol of the market to create an order in
|
|
769
|
+
* @param {string} type 'market', 'limit', 'STOP_LIMIT' or 'STOP_MARKET'
|
|
770
|
+
* @param {string} side 'buy' or 'sell'
|
|
771
|
+
* @param {float} amount how much of currency you want to trade in units of base currency
|
|
772
|
+
* @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
|
773
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
774
|
+
* @param {int} [params.clientOrderId] a unique id for the order
|
|
775
|
+
* @param {int} [params.timestamp] in milliseconds. If an order reaches the matching engine and the current timestamp exceeds timestamp + recvWindow, then the order will be rejected.
|
|
776
|
+
* @param {int} [params.recvWindow] in milliseconds. If an order reaches the matching engine and the current timestamp exceeds timestamp + recvWindow, then the order will be rejected. If timestamp is provided without recvWindow, then a default recvWindow of 1000ms is used.
|
|
777
|
+
* @param {float} [params.cost] the quote quantity that can be used as an alternative for the amount for market buy orders
|
|
778
|
+
* @param {float} [params.triggerPrice] The price at which a trigger order is triggered at
|
|
779
|
+
* @param {float} [params.limitPrice] Limit price for the STOP_LIMIT order
|
|
780
|
+
* @param {bool} [params.postOnly] if true, the order will only be posted if it will be a maker order
|
|
781
|
+
* @param {string} [params.timeInForce] GTC (default), IOC, FOK, PO, MAKER_ONLY or MAKER_ONLY_REPRICE (reprices order to the best maker only price if the specified price were to lead to a taker trade)
|
|
782
|
+
* @param {string} [params.selfTradePreventionMode] NONE, EXPIRE_MAKER, EXPIRE_TAKER or EXPIRE_BOTH for more info check here {@link https://docs.ox.fun/?json#self-trade-prevention-modes}
|
|
783
|
+
* @param {string} [params.displayQuantity] for an iceberg order, pass both quantity and displayQuantity fields in the order request
|
|
784
|
+
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
785
|
+
*/
|
|
786
|
+
await this.loadMarkets();
|
|
787
|
+
await this.authenticate();
|
|
788
|
+
const messageHash = this.nonce().toString();
|
|
789
|
+
const request = {
|
|
790
|
+
'op': 'placeorder',
|
|
791
|
+
'tag': messageHash,
|
|
792
|
+
};
|
|
793
|
+
params = this.omit(params, 'tag');
|
|
794
|
+
const orderRequest = this.createOrderRequest(symbol, type, side, amount, price, params);
|
|
795
|
+
const timestamp = this.safeInteger(orderRequest, 'timestamp');
|
|
796
|
+
if (timestamp === undefined) {
|
|
797
|
+
orderRequest['timestamp'] = this.milliseconds();
|
|
798
|
+
}
|
|
799
|
+
request['data'] = orderRequest;
|
|
800
|
+
const url = this.urls['api']['ws'];
|
|
801
|
+
return await this.watch(url, messageHash, request, messageHash);
|
|
802
|
+
}
|
|
803
|
+
async editOrderWs(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
|
|
804
|
+
/**
|
|
805
|
+
* @method
|
|
806
|
+
* @name oxfun#editOrderWs
|
|
807
|
+
* @description edit a trade order
|
|
808
|
+
* @see https://docs.ox.fun/?json#modify-order
|
|
809
|
+
* @param {string} id order id
|
|
810
|
+
* @param {string} symbol unified symbol of the market to create an order in
|
|
811
|
+
* @param {string} type 'market' or 'limit'
|
|
812
|
+
* @param {string} side 'buy' or 'sell'
|
|
813
|
+
* @param {float} amount how much of the currency you want to trade in units of the base currency
|
|
814
|
+
* @param {float|undefined} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
|
815
|
+
* @param {int} [params.timestamp] in milliseconds. If an order reaches the matching engine and the current timestamp exceeds timestamp + recvWindow, then the order will be rejected.
|
|
816
|
+
* @param {int} [params.recvWindow] in milliseconds. If an order reaches the matching engine and the current timestamp exceeds timestamp + recvWindow, then the order will be rejected. If timestamp is provided without recvWindow, then a default recvWindow of 1000ms is used.
|
|
817
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
818
|
+
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
819
|
+
*/
|
|
820
|
+
await this.loadMarkets();
|
|
821
|
+
await this.authenticate();
|
|
822
|
+
const messageHash = this.nonce().toString();
|
|
823
|
+
const request = {
|
|
824
|
+
'op': 'modifyorder',
|
|
825
|
+
'tag': messageHash,
|
|
826
|
+
};
|
|
827
|
+
params = this.omit(params, 'tag');
|
|
828
|
+
let orderRequest = this.createOrderRequest(symbol, type, side, amount, price, params);
|
|
829
|
+
orderRequest = this.extend(orderRequest, { 'orderId': id });
|
|
830
|
+
const timestamp = this.safeInteger(orderRequest, 'timestamp');
|
|
831
|
+
if (timestamp === undefined) {
|
|
832
|
+
orderRequest['timestamp'] = this.milliseconds();
|
|
833
|
+
}
|
|
834
|
+
request['data'] = orderRequest;
|
|
835
|
+
const url = this.urls['api']['ws'];
|
|
836
|
+
return await this.watch(url, messageHash, request, messageHash);
|
|
837
|
+
}
|
|
838
|
+
handlePlaceOrders(client, message) {
|
|
839
|
+
//
|
|
840
|
+
// {
|
|
841
|
+
// "event": "placeorder",
|
|
842
|
+
// "submitted": true,
|
|
843
|
+
// "tag": "1716934577",
|
|
844
|
+
// "timestamp": "1716932973899",
|
|
845
|
+
// "data": {
|
|
846
|
+
// "marketCode": "ETH-USD-SWAP-LIN",
|
|
847
|
+
// "side": "BUY",
|
|
848
|
+
// "orderType": "LIMIT",
|
|
849
|
+
// "quantity": "0.010",
|
|
850
|
+
// "timeInForce": "GTC",
|
|
851
|
+
// "price": "400.0",
|
|
852
|
+
// "limitPrice": "400.0",
|
|
853
|
+
// "orderId": "1000117429736",
|
|
854
|
+
// "source": 13
|
|
855
|
+
// }
|
|
856
|
+
// }
|
|
857
|
+
//
|
|
858
|
+
//
|
|
859
|
+
// Failure response format
|
|
860
|
+
// {
|
|
861
|
+
// "event": "placeorder",
|
|
862
|
+
// "submitted": false,
|
|
863
|
+
// "message": "JSON data format is invalid",
|
|
864
|
+
// "code": "20009",
|
|
865
|
+
// "timestamp": "1716932877381"
|
|
866
|
+
// }
|
|
867
|
+
//
|
|
868
|
+
const messageHash = this.safeString(message, 'tag');
|
|
869
|
+
const submitted = this.safeBool(message, 'submitted');
|
|
870
|
+
// filter out partial errors
|
|
871
|
+
if (!submitted) {
|
|
872
|
+
const method = this.safeString(message, 'event');
|
|
873
|
+
const stringMsg = this.json(message);
|
|
874
|
+
const code = this.safeInteger(message, 'code');
|
|
875
|
+
this.handleErrors(code, undefined, client.url, method, undefined, stringMsg, message, undefined, undefined);
|
|
876
|
+
}
|
|
877
|
+
const data = this.safeValue(message, 'data', {});
|
|
878
|
+
const order = this.parseOrder(data);
|
|
879
|
+
client.resolve(order, messageHash);
|
|
880
|
+
}
|
|
881
|
+
async cancelOrderWs(id, symbol = undefined, params = {}) {
|
|
882
|
+
/**
|
|
883
|
+
* @method
|
|
884
|
+
* @name oxfun#cancelOrderWs
|
|
885
|
+
* @see https://docs.ox.fun/?json#cancel-order
|
|
886
|
+
* @description cancels an open order
|
|
887
|
+
* @param {string} id order id
|
|
888
|
+
* @param {string} symbol unified market symbol, default is undefined
|
|
889
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
890
|
+
* @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
891
|
+
*/
|
|
892
|
+
if (symbol === undefined) {
|
|
893
|
+
throw new ArgumentsRequired(this.id + ' cancelOrderWs() requires a symbol argument');
|
|
894
|
+
}
|
|
895
|
+
await this.loadMarkets();
|
|
896
|
+
await this.authenticate();
|
|
897
|
+
const messageHash = this.nonce().toString();
|
|
898
|
+
const data = {
|
|
899
|
+
'marketCode': this.marketId(symbol),
|
|
900
|
+
'orderId': id,
|
|
901
|
+
};
|
|
902
|
+
const request = {
|
|
903
|
+
'op': 'cancelorder',
|
|
904
|
+
'tag': messageHash,
|
|
905
|
+
'data': data,
|
|
906
|
+
};
|
|
907
|
+
const url = this.urls['api']['ws'];
|
|
908
|
+
return await this.watch(url, messageHash, request, messageHash);
|
|
909
|
+
}
|
|
910
|
+
async cancelOrdersWs(ids, symbol = undefined, params = {}) {
|
|
911
|
+
/**
|
|
912
|
+
* @method
|
|
913
|
+
* @name okx#cancelOrdersWs
|
|
914
|
+
* @see https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-mass-cancel-order
|
|
915
|
+
* @description cancel multiple orders
|
|
916
|
+
* @param {string[]} ids order ids
|
|
917
|
+
* @param {string} symbol unified market symbol, default is undefined
|
|
918
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
919
|
+
* @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
920
|
+
*/
|
|
921
|
+
const idsLength = ids.length;
|
|
922
|
+
if (idsLength > 20) {
|
|
923
|
+
throw new BadRequest(this.id + ' cancelOrdersWs() accepts up to 20 ids at a time');
|
|
924
|
+
}
|
|
925
|
+
if (symbol === undefined) {
|
|
926
|
+
throw new ArgumentsRequired(this.id + ' cancelOrdersWs() requires a symbol argument');
|
|
927
|
+
}
|
|
928
|
+
await this.loadMarkets();
|
|
929
|
+
await this.authenticate();
|
|
930
|
+
const messageHash = this.nonce().toString();
|
|
931
|
+
const marketId = this.marketId(symbol);
|
|
932
|
+
const dataArray = [];
|
|
933
|
+
for (let i = 0; i < idsLength; i++) {
|
|
934
|
+
const data = {
|
|
935
|
+
'instId': marketId,
|
|
936
|
+
'ordId': ids[i],
|
|
937
|
+
};
|
|
938
|
+
dataArray.push(data);
|
|
939
|
+
}
|
|
940
|
+
const request = {
|
|
941
|
+
'op': 'cancelorders',
|
|
942
|
+
'tag': messageHash,
|
|
943
|
+
'dataArray': dataArray,
|
|
944
|
+
};
|
|
945
|
+
const url = this.urls['api']['ws'];
|
|
946
|
+
return await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
|
|
947
|
+
}
|
|
948
|
+
async authenticate(params = {}) {
|
|
949
|
+
const url = this.urls['api']['ws'];
|
|
950
|
+
const client = this.client(url);
|
|
951
|
+
const messageHash = 'authenticated';
|
|
952
|
+
const future = client.future(messageHash);
|
|
953
|
+
const authenticated = this.safeDict(client.subscriptions, messageHash);
|
|
954
|
+
if (authenticated === undefined) {
|
|
955
|
+
this.checkRequiredCredentials();
|
|
956
|
+
const timestamp = this.milliseconds();
|
|
957
|
+
const payload = timestamp.toString() + 'GET/auth/self/verify';
|
|
958
|
+
const signature = this.hmac(this.encode(payload), this.encode(this.secret), sha256, 'base64');
|
|
959
|
+
const request = {
|
|
960
|
+
'op': 'login',
|
|
961
|
+
'data': {
|
|
962
|
+
'apiKey': this.apiKey,
|
|
963
|
+
'timestamp': timestamp,
|
|
964
|
+
'signature': signature,
|
|
965
|
+
},
|
|
966
|
+
};
|
|
967
|
+
const message = this.extend(request, params);
|
|
968
|
+
this.watch(url, messageHash, message, messageHash);
|
|
969
|
+
}
|
|
970
|
+
return await future;
|
|
971
|
+
}
|
|
972
|
+
handleAuthenticationMessage(client, message) {
|
|
973
|
+
const authenticated = this.safeBool(message, 'success', false);
|
|
974
|
+
const messageHash = 'authenticated';
|
|
975
|
+
if (authenticated) {
|
|
976
|
+
// we resolve the future here permanently so authentication only happens once
|
|
977
|
+
const future = this.safeDict(client.futures, messageHash);
|
|
978
|
+
future.resolve(true);
|
|
979
|
+
}
|
|
980
|
+
else {
|
|
981
|
+
const error = new AuthenticationError(this.json(message));
|
|
982
|
+
client.reject(error, messageHash);
|
|
983
|
+
if (messageHash in client.subscriptions) {
|
|
984
|
+
delete client.subscriptions[messageHash];
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
ping(client) {
|
|
989
|
+
return 'ping';
|
|
990
|
+
}
|
|
991
|
+
handlePong(client, message) {
|
|
992
|
+
client.lastPong = this.milliseconds();
|
|
993
|
+
return message;
|
|
994
|
+
}
|
|
995
|
+
handleMessage(client, message) {
|
|
996
|
+
if (message === 'pong') {
|
|
997
|
+
this.handlePong(client, message);
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
const table = this.safeString(message, 'table');
|
|
1001
|
+
const data = this.safeList(message, 'data', []);
|
|
1002
|
+
const event = this.safeString(message, 'event');
|
|
1003
|
+
if ((table !== undefined) && (data !== undefined)) {
|
|
1004
|
+
if (table === 'trade') {
|
|
1005
|
+
this.handleTrades(client, message);
|
|
1006
|
+
}
|
|
1007
|
+
if (table === 'ticker') {
|
|
1008
|
+
this.handleTicker(client, message);
|
|
1009
|
+
}
|
|
1010
|
+
if (table.indexOf('candles') > -1) {
|
|
1011
|
+
this.handleOHLCV(client, message);
|
|
1012
|
+
}
|
|
1013
|
+
if (table.indexOf('depth') > -1) {
|
|
1014
|
+
this.handleOrderBook(client, message);
|
|
1015
|
+
}
|
|
1016
|
+
if (table.indexOf('balance') > -1) {
|
|
1017
|
+
this.handleBalance(client, message);
|
|
1018
|
+
}
|
|
1019
|
+
if (table.indexOf('position') > -1) {
|
|
1020
|
+
this.handlePositions(client, message);
|
|
1021
|
+
}
|
|
1022
|
+
if (table.indexOf('order') > -1) {
|
|
1023
|
+
this.handleOrders(client, message);
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
else {
|
|
1027
|
+
if (event === 'login') {
|
|
1028
|
+
this.handleAuthenticationMessage(client, message);
|
|
1029
|
+
}
|
|
1030
|
+
if ((event === 'placeorder') || (event === 'modifyorder') || (event === 'cancelorder')) {
|
|
1031
|
+
this.handlePlaceOrders(client, message);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|