ccxt 4.3.43 → 4.3.45
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 +7 -5
- package/dist/ccxt.browser.min.js +3 -3
- package/dist/cjs/ccxt.js +9 -1
- package/dist/cjs/src/abstract/oxfun.js +9 -0
- package/dist/cjs/src/bitstamp.js +18 -2
- package/dist/cjs/src/kucoin.js +28 -1
- package/dist/cjs/src/luno.js +9 -1
- package/dist/cjs/src/lykke.js +10 -2
- package/dist/cjs/src/ndax.js +5 -1
- package/dist/cjs/src/oxfun.js +2900 -0
- package/dist/cjs/src/poloniexfutures.js +2 -2
- package/dist/cjs/src/pro/bitmex.js +9 -0
- package/dist/cjs/src/pro/oxfun.js +1034 -0
- package/dist/cjs/src/pro/woo.js +1 -1
- package/dist/cjs/src/wavesexchange.js +121 -110
- package/dist/cjs/src/xt.js +135 -96
- package/js/ccxt.d.ts +11 -2
- package/js/ccxt.js +8 -2
- 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/oxfun.d.ts +37 -0
- package/js/src/abstract/oxfun.js +11 -0
- package/js/src/abstract/xt.d.ts +155 -0
- package/js/src/abstract/xt.js +11 -0
- package/js/src/bitstamp.js +18 -2
- 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/lykke.d.ts +2 -2
- package/js/src/lykke.js +10 -2
- package/js/src/ndax.d.ts +1 -1
- package/js/src/ndax.js +5 -1
- package/js/src/oxfun.d.ts +129 -0
- package/js/src/oxfun.js +2901 -0
- package/js/src/poloniexfutures.js +2 -2
- package/js/src/pro/bitmex.js +9 -0
- package/js/src/pro/oxfun.d.ts +38 -0
- package/js/src/pro/oxfun.js +1035 -0
- package/js/src/pro/woo.js +1 -1
- package/js/src/wavesexchange.d.ts +7 -7
- package/js/src/wavesexchange.js +122 -111
- package/js/src/xt.d.ts +161 -0
- package/js/src/xt.js +4761 -0
- package/package.json +1 -1
|
@@ -0,0 +1,2900 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var oxfun$1 = require('./abstract/oxfun.js');
|
|
4
|
+
var Precise = require('./base/Precise.js');
|
|
5
|
+
var errors = require('./base/errors.js');
|
|
6
|
+
var number = require('./base/functions/number.js');
|
|
7
|
+
var sha256 = require('./static_dependencies/noble-hashes/sha256.js');
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
/**
|
|
12
|
+
* @class oxfun
|
|
13
|
+
* @augments Exchange
|
|
14
|
+
*/
|
|
15
|
+
class oxfun extends oxfun$1 {
|
|
16
|
+
describe() {
|
|
17
|
+
return this.deepExtend(super.describe(), {
|
|
18
|
+
'id': 'oxfun',
|
|
19
|
+
'name': 'Oxfun',
|
|
20
|
+
'countries': ['PA'],
|
|
21
|
+
'version': 'v3',
|
|
22
|
+
'rateLimit': 120,
|
|
23
|
+
'pro': true,
|
|
24
|
+
'has': {
|
|
25
|
+
'CORS': undefined,
|
|
26
|
+
'spot': true,
|
|
27
|
+
'margin': false,
|
|
28
|
+
'swap': true,
|
|
29
|
+
'future': false,
|
|
30
|
+
'option': false,
|
|
31
|
+
'addMargin': false,
|
|
32
|
+
'cancelAllOrders': true,
|
|
33
|
+
'cancelOrder': true,
|
|
34
|
+
'cancelOrders': true,
|
|
35
|
+
'closeAllPositions': false,
|
|
36
|
+
'closePosition': false,
|
|
37
|
+
'createDepositAddress': false,
|
|
38
|
+
'createMarketBuyOrderWithCost': true,
|
|
39
|
+
'createMarketOrderWithCost': false,
|
|
40
|
+
'createMarketSellOrderWithCost': false,
|
|
41
|
+
'createOrder': true,
|
|
42
|
+
'createOrders': true,
|
|
43
|
+
'createPostOnlyOrder': true,
|
|
44
|
+
'createReduceOnlyOrder': false,
|
|
45
|
+
'createStopLimitOrder': true,
|
|
46
|
+
'createStopMarketOrder': true,
|
|
47
|
+
'createStopOrder': true,
|
|
48
|
+
'deposit': false,
|
|
49
|
+
'editOrder': false,
|
|
50
|
+
'fetchAccounts': true,
|
|
51
|
+
'fetchBalance': true,
|
|
52
|
+
'fetchBidsAsks': false,
|
|
53
|
+
'fetchBorrowInterest': false,
|
|
54
|
+
'fetchBorrowRateHistories': false,
|
|
55
|
+
'fetchBorrowRateHistory': false,
|
|
56
|
+
'fetchCanceledOrders': false,
|
|
57
|
+
'fetchClosedOrder': false,
|
|
58
|
+
'fetchClosedOrders': false,
|
|
59
|
+
'fetchCrossBorrowRate': false,
|
|
60
|
+
'fetchCrossBorrowRates': false,
|
|
61
|
+
'fetchCurrencies': true,
|
|
62
|
+
'fetchDeposit': false,
|
|
63
|
+
'fetchDepositAddress': false,
|
|
64
|
+
'fetchDepositAddresses': false,
|
|
65
|
+
'fetchDepositAddressesByNetwork': false,
|
|
66
|
+
'fetchDeposits': true,
|
|
67
|
+
'fetchDepositWithdrawFee': false,
|
|
68
|
+
'fetchDepositWithdrawFees': false,
|
|
69
|
+
'fetchFundingHistory': true,
|
|
70
|
+
'fetchFundingRate': false,
|
|
71
|
+
'fetchFundingRateHistory': true,
|
|
72
|
+
'fetchFundingRates': true,
|
|
73
|
+
'fetchIndexOHLCV': false,
|
|
74
|
+
'fetchIsolatedBorrowRate': false,
|
|
75
|
+
'fetchIsolatedBorrowRates': false,
|
|
76
|
+
'fetchL3OrderBook': false,
|
|
77
|
+
'fetchLedger': false,
|
|
78
|
+
'fetchLeverage': false,
|
|
79
|
+
'fetchLeverageTiers': true,
|
|
80
|
+
'fetchMarketLeverageTiers': false,
|
|
81
|
+
'fetchMarkets': true,
|
|
82
|
+
'fetchMarkOHLCV': false,
|
|
83
|
+
'fetchMyTrades': true,
|
|
84
|
+
'fetchOHLCV': true,
|
|
85
|
+
'fetchOpenInterestHistory': false,
|
|
86
|
+
'fetchOpenOrder': false,
|
|
87
|
+
'fetchOpenOrders': true,
|
|
88
|
+
'fetchOrder': true,
|
|
89
|
+
'fetchOrderBook': true,
|
|
90
|
+
'fetchOrderBooks': false,
|
|
91
|
+
'fetchOrders': false,
|
|
92
|
+
'fetchOrderTrades': false,
|
|
93
|
+
'fetchPosition': false,
|
|
94
|
+
'fetchPositionHistory': false,
|
|
95
|
+
'fetchPositionMode': false,
|
|
96
|
+
'fetchPositions': true,
|
|
97
|
+
'fetchPositionsForSymbol': false,
|
|
98
|
+
'fetchPositionsHistory': false,
|
|
99
|
+
'fetchPositionsRisk': false,
|
|
100
|
+
'fetchPremiumIndexOHLCV': false,
|
|
101
|
+
'fetchStatus': false,
|
|
102
|
+
'fetchTicker': true,
|
|
103
|
+
'fetchTickers': true,
|
|
104
|
+
'fetchTime': false,
|
|
105
|
+
'fetchTrades': true,
|
|
106
|
+
'fetchTradingFee': false,
|
|
107
|
+
'fetchTradingFees': false,
|
|
108
|
+
'fetchTradingLimits': false,
|
|
109
|
+
'fetchTransactionFee': false,
|
|
110
|
+
'fetchTransactionFees': false,
|
|
111
|
+
'fetchTransactions': false,
|
|
112
|
+
'fetchTransfers': true,
|
|
113
|
+
'fetchWithdrawal': false,
|
|
114
|
+
'fetchWithdrawals': true,
|
|
115
|
+
'fetchWithdrawalWhitelist': false,
|
|
116
|
+
'reduceMargin': false,
|
|
117
|
+
'repayCrossMargin': false,
|
|
118
|
+
'repayIsolatedMargin': false,
|
|
119
|
+
'setLeverage': false,
|
|
120
|
+
'setMargin': false,
|
|
121
|
+
'setMarginMode': false,
|
|
122
|
+
'setPositionMode': false,
|
|
123
|
+
'signIn': false,
|
|
124
|
+
'transfer': true,
|
|
125
|
+
'withdraw': true,
|
|
126
|
+
'ws': true,
|
|
127
|
+
},
|
|
128
|
+
'timeframes': {
|
|
129
|
+
'1m': '60s',
|
|
130
|
+
'5m': '300s',
|
|
131
|
+
'15m': '900s',
|
|
132
|
+
'30m': '1800s',
|
|
133
|
+
'1h': '3600s',
|
|
134
|
+
'2h': '7200s',
|
|
135
|
+
'4h': '14400s',
|
|
136
|
+
'1d': '86400s',
|
|
137
|
+
},
|
|
138
|
+
'urls': {
|
|
139
|
+
'logo': 'https://github.com/ccxt/ccxt/assets/43336371/9c7114b3-ec32-4cf7-a716-f807d7d071cd',
|
|
140
|
+
'referral': 'https://ox.fun/register?shareAccountId=5ZUD4a7G',
|
|
141
|
+
'api': {
|
|
142
|
+
'public': 'https://api.ox.fun',
|
|
143
|
+
'private': 'https://api.ox.fun',
|
|
144
|
+
},
|
|
145
|
+
'test': {
|
|
146
|
+
'public': 'https://stgapi.ox.fun',
|
|
147
|
+
'private': 'https://stgapi.ox.fun',
|
|
148
|
+
},
|
|
149
|
+
'www': 'https://ox.fun/',
|
|
150
|
+
'doc': 'https://docs.ox.fun/',
|
|
151
|
+
'fees': 'https://support.ox.fun/en/articles/8819866-trading-fees',
|
|
152
|
+
},
|
|
153
|
+
'api': {
|
|
154
|
+
'public': {
|
|
155
|
+
'get': {
|
|
156
|
+
'v3/markets': 1,
|
|
157
|
+
'v3/assets': 1,
|
|
158
|
+
'v3/tickers': 1,
|
|
159
|
+
'v3/funding/estimates': 1,
|
|
160
|
+
'v3/candles': 1,
|
|
161
|
+
'v3/depth': 1,
|
|
162
|
+
'v3/markets/operational': 1,
|
|
163
|
+
'v3/exchange-trades': 1,
|
|
164
|
+
'v3/funding/rates': 1,
|
|
165
|
+
'v3/leverage/tiers': 1,
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
'private': {
|
|
169
|
+
'get': {
|
|
170
|
+
'v3/account': 1,
|
|
171
|
+
'v3/account/names': 1,
|
|
172
|
+
'v3/wallet': 1,
|
|
173
|
+
'v3/transfer': 1,
|
|
174
|
+
'v3/balances': 1,
|
|
175
|
+
'v3/positions': 1,
|
|
176
|
+
'v3/funding': 1,
|
|
177
|
+
'v3/deposit-addresses': 1,
|
|
178
|
+
'v3/deposit': 1,
|
|
179
|
+
'v3/withdrawal-addresses': 1,
|
|
180
|
+
'v3/withdrawal': 1,
|
|
181
|
+
'v3/withdrawal-fees': 1,
|
|
182
|
+
'v3/orders/status': 1,
|
|
183
|
+
'v3/orders/working': 1,
|
|
184
|
+
'v3/trades': 1,
|
|
185
|
+
},
|
|
186
|
+
'post': {
|
|
187
|
+
'v3/transfer': 1,
|
|
188
|
+
'v3/withdrawal': 1,
|
|
189
|
+
'v3/orders/place': 1,
|
|
190
|
+
},
|
|
191
|
+
'delete': {
|
|
192
|
+
'v3/orders/cancel': 1,
|
|
193
|
+
'v3/orders/cancel-all': 1,
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
'fees': {
|
|
198
|
+
'trading': {
|
|
199
|
+
'tierBased': true,
|
|
200
|
+
'percentage': true,
|
|
201
|
+
'maker': this.parseNumber('0.00020'),
|
|
202
|
+
'taker': this.parseNumber('0.00070'),
|
|
203
|
+
'tiers': {
|
|
204
|
+
'maker': [
|
|
205
|
+
[this.parseNumber('0'), this.parseNumber('0.00020')],
|
|
206
|
+
[this.parseNumber('2500000'), this.parseNumber('0.00010')],
|
|
207
|
+
[this.parseNumber('25000000'), this.parseNumber('0')],
|
|
208
|
+
],
|
|
209
|
+
'taker': [
|
|
210
|
+
[this.parseNumber('0'), this.parseNumber('0.00070')],
|
|
211
|
+
[this.parseNumber('2500000'), this.parseNumber('0.00050')],
|
|
212
|
+
[this.parseNumber('25000000'), this.parseNumber('0.00040')],
|
|
213
|
+
],
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
'precisionMode': number.TICK_SIZE,
|
|
218
|
+
// exchange-specific options
|
|
219
|
+
'options': {
|
|
220
|
+
'sandboxMode': false,
|
|
221
|
+
'networks': {
|
|
222
|
+
'BTC': 'Bitcoin',
|
|
223
|
+
'ERC20': 'Ethereum',
|
|
224
|
+
'AVAX': 'Avalanche',
|
|
225
|
+
'SOL': 'Solana',
|
|
226
|
+
'ARB': 'Arbitrum',
|
|
227
|
+
'MATIC': 'Polygon',
|
|
228
|
+
'FTM': 'Fantom',
|
|
229
|
+
'BNB': 'BNBSmartChain',
|
|
230
|
+
'OPTIMISM': 'Optimism',
|
|
231
|
+
},
|
|
232
|
+
'networksById': {
|
|
233
|
+
'Bitcoin': 'BTC',
|
|
234
|
+
'Ethereum': 'ERC20',
|
|
235
|
+
'Avalanche': 'AVAX',
|
|
236
|
+
'Solana': 'SOL',
|
|
237
|
+
'Arbitrum': 'ARB',
|
|
238
|
+
'Polygon': 'MATIC',
|
|
239
|
+
'Fantom': 'FTM',
|
|
240
|
+
'Base': 'BASE',
|
|
241
|
+
'BNBSmartChain': 'BNB',
|
|
242
|
+
'Optimism': 'OPTIMISM',
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
'exceptions': {
|
|
246
|
+
'exact': {
|
|
247
|
+
'-0010': errors.OperationFailed,
|
|
248
|
+
'-429': errors.RateLimitExceeded,
|
|
249
|
+
'-05001': errors.AuthenticationError,
|
|
250
|
+
'-10001': errors.ExchangeError,
|
|
251
|
+
'-20000': errors.BadRequest,
|
|
252
|
+
'-20001': errors.BadRequest,
|
|
253
|
+
'-20002': errors.BadRequest,
|
|
254
|
+
'-20003': errors.NotSupported,
|
|
255
|
+
'-20005': errors.AuthenticationError,
|
|
256
|
+
'-20006': errors.BadRequest,
|
|
257
|
+
'-20007': errors.AuthenticationError,
|
|
258
|
+
'-20008': errors.BadRequest,
|
|
259
|
+
'-20009': errors.BadRequest,
|
|
260
|
+
'-20010': errors.ArgumentsRequired,
|
|
261
|
+
'-20011': errors.ArgumentsRequired,
|
|
262
|
+
'-20012': errors.ArgumentsRequired,
|
|
263
|
+
'-20013': errors.ArgumentsRequired,
|
|
264
|
+
'-20014': errors.BadRequest,
|
|
265
|
+
'-20015': errors.BadSymbol,
|
|
266
|
+
'-20016': errors.BadRequest,
|
|
267
|
+
'-20017': errors.BadRequest,
|
|
268
|
+
'-20018': errors.BadRequest,
|
|
269
|
+
'-20019': errors.BadRequest,
|
|
270
|
+
'-20020': errors.BadRequest,
|
|
271
|
+
'-20021': errors.BadRequest,
|
|
272
|
+
'-20022': errors.ArgumentsRequired,
|
|
273
|
+
'-20023': errors.ArgumentsRequired,
|
|
274
|
+
'-20024': errors.ExchangeError,
|
|
275
|
+
'-20025': errors.AuthenticationError,
|
|
276
|
+
'-20026': errors.BadRequest,
|
|
277
|
+
'-20027': errors.BadRequest,
|
|
278
|
+
'-20028': errors.BadRequest,
|
|
279
|
+
'-20029': errors.BadRequest,
|
|
280
|
+
'-20030': errors.BadRequest,
|
|
281
|
+
'-20031': errors.MarketClosed,
|
|
282
|
+
'-20032': errors.NetworkError,
|
|
283
|
+
'-20033': errors.BadRequest,
|
|
284
|
+
'-20034': errors.BadRequest,
|
|
285
|
+
'-20050': errors.ExchangeError,
|
|
286
|
+
'-30001': errors.BadRequest,
|
|
287
|
+
'-35034': errors.AuthenticationError,
|
|
288
|
+
'-35046': errors.AuthenticationError,
|
|
289
|
+
'-40001': errors.ExchangeError,
|
|
290
|
+
'-50001': errors.ExchangeError,
|
|
291
|
+
'-300001': errors.AccountNotEnabled,
|
|
292
|
+
'-300011': errors.InvalidOrder,
|
|
293
|
+
'-300012': errors.InvalidOrder,
|
|
294
|
+
'-100005': errors.OrderNotFound,
|
|
295
|
+
'-100006': errors.InvalidOrder,
|
|
296
|
+
'-100008': errors.BadRequest,
|
|
297
|
+
'-100015': errors.NetworkError,
|
|
298
|
+
'-710001': errors.ExchangeError,
|
|
299
|
+
'-710002': errors.BadRequest,
|
|
300
|
+
'-710003': errors.BadRequest,
|
|
301
|
+
'-710004': errors.BadRequest,
|
|
302
|
+
'-710005': errors.InsufficientFunds,
|
|
303
|
+
'-710006': errors.InsufficientFunds,
|
|
304
|
+
'-710007': errors.InsufficientFunds,
|
|
305
|
+
'-000101': errors.NetworkError,
|
|
306
|
+
'-000201': errors.NetworkError, // Trade service is busy, try again later
|
|
307
|
+
},
|
|
308
|
+
'broad': {
|
|
309
|
+
'-20001': errors.OperationFailed,
|
|
310
|
+
'-200050': errors.RequestTimeout, // The market is not active
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
async fetchMarkets(params = {}) {
|
|
316
|
+
/**
|
|
317
|
+
* @method
|
|
318
|
+
* @name oxfun#fetchMarkets
|
|
319
|
+
* @description retrieves data on all markets for bitmex
|
|
320
|
+
* @see https://docs.ox.fun/?json#get-v3-markets
|
|
321
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
322
|
+
* @returns {object[]} an array of objects representing market data
|
|
323
|
+
*/
|
|
324
|
+
const [responseFromMarkets, responseFromTickers] = await Promise.all([this.publicGetV3Markets(params), this.publicGetV3Tickers(params)]);
|
|
325
|
+
const marketsFromMarkets = this.safeList(responseFromMarkets, 'data', []);
|
|
326
|
+
//
|
|
327
|
+
// {
|
|
328
|
+
// success: true,
|
|
329
|
+
// data: [
|
|
330
|
+
// {
|
|
331
|
+
// marketCode: 'OX-USD-SWAP-LIN',
|
|
332
|
+
// name: 'OX/USD Perp',
|
|
333
|
+
// referencePair: 'OX/USDT',
|
|
334
|
+
// base: 'OX',
|
|
335
|
+
// counter: 'USD',
|
|
336
|
+
// type: 'FUTURE',
|
|
337
|
+
// tickSize: '0.00001',
|
|
338
|
+
// minSize: '1',
|
|
339
|
+
// listedAt: '1704766320000',
|
|
340
|
+
// upperPriceBound: '0.02122',
|
|
341
|
+
// lowerPriceBound: '0.01142',
|
|
342
|
+
// markPrice: '0.01632',
|
|
343
|
+
// indexPrice: '0.01564',
|
|
344
|
+
// lastUpdatedAt: '1714762235569'
|
|
345
|
+
// },
|
|
346
|
+
// {
|
|
347
|
+
// marketCode: 'BTC-USD-SWAP-LIN',
|
|
348
|
+
// name: 'BTC/USD Perp',
|
|
349
|
+
// referencePair: 'BTC/USDT',
|
|
350
|
+
// base: 'BTC',
|
|
351
|
+
// counter: 'USD',
|
|
352
|
+
// type: 'FUTURE',
|
|
353
|
+
// tickSize: '1',
|
|
354
|
+
// minSize: '0.0001',
|
|
355
|
+
// listedAt: '1704686640000',
|
|
356
|
+
// upperPriceBound: '67983',
|
|
357
|
+
// lowerPriceBound: '55621',
|
|
358
|
+
// markPrice: '61802',
|
|
359
|
+
// indexPrice: '61813',
|
|
360
|
+
// lastUpdatedAt: '1714762234765'
|
|
361
|
+
// },
|
|
362
|
+
// {
|
|
363
|
+
// "marketCode": "MILK-OX",
|
|
364
|
+
// "name": "MILK/OX",
|
|
365
|
+
// "referencePair": "MILK/OX",
|
|
366
|
+
// "base": "MILK",
|
|
367
|
+
// "counter": "OX",
|
|
368
|
+
// "type": "SPOT",
|
|
369
|
+
// "tickSize": "0.0001",
|
|
370
|
+
// "minSize": "1",
|
|
371
|
+
// "listedAt": "1706608500000",
|
|
372
|
+
// "upperPriceBound": "1.0000",
|
|
373
|
+
// "lowerPriceBound": "-1.0000",
|
|
374
|
+
// "markPrice": "0.0269",
|
|
375
|
+
// "indexPrice": "0.0269",
|
|
376
|
+
// "lastUpdatedAt": "1714757402185"
|
|
377
|
+
// },
|
|
378
|
+
// ...
|
|
379
|
+
// ]
|
|
380
|
+
// }
|
|
381
|
+
//
|
|
382
|
+
const marketsFromTickers = this.safeList(responseFromTickers, 'data', []);
|
|
383
|
+
//
|
|
384
|
+
// {
|
|
385
|
+
// "success": true,
|
|
386
|
+
// "data": [
|
|
387
|
+
// {
|
|
388
|
+
// "marketCode": "DYM-USD-SWAP-LIN",
|
|
389
|
+
// "markPrice": "3.321",
|
|
390
|
+
// "open24h": "3.315",
|
|
391
|
+
// "high24h": "3.356",
|
|
392
|
+
// "low24h": "3.255",
|
|
393
|
+
// "volume24h": "0",
|
|
394
|
+
// "currencyVolume24h": "0",
|
|
395
|
+
// "openInterest": "1768.1",
|
|
396
|
+
// "lastTradedPrice": "3.543",
|
|
397
|
+
// "lastTradedQuantity": "1.0",
|
|
398
|
+
// "lastUpdatedAt": "1714853388102"
|
|
399
|
+
// },
|
|
400
|
+
// ...
|
|
401
|
+
// ]
|
|
402
|
+
// }
|
|
403
|
+
//
|
|
404
|
+
const markets = this.arrayConcat(marketsFromMarkets, marketsFromTickers);
|
|
405
|
+
return this.parseMarkets(markets);
|
|
406
|
+
}
|
|
407
|
+
parseMarkets(markets) {
|
|
408
|
+
const marketIds = [];
|
|
409
|
+
const result = [];
|
|
410
|
+
for (let i = 0; i < markets.length; i++) {
|
|
411
|
+
const market = markets[i];
|
|
412
|
+
const marketId = this.safeString(market, 'marketCode');
|
|
413
|
+
if (!(this.inArray(marketId, marketIds))) {
|
|
414
|
+
marketIds.push(marketId);
|
|
415
|
+
result.push(this.parseMarket(market));
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return result;
|
|
419
|
+
}
|
|
420
|
+
parseMarket(market) {
|
|
421
|
+
const id = this.safeString(market, 'marketCode', '');
|
|
422
|
+
const parts = id.split('-');
|
|
423
|
+
const baseId = this.safeString(parts, 0);
|
|
424
|
+
const quoteId = this.safeString(parts, 1);
|
|
425
|
+
const base = this.safeCurrencyCode(baseId);
|
|
426
|
+
const quote = this.safeCurrencyCode(quoteId);
|
|
427
|
+
let symbol = base + '/' + quote;
|
|
428
|
+
let type = this.safeStringLower(market, 'type', 'spot'); // markets from v3/tickers are spot and have no type
|
|
429
|
+
let settleId = undefined;
|
|
430
|
+
let settle = undefined;
|
|
431
|
+
const isFuture = (type === 'future'); // the exchange has only perpetual futures
|
|
432
|
+
if (isFuture) {
|
|
433
|
+
type = 'swap';
|
|
434
|
+
settleId = 'OX';
|
|
435
|
+
settle = this.safeCurrencyCode('OX');
|
|
436
|
+
symbol = symbol + ':' + settle;
|
|
437
|
+
}
|
|
438
|
+
const isSpot = type === 'spot';
|
|
439
|
+
return this.safeMarketStructure({
|
|
440
|
+
'id': id,
|
|
441
|
+
'numericId': undefined,
|
|
442
|
+
'symbol': symbol,
|
|
443
|
+
'base': base,
|
|
444
|
+
'quote': quote,
|
|
445
|
+
'settle': settle,
|
|
446
|
+
'baseId': baseId,
|
|
447
|
+
'quoteId': quoteId,
|
|
448
|
+
'settleId': settleId,
|
|
449
|
+
'type': type,
|
|
450
|
+
'spot': isSpot,
|
|
451
|
+
'margin': false,
|
|
452
|
+
'swap': isFuture,
|
|
453
|
+
'future': false,
|
|
454
|
+
'option': false,
|
|
455
|
+
'active': true,
|
|
456
|
+
'contract': isFuture,
|
|
457
|
+
'linear': isFuture ? true : undefined,
|
|
458
|
+
'inverse': isFuture ? false : undefined,
|
|
459
|
+
'taker': this.fees['trading']['taker'],
|
|
460
|
+
'maker': this.fees['trading']['maker'],
|
|
461
|
+
'contractSize': isFuture ? 1 : undefined,
|
|
462
|
+
'expiry': undefined,
|
|
463
|
+
'expiryDatetime': undefined,
|
|
464
|
+
'strike': undefined,
|
|
465
|
+
'optionType': undefined,
|
|
466
|
+
'precision': {
|
|
467
|
+
'amount': undefined,
|
|
468
|
+
'price': this.safeNumber(market, 'tickSize'),
|
|
469
|
+
},
|
|
470
|
+
'limits': {
|
|
471
|
+
'leverage': {
|
|
472
|
+
'min': undefined,
|
|
473
|
+
'max': undefined,
|
|
474
|
+
},
|
|
475
|
+
'amount': {
|
|
476
|
+
'min': this.safeNumber(market, 'minSize'),
|
|
477
|
+
'max': undefined,
|
|
478
|
+
},
|
|
479
|
+
'price': {
|
|
480
|
+
'min': undefined,
|
|
481
|
+
'max': undefined,
|
|
482
|
+
},
|
|
483
|
+
'cost': {
|
|
484
|
+
'min': undefined,
|
|
485
|
+
'max': undefined,
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
'created': this.safeInteger(market, 'listedAt'),
|
|
489
|
+
'index': undefined,
|
|
490
|
+
'info': market,
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
async fetchCurrencies(params = {}) {
|
|
494
|
+
/**
|
|
495
|
+
* @method
|
|
496
|
+
* @name oxfun#fetchCurrencies
|
|
497
|
+
* @description fetches all available currencies on an exchange
|
|
498
|
+
* @see https://docs.ox.fun/?json#get-v3-assets
|
|
499
|
+
* @param {dict} [params] extra parameters specific to the exchange API endpoint
|
|
500
|
+
* @returns {dict} an associative dictionary of currencies
|
|
501
|
+
*/
|
|
502
|
+
const response = await this.publicGetV3Assets(params);
|
|
503
|
+
//
|
|
504
|
+
// {
|
|
505
|
+
// "success": true,
|
|
506
|
+
// "data": [
|
|
507
|
+
// {
|
|
508
|
+
// "asset": "OX",
|
|
509
|
+
// "isCollateral": true,
|
|
510
|
+
// "loanToValue": "1.000000000",
|
|
511
|
+
// "loanToValueFactor": "0.000000000",
|
|
512
|
+
// "networkList": [
|
|
513
|
+
// {
|
|
514
|
+
// "network": "BNBSmartChain",
|
|
515
|
+
// "tokenId": "0x78a0A62Fba6Fb21A83FE8a3433d44C73a4017A6f",
|
|
516
|
+
// "transactionPrecision": "18",
|
|
517
|
+
// "isWithdrawalFeeChargedToUser": true,
|
|
518
|
+
// "canDeposit": true,
|
|
519
|
+
// "canWithdraw": false,
|
|
520
|
+
// "minDeposit": "0.00010",
|
|
521
|
+
// "minWithdrawal": "0.00010"
|
|
522
|
+
// },
|
|
523
|
+
// {
|
|
524
|
+
// "network": "Polygon",
|
|
525
|
+
// "tokenId": "0x78a0A62Fba6Fb21A83FE8a3433d44C73a4017A6f",
|
|
526
|
+
// "transactionPrecision": "18",
|
|
527
|
+
// "isWithdrawalFeeChargedToUser": true,
|
|
528
|
+
// "canDeposit": true,
|
|
529
|
+
// "canWithdraw": false,
|
|
530
|
+
// "minDeposit": "0.00010",
|
|
531
|
+
// "minWithdrawal": "0.00010"
|
|
532
|
+
// },
|
|
533
|
+
// {
|
|
534
|
+
// "network": "Arbitrum",
|
|
535
|
+
// "tokenId": "0xba0Dda8762C24dA9487f5FA026a9B64b695A07Ea",
|
|
536
|
+
// "transactionPrecision": "18",
|
|
537
|
+
// "isWithdrawalFeeChargedToUser": true,
|
|
538
|
+
// "canDeposit": true,
|
|
539
|
+
// "canWithdraw": true,
|
|
540
|
+
// "minDeposit": "0.00010",
|
|
541
|
+
// "minWithdrawal": "0.00010"
|
|
542
|
+
// },
|
|
543
|
+
// {
|
|
544
|
+
// "network": "Ethereum",
|
|
545
|
+
// "tokenId": "0xba0Dda8762C24dA9487f5FA026a9B64b695A07Ea",
|
|
546
|
+
// "transactionPrecision": "18",
|
|
547
|
+
// "isWithdrawalFeeChargedToUser": true,
|
|
548
|
+
// "canDeposit": true,
|
|
549
|
+
// "canWithdraw": true,
|
|
550
|
+
// "minDeposit": "0.00010",
|
|
551
|
+
// "minWithdrawal": "0.00010"
|
|
552
|
+
// },
|
|
553
|
+
// {
|
|
554
|
+
// "network": "Arbitrum",
|
|
555
|
+
// "tokenId": "0x78a0A62Fba6Fb21A83FE8a3433d44C73a4017A6f",
|
|
556
|
+
// "transactionPrecision": "18",
|
|
557
|
+
// "isWithdrawalFeeChargedToUser": true,
|
|
558
|
+
// "canDeposit": true,
|
|
559
|
+
// "canWithdraw": false,
|
|
560
|
+
// "minDeposit": "0.00010",
|
|
561
|
+
// "minWithdrawal": "0.00010"
|
|
562
|
+
// },
|
|
563
|
+
// {
|
|
564
|
+
// "network": "Avalanche",
|
|
565
|
+
// "tokenId": "0x78a0A62Fba6Fb21A83FE8a3433d44C73a4017A6f",
|
|
566
|
+
// "transactionPrecision": "18",
|
|
567
|
+
// "isWithdrawalFeeChargedToUser": true,
|
|
568
|
+
// "canDeposit": true,
|
|
569
|
+
// "canWithdraw": false,
|
|
570
|
+
// "minDeposit": "0.00010",
|
|
571
|
+
// "minWithdrawal": "0.00010"
|
|
572
|
+
// },
|
|
573
|
+
// {
|
|
574
|
+
// "network": "Solana",
|
|
575
|
+
// "tokenId": "DV3845GEAVXfwpyVGGgWbqBVCtzHdCXNCGfcdboSEuZz",
|
|
576
|
+
// "transactionPrecision": "8",
|
|
577
|
+
// "isWithdrawalFeeChargedToUser": true,
|
|
578
|
+
// "canDeposit": true,
|
|
579
|
+
// "canWithdraw": true,
|
|
580
|
+
// "minDeposit": "0.00010",
|
|
581
|
+
// "minWithdrawal": "0.00010"
|
|
582
|
+
// },
|
|
583
|
+
// {
|
|
584
|
+
// "network": "Ethereum",
|
|
585
|
+
// "tokenId": "0x78a0A62Fba6Fb21A83FE8a3433d44C73a4017A6f",
|
|
586
|
+
// "transactionPrecision": "18",
|
|
587
|
+
// "isWithdrawalFeeChargedToUser": true,
|
|
588
|
+
// "canDeposit": true,
|
|
589
|
+
// "canWithdraw": false,
|
|
590
|
+
// "minDeposit": "0.00010",
|
|
591
|
+
// "minWithdrawal": "0.00010"
|
|
592
|
+
// }
|
|
593
|
+
// ]
|
|
594
|
+
// },
|
|
595
|
+
// {
|
|
596
|
+
// "asset": "BTC",
|
|
597
|
+
// "isCollateral": true,
|
|
598
|
+
// "loanToValue": "0.950000000",
|
|
599
|
+
// "loanToValueFactor": "0.000000000",
|
|
600
|
+
// "networkList": [
|
|
601
|
+
// {
|
|
602
|
+
// "network": "Bitcoin",
|
|
603
|
+
// "transactionPrecision": "8",
|
|
604
|
+
// "isWithdrawalFeeChargedToUser": true,
|
|
605
|
+
// "canDeposit": true,
|
|
606
|
+
// "canWithdraw": true,
|
|
607
|
+
// "minDeposit": "0.00010",
|
|
608
|
+
// "minWithdrawal": "0.00010"
|
|
609
|
+
// }
|
|
610
|
+
// ]
|
|
611
|
+
// },
|
|
612
|
+
// {
|
|
613
|
+
// "asset": "USDT.ARB",
|
|
614
|
+
// "isCollateral": true,
|
|
615
|
+
// "loanToValue": "0.950000000",
|
|
616
|
+
// "loanToValueFactor": "0.000000000",
|
|
617
|
+
// "networkList": [
|
|
618
|
+
// {
|
|
619
|
+
// "network": "Arbitrum",
|
|
620
|
+
// "tokenId": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
|
|
621
|
+
// "transactionPrecision": "18",
|
|
622
|
+
// "isWithdrawalFeeChargedToUser": true,
|
|
623
|
+
// "canDeposit": true,
|
|
624
|
+
// "canWithdraw": true,
|
|
625
|
+
// "minDeposit": "0.00010",
|
|
626
|
+
// "minWithdrawal": "0.00010"
|
|
627
|
+
// }
|
|
628
|
+
// ]
|
|
629
|
+
// },
|
|
630
|
+
// ...
|
|
631
|
+
// ]
|
|
632
|
+
// }
|
|
633
|
+
//
|
|
634
|
+
const data = this.safeList(response, 'data', []);
|
|
635
|
+
const result = {};
|
|
636
|
+
for (let i = 0; i < data.length; i++) {
|
|
637
|
+
const currency = data[i];
|
|
638
|
+
const fullId = this.safeString(currency, 'asset', '');
|
|
639
|
+
const parts = fullId.split('.');
|
|
640
|
+
const id = parts[0];
|
|
641
|
+
const code = this.safeCurrencyCode(id);
|
|
642
|
+
let networks = {};
|
|
643
|
+
const chains = this.safeList(currency, 'networkList', []);
|
|
644
|
+
let currencyMaxPrecision = undefined;
|
|
645
|
+
let currencyDepositEnabled = undefined;
|
|
646
|
+
let currencyWithdrawEnabled = undefined;
|
|
647
|
+
for (let j = 0; j < chains.length; j++) {
|
|
648
|
+
const chain = chains[j];
|
|
649
|
+
const networkId = this.safeString(chain, 'network');
|
|
650
|
+
const networkCode = this.networkIdToCode(networkId);
|
|
651
|
+
const deposit = this.safeBool(chain, 'canDeposit');
|
|
652
|
+
const withdraw = this.safeBool(chain, 'canWithdraw');
|
|
653
|
+
const active = (deposit && withdraw);
|
|
654
|
+
const minDeposit = this.safeString(chain, 'minDeposit');
|
|
655
|
+
const minWithdrawal = this.safeString(chain, 'minWithdrawal');
|
|
656
|
+
const precision = this.parsePrecision(this.safeString(chain, 'transactionPrecision'));
|
|
657
|
+
networks[networkCode] = {
|
|
658
|
+
'id': networkId,
|
|
659
|
+
'network': networkCode,
|
|
660
|
+
'margin': undefined,
|
|
661
|
+
'deposit': deposit,
|
|
662
|
+
'withdraw': withdraw,
|
|
663
|
+
'active': active,
|
|
664
|
+
'fee': undefined,
|
|
665
|
+
'precision': this.parseNumber(precision),
|
|
666
|
+
'limits': {
|
|
667
|
+
'deposit': {
|
|
668
|
+
'min': minDeposit,
|
|
669
|
+
'max': undefined,
|
|
670
|
+
},
|
|
671
|
+
'withdraw': {
|
|
672
|
+
'min': minWithdrawal,
|
|
673
|
+
'max': undefined,
|
|
674
|
+
},
|
|
675
|
+
},
|
|
676
|
+
'info': chain,
|
|
677
|
+
};
|
|
678
|
+
if ((currencyDepositEnabled === undefined) || deposit) {
|
|
679
|
+
currencyDepositEnabled = deposit;
|
|
680
|
+
}
|
|
681
|
+
if ((currencyWithdrawEnabled === undefined) || withdraw) {
|
|
682
|
+
currencyWithdrawEnabled = withdraw;
|
|
683
|
+
}
|
|
684
|
+
if ((currencyMaxPrecision === undefined) || Precise["default"].stringGt(currencyMaxPrecision, precision)) {
|
|
685
|
+
currencyMaxPrecision = precision;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
if (code in result) {
|
|
689
|
+
// checking for specific ids as USDC.ARB
|
|
690
|
+
networks = this.extend(result[code]['networks'], networks);
|
|
691
|
+
}
|
|
692
|
+
result[code] = {
|
|
693
|
+
'id': id,
|
|
694
|
+
'code': code,
|
|
695
|
+
'name': undefined,
|
|
696
|
+
'type': undefined,
|
|
697
|
+
'active': undefined,
|
|
698
|
+
'deposit': currencyDepositEnabled,
|
|
699
|
+
'withdraw': currencyWithdrawEnabled,
|
|
700
|
+
'fee': undefined,
|
|
701
|
+
'precision': this.parseNumber(currencyMaxPrecision),
|
|
702
|
+
'limits': {
|
|
703
|
+
'amount': {
|
|
704
|
+
'min': undefined,
|
|
705
|
+
'max': undefined,
|
|
706
|
+
},
|
|
707
|
+
'withdraw': {
|
|
708
|
+
'min': undefined,
|
|
709
|
+
'max': undefined,
|
|
710
|
+
},
|
|
711
|
+
},
|
|
712
|
+
'networks': networks,
|
|
713
|
+
'info': currency,
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
return result;
|
|
717
|
+
}
|
|
718
|
+
async fetchTickers(symbols = undefined, params = {}) {
|
|
719
|
+
/**
|
|
720
|
+
* @method
|
|
721
|
+
* @name oxfun#fetchTickers
|
|
722
|
+
* @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
723
|
+
* @see https://docs.ox.fun/?json#get-v3-tickers
|
|
724
|
+
* @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
725
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
726
|
+
* @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
727
|
+
*/
|
|
728
|
+
await this.loadMarkets();
|
|
729
|
+
symbols = this.marketSymbols(symbols);
|
|
730
|
+
const response = await this.publicGetV3Tickers(params);
|
|
731
|
+
//
|
|
732
|
+
// {
|
|
733
|
+
// "success": true,
|
|
734
|
+
// "data": [
|
|
735
|
+
// {
|
|
736
|
+
// "marketCode": "NII-USDT",
|
|
737
|
+
// "markPrice": "0",
|
|
738
|
+
// "open24h": "0",
|
|
739
|
+
// "high24h": "0",
|
|
740
|
+
// "low24h": "0",
|
|
741
|
+
// "volume24h": "0",
|
|
742
|
+
// "currencyVolume24h": "0",
|
|
743
|
+
// "openInterest": "0",
|
|
744
|
+
// "lastTradedPrice": "0",
|
|
745
|
+
// "lastTradedQuantity": "0",
|
|
746
|
+
// "lastUpdatedAt": "1714853388621"
|
|
747
|
+
// },
|
|
748
|
+
// {
|
|
749
|
+
// "marketCode": "GEC-USDT",
|
|
750
|
+
// "markPrice": "0",
|
|
751
|
+
// "open24h": "0",
|
|
752
|
+
// "high24h": "0",
|
|
753
|
+
// "low24h": "0",
|
|
754
|
+
// "volume24h": "0",
|
|
755
|
+
// "currencyVolume24h": "0",
|
|
756
|
+
// "openInterest": "0",
|
|
757
|
+
// "lastTradedPrice": "0",
|
|
758
|
+
// "lastTradedQuantity": "0",
|
|
759
|
+
// "lastUpdatedAt": "1714853388621"
|
|
760
|
+
// },
|
|
761
|
+
// {
|
|
762
|
+
// "marketCode": "DYM-USD-SWAP-LIN",
|
|
763
|
+
// "markPrice": "3.321",
|
|
764
|
+
// "open24h": "3.315",
|
|
765
|
+
// "high24h": "3.356",
|
|
766
|
+
// "low24h": "3.255",
|
|
767
|
+
// "volume24h": "0",
|
|
768
|
+
// "currencyVolume24h": "0",
|
|
769
|
+
// "openInterest": "1768.1",
|
|
770
|
+
// "lastTradedPrice": "3.543",
|
|
771
|
+
// "lastTradedQuantity": "1.0",
|
|
772
|
+
// "lastUpdatedAt": "1714853388102"
|
|
773
|
+
// },
|
|
774
|
+
// ...
|
|
775
|
+
// ]
|
|
776
|
+
// }
|
|
777
|
+
//
|
|
778
|
+
const tickers = this.safeList(response, 'data', []);
|
|
779
|
+
return this.parseTickers(tickers, symbols);
|
|
780
|
+
}
|
|
781
|
+
async fetchTicker(symbol, params = {}) {
|
|
782
|
+
/**
|
|
783
|
+
* @method
|
|
784
|
+
* @name oxfun#fetchTicker
|
|
785
|
+
* @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
786
|
+
* @see https://docs.ox.fun/?json#get-v3-tickers
|
|
787
|
+
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
788
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
789
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
790
|
+
*/
|
|
791
|
+
await this.loadMarkets();
|
|
792
|
+
const market = this.market(symbol);
|
|
793
|
+
const request = {
|
|
794
|
+
'marketCode': market['id'],
|
|
795
|
+
};
|
|
796
|
+
const response = await this.publicGetV3Tickers(this.extend(request, params));
|
|
797
|
+
//
|
|
798
|
+
// {
|
|
799
|
+
// "success": true,
|
|
800
|
+
// "data": [
|
|
801
|
+
// {
|
|
802
|
+
// "marketCode": "BTC-USD-SWAP-LIN",
|
|
803
|
+
// "markPrice": "64276",
|
|
804
|
+
// "open24h": "63674",
|
|
805
|
+
// "high24h": "64607",
|
|
806
|
+
// "low24h": "62933",
|
|
807
|
+
// "volume24h": "306317655.80000",
|
|
808
|
+
// "currencyVolume24h": "48.06810",
|
|
809
|
+
// "openInterest": "72.39250",
|
|
810
|
+
// "lastTradedPrice": "64300.0",
|
|
811
|
+
// "lastTradedQuantity": "1.0",
|
|
812
|
+
// "lastUpdatedAt": "1714925196034"
|
|
813
|
+
// }
|
|
814
|
+
// ]
|
|
815
|
+
// }
|
|
816
|
+
//
|
|
817
|
+
const data = this.safeList(response, 'data', []);
|
|
818
|
+
const ticker = this.safeDict(data, 0, {});
|
|
819
|
+
return this.parseTicker(ticker, market);
|
|
820
|
+
}
|
|
821
|
+
parseTicker(ticker, market = undefined) {
|
|
822
|
+
//
|
|
823
|
+
// {
|
|
824
|
+
// "marketCode": "BTC-USD-SWAP-LIN",
|
|
825
|
+
// "markPrice": "64276",
|
|
826
|
+
// "open24h": "63674",
|
|
827
|
+
// "high24h": "64607",
|
|
828
|
+
// "low24h": "62933",
|
|
829
|
+
// "volume24h": "306317655.80000",
|
|
830
|
+
// "currencyVolume24h": "48.06810",
|
|
831
|
+
// "openInterest": "72.39250",
|
|
832
|
+
// "lastTradedPrice": "64300.0",
|
|
833
|
+
// "lastTradedQuantity": "1.0",
|
|
834
|
+
// "lastUpdatedAt": "1714925196034"
|
|
835
|
+
// }
|
|
836
|
+
//
|
|
837
|
+
const timestamp = this.safeInteger(ticker, 'lastUpdatedAt');
|
|
838
|
+
const marketId = this.safeString(ticker, 'marketCode');
|
|
839
|
+
market = this.safeMarket(marketId, market);
|
|
840
|
+
const symbol = market['symbol'];
|
|
841
|
+
const last = this.safeString(ticker, 'lastTradedPrice');
|
|
842
|
+
return this.safeTicker({
|
|
843
|
+
'symbol': symbol,
|
|
844
|
+
'timestamp': timestamp,
|
|
845
|
+
'datetime': this.iso8601(timestamp),
|
|
846
|
+
'high': this.safeString(ticker, 'high24h'),
|
|
847
|
+
'low': this.safeString(ticker, 'low24h'),
|
|
848
|
+
'bid': undefined,
|
|
849
|
+
'bidVolume': undefined,
|
|
850
|
+
'ask': undefined,
|
|
851
|
+
'askVolume': undefined,
|
|
852
|
+
'vwap': undefined,
|
|
853
|
+
'open': this.safeString(ticker, 'open24h'),
|
|
854
|
+
'close': last,
|
|
855
|
+
'last': last,
|
|
856
|
+
'previousClose': undefined,
|
|
857
|
+
'change': undefined,
|
|
858
|
+
'percentage': undefined,
|
|
859
|
+
'average': undefined,
|
|
860
|
+
'baseVolume': this.safeString(ticker, 'currencyVolume24h'),
|
|
861
|
+
'quoteVolume': undefined,
|
|
862
|
+
'info': ticker,
|
|
863
|
+
}, market);
|
|
864
|
+
}
|
|
865
|
+
async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
|
866
|
+
/**
|
|
867
|
+
* @method
|
|
868
|
+
* @name oxfun#fetchOHLCV
|
|
869
|
+
* @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
870
|
+
* @see https://docs.ox.fun/?json#get-v3-candles
|
|
871
|
+
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
872
|
+
* @param {string} timeframe the length of time each candle represents
|
|
873
|
+
* @param {int} [since] timestamp in ms of the earliest candle to fetch (default 24 hours ago)
|
|
874
|
+
* @param {int} [limit] the maximum amount of candles to fetch (default 200, max 500)
|
|
875
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
876
|
+
* @param {int} [params.until] timestamp in ms of the latest candle to fetch (default now)
|
|
877
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
878
|
+
*/
|
|
879
|
+
await this.loadMarkets();
|
|
880
|
+
const market = this.market(symbol);
|
|
881
|
+
timeframe = this.safeString(this.timeframes, timeframe, timeframe);
|
|
882
|
+
const request = {
|
|
883
|
+
'marketCode': market['id'],
|
|
884
|
+
'timeframe': timeframe,
|
|
885
|
+
};
|
|
886
|
+
if (since !== undefined) {
|
|
887
|
+
request['startTime'] = since; // startTime and endTime must be within 7 days of each other
|
|
888
|
+
}
|
|
889
|
+
if (limit !== undefined) {
|
|
890
|
+
request['limit'] = limit;
|
|
891
|
+
}
|
|
892
|
+
const until = this.safeInteger(params, 'until');
|
|
893
|
+
if (until !== undefined) {
|
|
894
|
+
request['endTime'] = until;
|
|
895
|
+
params = this.omit(params, 'until');
|
|
896
|
+
}
|
|
897
|
+
else if (since !== undefined) {
|
|
898
|
+
request['endTime'] = this.sum(since, 7 * 24 * 60 * 60 * 1000); // for the exchange not to throw an exception if since is younger than 7 days
|
|
899
|
+
}
|
|
900
|
+
const response = await this.publicGetV3Candles(this.extend(request, params));
|
|
901
|
+
//
|
|
902
|
+
// {
|
|
903
|
+
// "success": true,
|
|
904
|
+
// "timeframe": "3600s",
|
|
905
|
+
// "data": [
|
|
906
|
+
// {
|
|
907
|
+
// "open": "0.03240000",
|
|
908
|
+
// "high": "0.03240000",
|
|
909
|
+
// "low": "0.03240000",
|
|
910
|
+
// "close": "0.03240000",
|
|
911
|
+
// "volume": "0",
|
|
912
|
+
// "currencyVolume": "0",
|
|
913
|
+
// "openedAt": "1714906800000"
|
|
914
|
+
// },
|
|
915
|
+
// {
|
|
916
|
+
// "open": "0.03240000",
|
|
917
|
+
// "high": "0.03240000",
|
|
918
|
+
// "low": "0.03240000",
|
|
919
|
+
// "close": "0.03240000",
|
|
920
|
+
// "volume": "0",
|
|
921
|
+
// "currencyVolume": "0",
|
|
922
|
+
// "openedAt": "1714903200000"
|
|
923
|
+
// },
|
|
924
|
+
// ...
|
|
925
|
+
// ]
|
|
926
|
+
// }
|
|
927
|
+
//
|
|
928
|
+
const result = this.safeList(response, 'data', []);
|
|
929
|
+
return this.parseOHLCVs(result, market, timeframe, since, limit);
|
|
930
|
+
}
|
|
931
|
+
parseOHLCV(ohlcv, market = undefined) {
|
|
932
|
+
//
|
|
933
|
+
// {
|
|
934
|
+
// "open": "0.03240000",
|
|
935
|
+
// "high": "0.03240000",
|
|
936
|
+
// "low": "0.03240000",
|
|
937
|
+
// "close": "0.03240000",
|
|
938
|
+
// "volume": "0",
|
|
939
|
+
// "currencyVolume": "0",
|
|
940
|
+
// "openedAt": "1714906800000"
|
|
941
|
+
// }
|
|
942
|
+
//
|
|
943
|
+
return [
|
|
944
|
+
this.safeInteger(ohlcv, 'openedAt'),
|
|
945
|
+
this.safeNumber(ohlcv, 'open'),
|
|
946
|
+
this.safeNumber(ohlcv, 'high'),
|
|
947
|
+
this.safeNumber(ohlcv, 'low'),
|
|
948
|
+
this.safeNumber(ohlcv, 'close'),
|
|
949
|
+
this.safeNumber(ohlcv, 'currencyVolume'),
|
|
950
|
+
];
|
|
951
|
+
}
|
|
952
|
+
async fetchOrderBook(symbol, limit = undefined, params = {}) {
|
|
953
|
+
/**
|
|
954
|
+
* @method
|
|
955
|
+
* @name oxfun#fetchOrderBook
|
|
956
|
+
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
957
|
+
* @see https://docs.ox.fun/?json#get-v3-depth
|
|
958
|
+
* @param {string} symbol unified symbol of the market to fetch the order book for
|
|
959
|
+
* @param {int} [limit] the maximum amount of order book entries to return (default 5, max 100)
|
|
960
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
961
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
962
|
+
*/
|
|
963
|
+
await this.loadMarkets();
|
|
964
|
+
const market = this.market(symbol);
|
|
965
|
+
const request = {
|
|
966
|
+
'marketCode': market['id'],
|
|
967
|
+
};
|
|
968
|
+
if (limit !== undefined) {
|
|
969
|
+
request['level'] = limit;
|
|
970
|
+
}
|
|
971
|
+
const response = await this.publicGetV3Depth(this.extend(request, params));
|
|
972
|
+
//
|
|
973
|
+
// {
|
|
974
|
+
// "success": true,
|
|
975
|
+
// "level": "5",
|
|
976
|
+
// "data": {
|
|
977
|
+
// "marketCode": "BTC-USD-SWAP-LIN",
|
|
978
|
+
// "lastUpdatedAt": "1714933499266",
|
|
979
|
+
// "asks": [
|
|
980
|
+
// [ 64073.0, 8.4622 ],
|
|
981
|
+
// [ 64092.0, 8.1912 ],
|
|
982
|
+
// [ 64111.0, 8.0669 ],
|
|
983
|
+
// [ 64130.0, 11.7195 ],
|
|
984
|
+
// [ 64151.0, 10.1798 ]
|
|
985
|
+
// ],
|
|
986
|
+
// "bids": [
|
|
987
|
+
// [ 64022.0, 10.1292 ],
|
|
988
|
+
// [ 64003.0, 8.1619 ],
|
|
989
|
+
// [ 64000.0, 1.0 ],
|
|
990
|
+
// [ 63984.0, 12.7724 ],
|
|
991
|
+
// [ 63963.0, 11.0073 ]
|
|
992
|
+
// ]
|
|
993
|
+
// }
|
|
994
|
+
// }
|
|
995
|
+
//
|
|
996
|
+
const data = this.safeDict(response, 'data', {});
|
|
997
|
+
const timestamp = this.safeInteger(data, 'lastUpdatedAt');
|
|
998
|
+
return this.parseOrderBook(data, market['symbol'], timestamp);
|
|
999
|
+
}
|
|
1000
|
+
async fetchFundingRates(symbols = undefined, params = {}) {
|
|
1001
|
+
/**
|
|
1002
|
+
* @method
|
|
1003
|
+
* @name oxfun#fetchFundingRates
|
|
1004
|
+
* @see https://docs.ox.fun/?json#get-v3-funding-estimates
|
|
1005
|
+
* @description fetch the current funding rates
|
|
1006
|
+
* @param {string[]} symbols unified market symbols
|
|
1007
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1008
|
+
* @returns {Order[]} an array of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
|
|
1009
|
+
*/
|
|
1010
|
+
await this.loadMarkets();
|
|
1011
|
+
symbols = this.marketSymbols(symbols);
|
|
1012
|
+
const response = await this.publicGetV3FundingEstimates(params);
|
|
1013
|
+
//
|
|
1014
|
+
// {
|
|
1015
|
+
// "success": true,
|
|
1016
|
+
// "data": [
|
|
1017
|
+
// {
|
|
1018
|
+
// "marketCode": "OX-USD-SWAP-LIN",
|
|
1019
|
+
// "fundingAt": "1715515200000",
|
|
1020
|
+
// "estFundingRate": "0.000200000"
|
|
1021
|
+
// },
|
|
1022
|
+
// {
|
|
1023
|
+
// "marketCode": "BTC-USD-SWAP-LIN",
|
|
1024
|
+
// "fundingAt": "1715515200000",
|
|
1025
|
+
// "estFundingRate": "0.000003"
|
|
1026
|
+
// },
|
|
1027
|
+
// ...
|
|
1028
|
+
// ]
|
|
1029
|
+
// }
|
|
1030
|
+
//
|
|
1031
|
+
const data = this.safeList(response, 'data', []);
|
|
1032
|
+
const result = this.parseFundingRates(data);
|
|
1033
|
+
return this.filterByArray(result, 'symbol', symbols);
|
|
1034
|
+
}
|
|
1035
|
+
parseFundingRate(fundingRate, market = undefined) {
|
|
1036
|
+
//
|
|
1037
|
+
// {
|
|
1038
|
+
// "marketCode": "OX-USD-SWAP-LIN",
|
|
1039
|
+
// "fundingAt": "1715515200000",
|
|
1040
|
+
// "estFundingRate": "0.000200000"
|
|
1041
|
+
// },
|
|
1042
|
+
//
|
|
1043
|
+
//
|
|
1044
|
+
const symbol = this.safeString(fundingRate, 'marketCode');
|
|
1045
|
+
market = this.market(symbol);
|
|
1046
|
+
const estFundingRateTimestamp = this.safeInteger(fundingRate, 'fundingAt');
|
|
1047
|
+
return {
|
|
1048
|
+
'info': fundingRate,
|
|
1049
|
+
'symbol': market['symbol'],
|
|
1050
|
+
'markPrice': undefined,
|
|
1051
|
+
'indexPrice': undefined,
|
|
1052
|
+
'interestRate': this.parseNumber('0'),
|
|
1053
|
+
'estimatedSettlePrice': undefined,
|
|
1054
|
+
'timestamp': estFundingRateTimestamp,
|
|
1055
|
+
'datetime': this.iso8601(estFundingRateTimestamp),
|
|
1056
|
+
'fundingRate': this.safeNumber(fundingRate, 'estFundingRate'),
|
|
1057
|
+
'fundingTimestamp': undefined,
|
|
1058
|
+
'fundingDatetime': undefined,
|
|
1059
|
+
'nextFundingRate': undefined,
|
|
1060
|
+
'nextFundingTimestamp': undefined,
|
|
1061
|
+
'nextFundingDatetime': undefined,
|
|
1062
|
+
'previousFundingRate': undefined,
|
|
1063
|
+
'previousFundingTimestamp': undefined,
|
|
1064
|
+
'previousFundingDatetime': undefined,
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1068
|
+
/**
|
|
1069
|
+
* @method
|
|
1070
|
+
* @name oxfun#fetchFundingRateHistory
|
|
1071
|
+
* @description Fetches the history of funding rates
|
|
1072
|
+
* @see https://docs.ox.fun/?json#get-v3-funding-rates
|
|
1073
|
+
* @param {string} symbol unified symbol of the market to fetch trades for
|
|
1074
|
+
* @param {int} [since] timestamp in ms of the earliest trade to fetch (default 24 hours ago)
|
|
1075
|
+
* @param {int} [limit] the maximum amount of trades to fetch (default 200, max 500)
|
|
1076
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1077
|
+
* @param {int} [params.until] timestamp in ms of the latest trade to fetch (default now)
|
|
1078
|
+
* @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
|
|
1079
|
+
*/
|
|
1080
|
+
await this.loadMarkets();
|
|
1081
|
+
const market = this.market(symbol);
|
|
1082
|
+
const request = {
|
|
1083
|
+
'marketCode': market['id'],
|
|
1084
|
+
};
|
|
1085
|
+
if (since !== undefined) {
|
|
1086
|
+
request['startTime'] = since; // startTime and endTime must be within 7 days of each other
|
|
1087
|
+
}
|
|
1088
|
+
if (limit !== undefined) {
|
|
1089
|
+
request['limit'] = limit;
|
|
1090
|
+
}
|
|
1091
|
+
const until = this.safeInteger(params, 'until');
|
|
1092
|
+
if (until !== undefined) {
|
|
1093
|
+
request['endTime'] = until;
|
|
1094
|
+
params = this.omit(params, 'until');
|
|
1095
|
+
}
|
|
1096
|
+
const response = await this.publicGetV3FundingRates(this.extend(request, params));
|
|
1097
|
+
//
|
|
1098
|
+
// {
|
|
1099
|
+
// success: true,
|
|
1100
|
+
// data: [
|
|
1101
|
+
// {
|
|
1102
|
+
// marketCode: 'NEAR-USD-SWAP-LIN',
|
|
1103
|
+
// fundingRate: '-0.000010000',
|
|
1104
|
+
// createdAt: '1715428870755'
|
|
1105
|
+
// },
|
|
1106
|
+
// {
|
|
1107
|
+
// marketCode: 'ENA-USD-SWAP-LIN',
|
|
1108
|
+
// fundingRate: '0.000150000',
|
|
1109
|
+
// createdAt: '1715428868616'
|
|
1110
|
+
// },
|
|
1111
|
+
// ...
|
|
1112
|
+
// }
|
|
1113
|
+
//
|
|
1114
|
+
const data = this.safeList(response, 'data', []);
|
|
1115
|
+
return this.parseFundingRateHistories(data, market, since, limit);
|
|
1116
|
+
}
|
|
1117
|
+
parseFundingRateHistory(info, market = undefined) {
|
|
1118
|
+
//
|
|
1119
|
+
// {
|
|
1120
|
+
// success: true,
|
|
1121
|
+
// data: [
|
|
1122
|
+
// {
|
|
1123
|
+
// marketCode: 'NEAR-USD-SWAP-LIN',
|
|
1124
|
+
// fundingRate: '-0.000010000',
|
|
1125
|
+
// createdAt: '1715428870755'
|
|
1126
|
+
// },
|
|
1127
|
+
// {
|
|
1128
|
+
// marketCode: 'ENA-USD-SWAP-LIN',
|
|
1129
|
+
// fundingRate: '0.000150000',
|
|
1130
|
+
// createdAt: '1715428868616'
|
|
1131
|
+
// },
|
|
1132
|
+
// ...
|
|
1133
|
+
// }
|
|
1134
|
+
//
|
|
1135
|
+
const marketId = this.safeString(info, 'marketCode');
|
|
1136
|
+
market = this.safeMarket(marketId, market);
|
|
1137
|
+
const symbol = market['symbol'];
|
|
1138
|
+
const timestamp = this.safeInteger(info, 'createdAt');
|
|
1139
|
+
return {
|
|
1140
|
+
'info': info,
|
|
1141
|
+
'symbol': symbol,
|
|
1142
|
+
'fundingRate': this.safeNumber(info, 'fundingRate'),
|
|
1143
|
+
'timestamp': timestamp,
|
|
1144
|
+
'datetime': this.iso8601(timestamp),
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
async fetchFundingHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1148
|
+
/**
|
|
1149
|
+
* @method
|
|
1150
|
+
* @name oxfun#fetchFundingHistory
|
|
1151
|
+
* @description fetches the history of funding payments
|
|
1152
|
+
* @see https://docs.ox.fun/?json#get-v3-funding
|
|
1153
|
+
* @param {string} symbol unified symbol of the market to fetch trades for
|
|
1154
|
+
* @param {int} [since] timestamp in ms of the earliest trade to fetch (default 24 hours ago)
|
|
1155
|
+
* @param {int} [limit] the maximum amount of trades to fetch (default 200, max 500)
|
|
1156
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1157
|
+
* @param {int} [params.until] timestamp in ms of the latest trade to fetch (default now)
|
|
1158
|
+
* @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
|
|
1159
|
+
*/
|
|
1160
|
+
await this.loadMarkets();
|
|
1161
|
+
const market = this.market(symbol);
|
|
1162
|
+
const request = {
|
|
1163
|
+
'marketCode': market['id'],
|
|
1164
|
+
};
|
|
1165
|
+
if (since !== undefined) {
|
|
1166
|
+
request['startTime'] = since; // startTime and endTime must be within 7 days of each other
|
|
1167
|
+
}
|
|
1168
|
+
if (limit !== undefined) {
|
|
1169
|
+
request['limit'] = limit;
|
|
1170
|
+
}
|
|
1171
|
+
const until = this.safeInteger(params, 'until');
|
|
1172
|
+
if (until !== undefined) {
|
|
1173
|
+
request['endTime'] = until;
|
|
1174
|
+
params = this.omit(params, 'until');
|
|
1175
|
+
}
|
|
1176
|
+
const response = await this.privateGetV3Funding(this.extend(request, params));
|
|
1177
|
+
//
|
|
1178
|
+
// {
|
|
1179
|
+
// success: true,
|
|
1180
|
+
// data: [
|
|
1181
|
+
// {
|
|
1182
|
+
// id: '966709913041305605',
|
|
1183
|
+
// marketCode: 'ETH-USD-SWAP-LIN',
|
|
1184
|
+
// payment: '-0.00430822',
|
|
1185
|
+
// fundingRate: '0.000014',
|
|
1186
|
+
// position: '0.001',
|
|
1187
|
+
// indexPrice: '3077.3',
|
|
1188
|
+
// createdAt: '1715086852890'
|
|
1189
|
+
// },
|
|
1190
|
+
// {
|
|
1191
|
+
// id: '966698111997509637',
|
|
1192
|
+
// marketCode: 'ETH-USD-SWAP-LIN',
|
|
1193
|
+
// payment: '-0.0067419',
|
|
1194
|
+
// fundingRate: '0.000022',
|
|
1195
|
+
// position: '0.001',
|
|
1196
|
+
// indexPrice: '3064.5',
|
|
1197
|
+
// createdAt: '1715083251516'
|
|
1198
|
+
// },
|
|
1199
|
+
// ...
|
|
1200
|
+
// ]
|
|
1201
|
+
// }
|
|
1202
|
+
//
|
|
1203
|
+
const result = this.safeList(response, 'data', []);
|
|
1204
|
+
return this.parseIncomes(result, market, since, limit);
|
|
1205
|
+
}
|
|
1206
|
+
parseIncome(income, market = undefined) {
|
|
1207
|
+
//
|
|
1208
|
+
// {
|
|
1209
|
+
// id: '966709913041305605',
|
|
1210
|
+
// marketCode: 'ETH-USD-SWAP-LIN',
|
|
1211
|
+
// payment: '-0.00430822',
|
|
1212
|
+
// fundingRate: '0.000014',
|
|
1213
|
+
// position: '0.001',
|
|
1214
|
+
// indexPrice: '3077.3',
|
|
1215
|
+
// createdAt: '1715086852890'
|
|
1216
|
+
// },
|
|
1217
|
+
//
|
|
1218
|
+
const marketId = this.safeString(income, 'marketCode');
|
|
1219
|
+
const symbol = this.safeSymbol(marketId, market);
|
|
1220
|
+
const amount = this.safeNumber(income, 'payment');
|
|
1221
|
+
const code = this.safeCurrencyCode('OX');
|
|
1222
|
+
const id = this.safeString(income, 'id');
|
|
1223
|
+
const timestamp = this.safeTimestamp(income, 'createdAt');
|
|
1224
|
+
const rate = this.safeNumber(income, 'fundingRate');
|
|
1225
|
+
return {
|
|
1226
|
+
'info': income,
|
|
1227
|
+
'symbol': symbol,
|
|
1228
|
+
'code': code,
|
|
1229
|
+
'timestamp': timestamp,
|
|
1230
|
+
'datetime': this.iso8601(timestamp),
|
|
1231
|
+
'id': id,
|
|
1232
|
+
'amount': amount,
|
|
1233
|
+
'rate': rate,
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
async fetchLeverageTiers(symbols = undefined, params = {}) {
|
|
1237
|
+
/**
|
|
1238
|
+
* @method
|
|
1239
|
+
* @name oxfun#fetchLeverageTiers
|
|
1240
|
+
* @description retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes, if a market has a leverage tier of 0, then the leverage tiers cannot be obtained for this market
|
|
1241
|
+
* @see https://docs.ox.fun/?json#get-v3-leverage-tiers
|
|
1242
|
+
* @param {string[]} [symbols] list of unified market symbols
|
|
1243
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1244
|
+
* @returns {object} a dictionary of [leverage tiers structures]{@link https://docs.ccxt.com/#/?id=leverage-tiers-structure}, indexed by market symbols
|
|
1245
|
+
*/
|
|
1246
|
+
await this.loadMarkets();
|
|
1247
|
+
const response = await this.publicGetV3LeverageTiers(params);
|
|
1248
|
+
//
|
|
1249
|
+
// {
|
|
1250
|
+
// success: true,
|
|
1251
|
+
// data: [
|
|
1252
|
+
// {
|
|
1253
|
+
// marketCode: 'SOL-USD-SWAP-LIN',
|
|
1254
|
+
// tiers: [
|
|
1255
|
+
// {
|
|
1256
|
+
// tier: '1',
|
|
1257
|
+
// leverage: '10',
|
|
1258
|
+
// positionFloor: '0',
|
|
1259
|
+
// positionCap: '200000000',
|
|
1260
|
+
// initialMargin: '0.1',
|
|
1261
|
+
// maintenanceMargin: '0.05',
|
|
1262
|
+
// maintenanceAmount: '0'
|
|
1263
|
+
// },
|
|
1264
|
+
// {
|
|
1265
|
+
// tier: '2',
|
|
1266
|
+
// leverage: '5',
|
|
1267
|
+
// positionFloor: '200000000',
|
|
1268
|
+
// positionCap: '280000000',
|
|
1269
|
+
// initialMargin: '0.2',
|
|
1270
|
+
// maintenanceMargin: '0.1',
|
|
1271
|
+
// maintenanceAmount: '7000000'
|
|
1272
|
+
// },
|
|
1273
|
+
// {
|
|
1274
|
+
// tier: '3',
|
|
1275
|
+
// leverage: '4',
|
|
1276
|
+
// positionFloor: '280000000',
|
|
1277
|
+
// positionCap: '460000000',
|
|
1278
|
+
// initialMargin: '0.25',
|
|
1279
|
+
// maintenanceMargin: '0.125',
|
|
1280
|
+
// maintenanceAmount: '14000000'
|
|
1281
|
+
// },
|
|
1282
|
+
// ...
|
|
1283
|
+
// ]
|
|
1284
|
+
// },
|
|
1285
|
+
// ...
|
|
1286
|
+
// ]
|
|
1287
|
+
// }
|
|
1288
|
+
//
|
|
1289
|
+
const data = this.safeList(response, 'data', []);
|
|
1290
|
+
return this.parseLeverageTiers(data, symbols, 'marketCode');
|
|
1291
|
+
}
|
|
1292
|
+
parseMarketLeverageTiers(info, market = undefined) {
|
|
1293
|
+
//
|
|
1294
|
+
// {
|
|
1295
|
+
// marketCode: 'SOL-USD-SWAP-LIN',
|
|
1296
|
+
// tiers: [
|
|
1297
|
+
// {
|
|
1298
|
+
// tier: '1',
|
|
1299
|
+
// leverage: '10',
|
|
1300
|
+
// positionFloor: '0',
|
|
1301
|
+
// positionCap: '200000000',
|
|
1302
|
+
// initialMargin: '0.1',
|
|
1303
|
+
// maintenanceMargin: '0.05',
|
|
1304
|
+
// maintenanceAmount: '0'
|
|
1305
|
+
// ...
|
|
1306
|
+
// ]
|
|
1307
|
+
// },
|
|
1308
|
+
//
|
|
1309
|
+
const marketId = this.safeString(info, 'marketCode');
|
|
1310
|
+
market = this.safeMarket(marketId, market);
|
|
1311
|
+
const listOfTiers = this.safeList(info, 'tiers', []);
|
|
1312
|
+
const tiers = [];
|
|
1313
|
+
for (let j = 0; j < listOfTiers.length; j++) {
|
|
1314
|
+
const tier = listOfTiers[j];
|
|
1315
|
+
tiers.push({
|
|
1316
|
+
'tier': this.safeNumber(tier, 'tier'),
|
|
1317
|
+
'currency': market['settle'],
|
|
1318
|
+
'minNotional': this.safeNumber(tier, 'positionFloor'),
|
|
1319
|
+
'maxNotional': this.safeNumber(tier, 'positionCap'),
|
|
1320
|
+
'maintenanceMarginRate': this.safeNumber(tier, 'maintenanceMargin'),
|
|
1321
|
+
'maxLeverage': this.safeNumber(tier, 'leverage'),
|
|
1322
|
+
'info': tier,
|
|
1323
|
+
});
|
|
1324
|
+
}
|
|
1325
|
+
return tiers;
|
|
1326
|
+
}
|
|
1327
|
+
async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
|
|
1328
|
+
/**
|
|
1329
|
+
* @method
|
|
1330
|
+
* @name oxfun#fetchTrades
|
|
1331
|
+
* @description get the list of most recent trades for a particular symbol
|
|
1332
|
+
* @see https://docs.ox.fun/?json#get-v3-exchange-trades
|
|
1333
|
+
* @param {string} symbol unified symbol of the market to fetch trades for
|
|
1334
|
+
* @param {int} [since] timestamp in ms of the earliest trade to fetch (default 24 hours ago)
|
|
1335
|
+
* @param {int} [limit] the maximum amount of trades to fetch (default 200, max 500)
|
|
1336
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1337
|
+
* @param {int} [params.until] timestamp in ms of the latest trade to fetch (default now)
|
|
1338
|
+
* @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
|
|
1339
|
+
*/
|
|
1340
|
+
await this.loadMarkets();
|
|
1341
|
+
const market = this.market(symbol);
|
|
1342
|
+
const request = {
|
|
1343
|
+
'marketCode': market['id'],
|
|
1344
|
+
};
|
|
1345
|
+
if (since !== undefined) {
|
|
1346
|
+
request['startTime'] = since; // startTime and endTime must be within 7 days of each other
|
|
1347
|
+
}
|
|
1348
|
+
if (limit !== undefined) {
|
|
1349
|
+
request['limit'] = limit;
|
|
1350
|
+
}
|
|
1351
|
+
const until = this.safeInteger(params, 'until');
|
|
1352
|
+
if (until !== undefined) {
|
|
1353
|
+
request['endTime'] = until;
|
|
1354
|
+
params = this.omit(params, 'until');
|
|
1355
|
+
}
|
|
1356
|
+
else if (since !== undefined) {
|
|
1357
|
+
request['endTime'] = this.sum(since, 7 * 24 * 60 * 60 * 1000); // for the exchange not to throw an exception if since is younger than 7 days
|
|
1358
|
+
}
|
|
1359
|
+
const response = await this.publicGetV3ExchangeTrades(this.extend(request, params));
|
|
1360
|
+
//
|
|
1361
|
+
// {
|
|
1362
|
+
// "success": true,
|
|
1363
|
+
// "data": [
|
|
1364
|
+
// {
|
|
1365
|
+
// "marketCode": "BTC-USD-SWAP-LIN",
|
|
1366
|
+
// "matchPrice": "63900",
|
|
1367
|
+
// "matchQuantity": "1",
|
|
1368
|
+
// "side": "SELL",
|
|
1369
|
+
// "matchType": "TAKER",
|
|
1370
|
+
// "matchedAt": "1714934112352"
|
|
1371
|
+
// },
|
|
1372
|
+
// ...
|
|
1373
|
+
// ]
|
|
1374
|
+
// }
|
|
1375
|
+
//
|
|
1376
|
+
const data = this.safeList(response, 'data', []);
|
|
1377
|
+
return this.parseTrades(data, market, since, limit);
|
|
1378
|
+
}
|
|
1379
|
+
async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1380
|
+
/**
|
|
1381
|
+
* @method
|
|
1382
|
+
* @name oxfun#fetchMyTrades
|
|
1383
|
+
* @description fetch all trades made by the user
|
|
1384
|
+
* @see https://docs.ox.fun/?json#get-v3-trades
|
|
1385
|
+
* @param {string} symbol unified market symbol
|
|
1386
|
+
* @param {int} [since] the earliest time in ms to fetch trades for
|
|
1387
|
+
* @param {int} [limit] the maximum amount of trades to fetch (default 200, max 500)
|
|
1388
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1389
|
+
* @param {int} [params.until] timestamp in ms of the latest trade to fetch (default now)
|
|
1390
|
+
* @returns {Trade[]} a list of [trade structures]{@link https://github.com/ccxt/ccxt/wiki/Manual#trade-structure}
|
|
1391
|
+
*/
|
|
1392
|
+
await this.loadMarkets();
|
|
1393
|
+
const request = {};
|
|
1394
|
+
let market = undefined;
|
|
1395
|
+
if (symbol !== undefined) {
|
|
1396
|
+
market = this.market(symbol);
|
|
1397
|
+
request['marketCode'] = market['id'];
|
|
1398
|
+
}
|
|
1399
|
+
if (since !== undefined) { // startTime and endTime must be within 7 days of each other
|
|
1400
|
+
request['startTime'] = since;
|
|
1401
|
+
}
|
|
1402
|
+
if (limit !== undefined) {
|
|
1403
|
+
request['limit'] = limit;
|
|
1404
|
+
}
|
|
1405
|
+
const until = this.safeInteger(params, 'until');
|
|
1406
|
+
if (until !== undefined) {
|
|
1407
|
+
request['endTime'] = until;
|
|
1408
|
+
params = this.omit(params, 'until');
|
|
1409
|
+
}
|
|
1410
|
+
else if (since !== undefined) {
|
|
1411
|
+
request['endTime'] = this.sum(since, 7 * 24 * 60 * 60 * 1000); // for the exchange not to throw an exception if since is younger than 7 days
|
|
1412
|
+
}
|
|
1413
|
+
const response = await this.privateGetV3Trades(this.extend(request, params));
|
|
1414
|
+
//
|
|
1415
|
+
// {
|
|
1416
|
+
// "success": true,
|
|
1417
|
+
// "data": [
|
|
1418
|
+
// {
|
|
1419
|
+
// "orderId": "1000104903698",
|
|
1420
|
+
// "clientOrderId": "1715000260094",
|
|
1421
|
+
// "matchId": "400017129522773178",
|
|
1422
|
+
// "marketCode": "ETH-USD-SWAP-LIN",
|
|
1423
|
+
// "side": "BUY",
|
|
1424
|
+
// "matchedQuantity": "0.001",
|
|
1425
|
+
// "matchPrice": "3100.2",
|
|
1426
|
+
// "total": "310.02",
|
|
1427
|
+
// "orderMatchType": "MAKER",
|
|
1428
|
+
// "feeAsset": "OX",
|
|
1429
|
+
// "fee": "0.062004",
|
|
1430
|
+
// "source": "0",
|
|
1431
|
+
// "matchedAt": "1715000267420"
|
|
1432
|
+
// }
|
|
1433
|
+
// ]
|
|
1434
|
+
// }
|
|
1435
|
+
//
|
|
1436
|
+
const result = this.safeList(response, 'data', []);
|
|
1437
|
+
return this.parseTrades(result, market, since, limit);
|
|
1438
|
+
}
|
|
1439
|
+
parseTrade(trade, market = undefined) {
|
|
1440
|
+
//
|
|
1441
|
+
// public fetchTrades
|
|
1442
|
+
//
|
|
1443
|
+
// {
|
|
1444
|
+
// "marketCode": "BTC-USD-SWAP-LIN",
|
|
1445
|
+
// "matchPrice": "63900",
|
|
1446
|
+
// "matchQuantity": "1",
|
|
1447
|
+
// "side": "SELL",
|
|
1448
|
+
// "matchType": "TAKER",
|
|
1449
|
+
// "matchedAt": "1714934112352"
|
|
1450
|
+
// }
|
|
1451
|
+
//
|
|
1452
|
+
//
|
|
1453
|
+
// private fetchMyTrades
|
|
1454
|
+
//
|
|
1455
|
+
// {
|
|
1456
|
+
// "orderId": "1000104903698",
|
|
1457
|
+
// "clientOrderId": "1715000260094",
|
|
1458
|
+
// "matchId": "400017129522773178",
|
|
1459
|
+
// "marketCode": "ETH-USD-SWAP-LIN",
|
|
1460
|
+
// "side": "BUY",
|
|
1461
|
+
// "matchedQuantity": "0.001",
|
|
1462
|
+
// "matchPrice": "3100.2",
|
|
1463
|
+
// "total": "310.02",
|
|
1464
|
+
// "orderMatchType": "MAKER",
|
|
1465
|
+
// "feeAsset": "OX",
|
|
1466
|
+
// "fee": "0.062004",
|
|
1467
|
+
// "source": "0",
|
|
1468
|
+
// "matchedAt": "1715000267420"
|
|
1469
|
+
// }
|
|
1470
|
+
//
|
|
1471
|
+
const marketId = this.safeString(trade, 'marketCode');
|
|
1472
|
+
market = this.safeMarket(marketId, market);
|
|
1473
|
+
const symbol = market['symbol'];
|
|
1474
|
+
const timestamp = this.safeInteger(trade, 'matchedAt');
|
|
1475
|
+
const fee = {
|
|
1476
|
+
'cost': this.safeString(trade, 'fee'),
|
|
1477
|
+
'currency': this.safeCurrencyCode(this.safeString(trade, 'feeAsset')),
|
|
1478
|
+
};
|
|
1479
|
+
return this.safeTrade({
|
|
1480
|
+
'id': this.safeString(trade, 'matchId'),
|
|
1481
|
+
'timestamp': timestamp,
|
|
1482
|
+
'datetime': this.iso8601(timestamp),
|
|
1483
|
+
'symbol': symbol,
|
|
1484
|
+
'type': undefined,
|
|
1485
|
+
'order': this.safeString(trade, 'orderId'),
|
|
1486
|
+
'side': this.safeStringLower(trade, 'side'),
|
|
1487
|
+
'takerOrMaker': this.safeStringLower2(trade, 'matchType', 'orderMatchType'),
|
|
1488
|
+
'price': this.safeString(trade, 'matchPrice'),
|
|
1489
|
+
'amount': this.safeString2(trade, 'matchQuantity', 'matchedQuantity'),
|
|
1490
|
+
'cost': undefined,
|
|
1491
|
+
'fee': fee,
|
|
1492
|
+
'info': trade,
|
|
1493
|
+
}, market);
|
|
1494
|
+
}
|
|
1495
|
+
async fetchBalance(params = {}) {
|
|
1496
|
+
/**
|
|
1497
|
+
* @method
|
|
1498
|
+
* @name oxfun#fetchBalance
|
|
1499
|
+
* @description query for balance and get the amount of funds available for trading or funds locked in orders
|
|
1500
|
+
* @see https://docs.ox.fun/?json#get-v3-balances
|
|
1501
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1502
|
+
* @param {string} [params.asset] currency id, if empty the exchange returns info about all currencies
|
|
1503
|
+
* @param {string} [params.subAcc] Name of sub account. If no subAcc is given, then the response contains only the account linked to the API-Key.
|
|
1504
|
+
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
|
|
1505
|
+
*/
|
|
1506
|
+
await this.loadMarkets();
|
|
1507
|
+
const response = await this.privateGetV3Balances(params);
|
|
1508
|
+
//
|
|
1509
|
+
// {
|
|
1510
|
+
// "success": true,
|
|
1511
|
+
// "data": [
|
|
1512
|
+
// {
|
|
1513
|
+
// "accountId": "106490",
|
|
1514
|
+
// "name": "main",
|
|
1515
|
+
// "balances": [
|
|
1516
|
+
// {
|
|
1517
|
+
// "asset": "OX",
|
|
1518
|
+
// "total": "-7.55145065000",
|
|
1519
|
+
// "available": "-71.16445065000",
|
|
1520
|
+
// "reserved": "0",
|
|
1521
|
+
// "lastUpdatedAt": "1715000448946"
|
|
1522
|
+
// },
|
|
1523
|
+
// {
|
|
1524
|
+
// "asset": "ETH",
|
|
1525
|
+
// "total": "0.01",
|
|
1526
|
+
// "available": "0.01",
|
|
1527
|
+
// "reserved": "0",
|
|
1528
|
+
// "lastUpdatedAt": "1714914512750"
|
|
1529
|
+
// },
|
|
1530
|
+
// ...
|
|
1531
|
+
// ]
|
|
1532
|
+
// },
|
|
1533
|
+
// ...
|
|
1534
|
+
// ]
|
|
1535
|
+
// }
|
|
1536
|
+
//
|
|
1537
|
+
const data = this.safeList(response, 'data', []);
|
|
1538
|
+
let balance = data[0];
|
|
1539
|
+
const subAcc = this.safeString(params, 'subAcc');
|
|
1540
|
+
if (subAcc !== undefined) {
|
|
1541
|
+
for (let i = 0; i < data.length; i++) {
|
|
1542
|
+
const b = data[i];
|
|
1543
|
+
const name = this.safeString(b, 'name');
|
|
1544
|
+
if (name === subAcc) {
|
|
1545
|
+
balance = b;
|
|
1546
|
+
break;
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
return this.parseBalance(balance);
|
|
1551
|
+
}
|
|
1552
|
+
parseBalance(balance) {
|
|
1553
|
+
//
|
|
1554
|
+
// {
|
|
1555
|
+
// "accountId": "106490",
|
|
1556
|
+
// "name": "main",
|
|
1557
|
+
// "balances": [
|
|
1558
|
+
// {
|
|
1559
|
+
// "asset": "OX",
|
|
1560
|
+
// "total": "-7.55145065000",
|
|
1561
|
+
// "available": "-71.16445065000",
|
|
1562
|
+
// "reserved": "0",
|
|
1563
|
+
// "lastUpdatedAt": "1715000448946"
|
|
1564
|
+
// },
|
|
1565
|
+
// {
|
|
1566
|
+
// "asset": "ETH",
|
|
1567
|
+
// "total": "0.01",
|
|
1568
|
+
// "available": "0.01",
|
|
1569
|
+
// "reserved": "0",
|
|
1570
|
+
// "lastUpdatedAt": "1714914512750"
|
|
1571
|
+
// },
|
|
1572
|
+
// ...
|
|
1573
|
+
// ]
|
|
1574
|
+
// }
|
|
1575
|
+
//
|
|
1576
|
+
const result = {
|
|
1577
|
+
'info': balance,
|
|
1578
|
+
};
|
|
1579
|
+
const balances = this.safeList(balance, 'balances', []);
|
|
1580
|
+
for (let i = 0; i < balances.length; i++) {
|
|
1581
|
+
const balanceEntry = balances[i];
|
|
1582
|
+
const currencyId = this.safeString(balanceEntry, 'asset');
|
|
1583
|
+
const code = this.safeCurrencyCode(currencyId);
|
|
1584
|
+
const account = this.account();
|
|
1585
|
+
account['total'] = this.safeString(balanceEntry, 'total');
|
|
1586
|
+
account['free'] = this.safeString(balanceEntry, 'available');
|
|
1587
|
+
account['used'] = this.safeString(balanceEntry, 'reserved');
|
|
1588
|
+
result[code] = account;
|
|
1589
|
+
}
|
|
1590
|
+
return this.safeBalance(result);
|
|
1591
|
+
}
|
|
1592
|
+
async fetchAccounts(params = {}) {
|
|
1593
|
+
/**
|
|
1594
|
+
* @method
|
|
1595
|
+
* @name oxfun#fetchAccounts
|
|
1596
|
+
* @description fetch subaccounts associated with a profile
|
|
1597
|
+
* @see https://docs.ox.fun/?json#get-v3-account-names
|
|
1598
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1599
|
+
* @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/#/?id=account-structure} indexed by the account type
|
|
1600
|
+
*/
|
|
1601
|
+
await this.loadMarkets();
|
|
1602
|
+
// this endpoint can only be called using API keys paired with the parent account! Returns all active subaccounts.
|
|
1603
|
+
const response = await this.privateGetV3AccountNames(params);
|
|
1604
|
+
//
|
|
1605
|
+
// {
|
|
1606
|
+
// "success": true,
|
|
1607
|
+
// "data": [
|
|
1608
|
+
// {
|
|
1609
|
+
// "accountId": "106526",
|
|
1610
|
+
// "name": "testSubAccount"
|
|
1611
|
+
// },
|
|
1612
|
+
// ...
|
|
1613
|
+
// ]
|
|
1614
|
+
// }
|
|
1615
|
+
//
|
|
1616
|
+
const data = this.safeList(response, 'data', []);
|
|
1617
|
+
return this.parseAccounts(data, params);
|
|
1618
|
+
}
|
|
1619
|
+
parseAccount(account) {
|
|
1620
|
+
//
|
|
1621
|
+
// {
|
|
1622
|
+
// "accountId": "106526",
|
|
1623
|
+
// "name": "testSubAccount"
|
|
1624
|
+
// },
|
|
1625
|
+
//
|
|
1626
|
+
return {
|
|
1627
|
+
'id': this.safeString(account, 'accountId'),
|
|
1628
|
+
'type': undefined,
|
|
1629
|
+
'code': undefined,
|
|
1630
|
+
'info': account,
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
async transfer(code, amount, fromAccount, toAccount, params = {}) {
|
|
1634
|
+
/**
|
|
1635
|
+
* @method
|
|
1636
|
+
* @name oxfun#transfer
|
|
1637
|
+
* @description transfer currency internally between wallets on the same account
|
|
1638
|
+
* @see https://docs.ox.fun/?json#post-v3-transfer
|
|
1639
|
+
* @param {string} code unified currency code
|
|
1640
|
+
* @param {float} amount amount to transfer
|
|
1641
|
+
* @param {string} fromAccount account id to transfer from
|
|
1642
|
+
* @param {string} toAccount account id to transfer to
|
|
1643
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1644
|
+
* @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure}
|
|
1645
|
+
*/
|
|
1646
|
+
// transferring funds between sub-accounts is restricted to API keys linked to the parent account.
|
|
1647
|
+
await this.loadMarkets();
|
|
1648
|
+
const currency = this.currency(code);
|
|
1649
|
+
const request = {
|
|
1650
|
+
'asset': currency['id'],
|
|
1651
|
+
'quantity': this.currencyToPrecision(code, amount),
|
|
1652
|
+
'fromAccount': fromAccount,
|
|
1653
|
+
'toAccount': toAccount,
|
|
1654
|
+
};
|
|
1655
|
+
const response = await this.privatePostV3Transfer(this.extend(request, params));
|
|
1656
|
+
//
|
|
1657
|
+
// {
|
|
1658
|
+
// timestamp: 1715430036267,
|
|
1659
|
+
// datetime: '2024-05-11T12:20:36.267Z',
|
|
1660
|
+
// currency: 'OX',
|
|
1661
|
+
// amount: 10,
|
|
1662
|
+
// fromAccount: '106464',
|
|
1663
|
+
// toAccount: '106570',
|
|
1664
|
+
// info: {
|
|
1665
|
+
// asset: 'OX',
|
|
1666
|
+
// quantity: '10',
|
|
1667
|
+
// fromAccount: '106464',
|
|
1668
|
+
// toAccount: '106570',
|
|
1669
|
+
// transferredAt: '1715430036267'
|
|
1670
|
+
// }
|
|
1671
|
+
// }
|
|
1672
|
+
//
|
|
1673
|
+
const data = this.safeDict(response, 'data', {});
|
|
1674
|
+
return this.parseTransfer(data, currency);
|
|
1675
|
+
}
|
|
1676
|
+
async fetchTransfers(code = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1677
|
+
/**
|
|
1678
|
+
* @method
|
|
1679
|
+
* @name oxfun#fetchTransfers
|
|
1680
|
+
* @description fetch a history of internal transfers made on an account
|
|
1681
|
+
* @see https://docs.ox.fun/?json#get-v3-transfer
|
|
1682
|
+
* @param {string} code unified currency code of the currency transferred
|
|
1683
|
+
* @param {int} [since] the earliest time in ms to fetch transfers for (default 24 hours ago)
|
|
1684
|
+
* @param {int} [limit] the maximum number of transfer structures to retrieve (default 50, max 200)
|
|
1685
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1686
|
+
* @param {int} [params.until] the latest time in ms to fetch transfers for (default time now)
|
|
1687
|
+
* @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/#/?id=transfer-structure}
|
|
1688
|
+
*/
|
|
1689
|
+
// API keys linked to the parent account can get all account transfers, while API keys linked to a sub-account can only see transfers where the sub-account is either the "fromAccount" or "toAccount"
|
|
1690
|
+
await this.loadMarkets();
|
|
1691
|
+
const request = {};
|
|
1692
|
+
let currency = undefined;
|
|
1693
|
+
if (code !== undefined) {
|
|
1694
|
+
currency = this.currency(code);
|
|
1695
|
+
request['asset'] = currency['id'];
|
|
1696
|
+
}
|
|
1697
|
+
if (since !== undefined) {
|
|
1698
|
+
request['startTime'] = since; // startTime and endTime must be within 7 days of each other
|
|
1699
|
+
}
|
|
1700
|
+
if (limit !== undefined) {
|
|
1701
|
+
request['limit'] = limit;
|
|
1702
|
+
}
|
|
1703
|
+
const until = this.safeInteger(params, 'until');
|
|
1704
|
+
if (until !== undefined) {
|
|
1705
|
+
request['endTime'] = until;
|
|
1706
|
+
params = this.omit(params, 'until');
|
|
1707
|
+
}
|
|
1708
|
+
else if (since !== undefined) {
|
|
1709
|
+
request['endTime'] = this.sum(since, 7 * 24 * 60 * 60 * 1000); // for the exchange not to throw an exception if since is younger than 7 days
|
|
1710
|
+
}
|
|
1711
|
+
const response = await this.privateGetV3Transfer(this.extend(request, params));
|
|
1712
|
+
//
|
|
1713
|
+
// {
|
|
1714
|
+
// "success": true,
|
|
1715
|
+
// "data": [
|
|
1716
|
+
// {
|
|
1717
|
+
// "asset": "USDT",
|
|
1718
|
+
// "quantity": "5",
|
|
1719
|
+
// "fromAccount": "106490",
|
|
1720
|
+
// "toAccount": "106526",
|
|
1721
|
+
// "id": "966706320886267905",
|
|
1722
|
+
// "status": "COMPLETED",
|
|
1723
|
+
// "transferredAt": "1715085756708"
|
|
1724
|
+
// },
|
|
1725
|
+
// ...
|
|
1726
|
+
// ]
|
|
1727
|
+
// }
|
|
1728
|
+
//
|
|
1729
|
+
const data = this.safeList(response, 'data', []);
|
|
1730
|
+
return this.parseTransfers(data, currency, since, limit);
|
|
1731
|
+
}
|
|
1732
|
+
parseTransfer(transfer, currency = undefined) {
|
|
1733
|
+
//
|
|
1734
|
+
// fetchTransfers
|
|
1735
|
+
//
|
|
1736
|
+
// {
|
|
1737
|
+
// "asset": "USDT",
|
|
1738
|
+
// "quantity": "5",
|
|
1739
|
+
// "fromAccount": "106490",
|
|
1740
|
+
// "toAccount": "106526",
|
|
1741
|
+
// "id": "966706320886267905",
|
|
1742
|
+
// "status": "COMPLETED",
|
|
1743
|
+
// "transferredAt": "1715085756708"
|
|
1744
|
+
// }
|
|
1745
|
+
//
|
|
1746
|
+
const timestamp = this.safeInteger(transfer, 'transferredAt');
|
|
1747
|
+
const currencyId = this.safeString(transfer, 'asset');
|
|
1748
|
+
return {
|
|
1749
|
+
'id': this.safeString(transfer, 'id'),
|
|
1750
|
+
'timestamp': timestamp,
|
|
1751
|
+
'datetime': this.iso8601(timestamp),
|
|
1752
|
+
'currency': this.safeCurrencyCode(currencyId, currency),
|
|
1753
|
+
'amount': this.safeNumber(transfer, 'quantity'),
|
|
1754
|
+
'fromAccount': this.safeString(transfer, 'fromAccount'),
|
|
1755
|
+
'toAccount': this.safeString(transfer, 'toAccount'),
|
|
1756
|
+
'status': this.parseTransferStatus(this.safeString(transfer, 'status')),
|
|
1757
|
+
'info': transfer,
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1760
|
+
parseTransferStatus(status) {
|
|
1761
|
+
const statuses = {
|
|
1762
|
+
'COMPLETED': 'ok',
|
|
1763
|
+
};
|
|
1764
|
+
return this.safeString(statuses, status, status);
|
|
1765
|
+
}
|
|
1766
|
+
async fetchDepositAddress(code, params = {}) {
|
|
1767
|
+
/**
|
|
1768
|
+
* @method
|
|
1769
|
+
* @name oxfun#fetchDepositAddress
|
|
1770
|
+
* @description fetch the deposit address for a currency associated with this account
|
|
1771
|
+
* @see https://docs.ox.fun/?json#get-v3-deposit-addresses
|
|
1772
|
+
* @param {string} code unified currency code
|
|
1773
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1774
|
+
* @param {string} [params.network] network for fetch deposit address
|
|
1775
|
+
* @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure}
|
|
1776
|
+
*/
|
|
1777
|
+
const networkCode = this.safeString(params, 'network');
|
|
1778
|
+
const networkId = this.networkCodeToId(networkCode, code);
|
|
1779
|
+
if (networkId === undefined) {
|
|
1780
|
+
throw new errors.BadRequest(this.id + ' fetchDepositAddress() require network parameter');
|
|
1781
|
+
}
|
|
1782
|
+
await this.loadMarkets();
|
|
1783
|
+
const currency = this.currency(code);
|
|
1784
|
+
const request = {
|
|
1785
|
+
'asset': currency['id'],
|
|
1786
|
+
'network': networkId,
|
|
1787
|
+
};
|
|
1788
|
+
params = this.omit(params, 'network');
|
|
1789
|
+
const response = await this.privateGetV3DepositAddresses(this.extend(request, params));
|
|
1790
|
+
//
|
|
1791
|
+
// {"success":true,"data":{"address":"0x998dEc76151FB723963Bd8AFD517687b38D33dE8"}}
|
|
1792
|
+
//
|
|
1793
|
+
const data = this.safeDict(response, 'data', {});
|
|
1794
|
+
return this.parseDepositAddress(data, currency);
|
|
1795
|
+
}
|
|
1796
|
+
parseDepositAddress(depositAddress, currency = undefined) {
|
|
1797
|
+
//
|
|
1798
|
+
// {"address":"0x998dEc76151FB723963Bd8AFD517687b38D33dE8"}
|
|
1799
|
+
//
|
|
1800
|
+
const address = this.safeString(depositAddress, 'address');
|
|
1801
|
+
this.checkAddress(address);
|
|
1802
|
+
return {
|
|
1803
|
+
'currency': currency['code'],
|
|
1804
|
+
'address': address,
|
|
1805
|
+
'tag': undefined,
|
|
1806
|
+
'network': undefined,
|
|
1807
|
+
'info': depositAddress,
|
|
1808
|
+
};
|
|
1809
|
+
}
|
|
1810
|
+
async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1811
|
+
/**
|
|
1812
|
+
* @method
|
|
1813
|
+
* @name oxfun#fetchDeposits
|
|
1814
|
+
* @description fetch all deposits made to an account
|
|
1815
|
+
* @see https://docs.ox.fun/?json#get-v3-deposit
|
|
1816
|
+
* @param {string} code unified currency code of the currency transferred
|
|
1817
|
+
* @param {int} [since] the earliest time in ms to fetch transfers for (default 24 hours ago)
|
|
1818
|
+
* @param {int} [limit] the maximum number of transfer structures to retrieve (default 50, max 200)
|
|
1819
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1820
|
+
* @param {int} [params.until] the latest time in ms to fetch transfers for (default time now)
|
|
1821
|
+
* @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/#/?id=transfer-structure}
|
|
1822
|
+
*/
|
|
1823
|
+
await this.loadMarkets();
|
|
1824
|
+
const request = {};
|
|
1825
|
+
let currency = undefined;
|
|
1826
|
+
if (code !== undefined) {
|
|
1827
|
+
currency = this.currency(code);
|
|
1828
|
+
request['asset'] = currency['id'];
|
|
1829
|
+
}
|
|
1830
|
+
if (since !== undefined) {
|
|
1831
|
+
request['startTime'] = since; // startTime and endTime must be within 7 days of each other
|
|
1832
|
+
}
|
|
1833
|
+
if (limit !== undefined) {
|
|
1834
|
+
request['limit'] = limit;
|
|
1835
|
+
}
|
|
1836
|
+
const until = this.safeInteger(params, 'until');
|
|
1837
|
+
if (until !== undefined) {
|
|
1838
|
+
request['endTime'] = until;
|
|
1839
|
+
params = this.omit(params, 'until');
|
|
1840
|
+
}
|
|
1841
|
+
const response = await this.privateGetV3Deposit(this.extend(request, params));
|
|
1842
|
+
//
|
|
1843
|
+
// {
|
|
1844
|
+
// "success": true,
|
|
1845
|
+
// "data": [
|
|
1846
|
+
// {
|
|
1847
|
+
// "asset":"USDC",
|
|
1848
|
+
// "network":"Ethereum",
|
|
1849
|
+
// "address": "0x998dEc76151FB723963Bd8AFD517687b38D33dE8",
|
|
1850
|
+
// "quantity":"50",
|
|
1851
|
+
// "id":"5914",
|
|
1852
|
+
// "status": "COMPLETED",
|
|
1853
|
+
// "txId":"0xf5e79663830a0c6f94d46638dcfbc134566c12facf1832396f81ecb55d3c75dc",
|
|
1854
|
+
// "creditedAt":"1714821645154"
|
|
1855
|
+
// }
|
|
1856
|
+
// ]
|
|
1857
|
+
// }
|
|
1858
|
+
//
|
|
1859
|
+
const data = this.safeList(response, 'data', []);
|
|
1860
|
+
for (let i = 0; i < data.length; i++) {
|
|
1861
|
+
data[i]['type'] = 'deposit';
|
|
1862
|
+
}
|
|
1863
|
+
return this.parseTransactions(data, currency, since, limit);
|
|
1864
|
+
}
|
|
1865
|
+
async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1866
|
+
/**
|
|
1867
|
+
* @method
|
|
1868
|
+
* @name oxfun#fetchWithdrawals
|
|
1869
|
+
* @description fetch all withdrawals made from an account
|
|
1870
|
+
* @see https://docs.ox.fun/?json#get-v3-withdrawal
|
|
1871
|
+
* @param {string} code unified currency code of the currency transferred
|
|
1872
|
+
* @param {int} [since] the earliest time in ms to fetch transfers for (default 24 hours ago)
|
|
1873
|
+
* @param {int} [limit] the maximum number of transfer structures to retrieve (default 50, max 200)
|
|
1874
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1875
|
+
* @param {int} [params.until] the latest time in ms to fetch transfers for (default time now)
|
|
1876
|
+
* @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
|
|
1877
|
+
*/
|
|
1878
|
+
await this.loadMarkets();
|
|
1879
|
+
const request = {};
|
|
1880
|
+
let currency = undefined;
|
|
1881
|
+
if (code !== undefined) {
|
|
1882
|
+
currency = this.currency(code);
|
|
1883
|
+
request['asset'] = currency['id'];
|
|
1884
|
+
}
|
|
1885
|
+
if (since !== undefined) {
|
|
1886
|
+
request['startTime'] = since; // startTime and endTime must be within 7 days of each other
|
|
1887
|
+
}
|
|
1888
|
+
if (limit !== undefined) {
|
|
1889
|
+
request['limit'] = limit;
|
|
1890
|
+
}
|
|
1891
|
+
const until = this.safeInteger(params, 'until');
|
|
1892
|
+
if (until !== undefined) {
|
|
1893
|
+
request['endTime'] = until;
|
|
1894
|
+
params = this.omit(params, 'until');
|
|
1895
|
+
}
|
|
1896
|
+
const response = await this.privateGetV3Withdrawal(this.extend(request, params));
|
|
1897
|
+
//
|
|
1898
|
+
// {
|
|
1899
|
+
// success: true,
|
|
1900
|
+
// data: [
|
|
1901
|
+
// {
|
|
1902
|
+
// id: '968163212989431811',
|
|
1903
|
+
// asset: 'OX',
|
|
1904
|
+
// network: 'Arbitrum',
|
|
1905
|
+
// address: '0x90fc1fB49a4ED8f485dd02A2a1Cf576897f6Bfc9',
|
|
1906
|
+
// quantity: '11.7444',
|
|
1907
|
+
// fee: '1.744400000',
|
|
1908
|
+
// status: 'COMPLETED',
|
|
1909
|
+
// txId: '0xe96b2d128b737fdbca927edf355cff42202e65b0fb960e64ffb9bd68c121f69f',
|
|
1910
|
+
// requestedAt: '1715530365450',
|
|
1911
|
+
// completedAt: '1715530527000'
|
|
1912
|
+
// }
|
|
1913
|
+
// ]
|
|
1914
|
+
// }
|
|
1915
|
+
//
|
|
1916
|
+
const data = this.safeList(response, 'data', []);
|
|
1917
|
+
for (let i = 0; i < data.length; i++) {
|
|
1918
|
+
data[i]['type'] = 'withdrawal';
|
|
1919
|
+
}
|
|
1920
|
+
return this.parseTransactions(data, currency, since, limit);
|
|
1921
|
+
}
|
|
1922
|
+
parseTransactions(transactions, currency = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1923
|
+
let result = [];
|
|
1924
|
+
for (let i = 0; i < transactions.length; i++) {
|
|
1925
|
+
transactions[i] = this.extend(transactions[i], params);
|
|
1926
|
+
const transaction = this.parseTransaction(transactions[i], currency);
|
|
1927
|
+
result.push(transaction);
|
|
1928
|
+
}
|
|
1929
|
+
result = this.sortBy(result, 'timestamp');
|
|
1930
|
+
const code = (currency !== undefined) ? currency['code'] : undefined;
|
|
1931
|
+
return this.filterByCurrencySinceLimit(result, code, since, limit);
|
|
1932
|
+
}
|
|
1933
|
+
parseTransaction(transaction, currency = undefined) {
|
|
1934
|
+
//
|
|
1935
|
+
// fetchDeposits
|
|
1936
|
+
// {
|
|
1937
|
+
// "asset":"USDC",
|
|
1938
|
+
// "network":"Ethereum",
|
|
1939
|
+
// "address": "0x998dEc76151FB723963Bd8AFD517687b38D33dE8",
|
|
1940
|
+
// "quantity":"50",
|
|
1941
|
+
// "id":"5914",
|
|
1942
|
+
// "status": "COMPLETED",
|
|
1943
|
+
// "txId":"0xf5e79663830a0c6f94d46638dcfbc134566c12facf1832396f81ecb55d3c75dc",
|
|
1944
|
+
// "creditedAt":"1714821645154"
|
|
1945
|
+
// }
|
|
1946
|
+
//
|
|
1947
|
+
// fetchWithdrawals
|
|
1948
|
+
// {
|
|
1949
|
+
// id: '968163212989431811',
|
|
1950
|
+
// asset: 'OX',
|
|
1951
|
+
// network: 'Arbitrum',
|
|
1952
|
+
// address: '0x90fc1fB49a4ED8f485dd02A2a1Cf576897f6Bfc9',
|
|
1953
|
+
// quantity: '11.7444',
|
|
1954
|
+
// fee: '1.744400000',
|
|
1955
|
+
// status: 'COMPLETED',
|
|
1956
|
+
// txId: '0xe96b2d128b737fdbca927edf355cff42202e65b0fb960e64ffb9bd68c121f69f',
|
|
1957
|
+
// requestedAt: '1715530365450',
|
|
1958
|
+
// completedAt: '1715530527000'
|
|
1959
|
+
// }
|
|
1960
|
+
//
|
|
1961
|
+
// withdraw
|
|
1962
|
+
// {
|
|
1963
|
+
// "id": "968364664449302529",
|
|
1964
|
+
// "asset": "OX",
|
|
1965
|
+
// "network": "Arbitrum",
|
|
1966
|
+
// "address": "0x90fc1fB49a4ED8f485dd02A2a1Cf576897f6Bfc9",
|
|
1967
|
+
// "quantity": "10",
|
|
1968
|
+
// "externalFee": false,
|
|
1969
|
+
// "fee": "1.6728",
|
|
1970
|
+
// "status": "PENDING",
|
|
1971
|
+
// "requestedAt": "1715591843616"
|
|
1972
|
+
// }
|
|
1973
|
+
//
|
|
1974
|
+
const id = this.safeString(transaction, 'id');
|
|
1975
|
+
const type = this.safeString(transaction, 'type');
|
|
1976
|
+
transaction = this.omit(transaction, 'type');
|
|
1977
|
+
let address = undefined;
|
|
1978
|
+
let addressTo = undefined;
|
|
1979
|
+
let status = undefined;
|
|
1980
|
+
if (type === 'deposit') {
|
|
1981
|
+
address = this.safeString(transaction, 'address');
|
|
1982
|
+
status = this.parseDepositStatus(this.safeString(transaction, 'status'));
|
|
1983
|
+
}
|
|
1984
|
+
else if (type === 'withdrawal') {
|
|
1985
|
+
addressTo = this.safeString(transaction, 'address');
|
|
1986
|
+
status = this.parseWithdrawalStatus(this.safeString(transaction, 'status'));
|
|
1987
|
+
}
|
|
1988
|
+
const txid = this.safeString(transaction, 'txId');
|
|
1989
|
+
const currencyId = this.safeString(transaction, 'asset');
|
|
1990
|
+
const code = this.safeCurrencyCode(currencyId, currency);
|
|
1991
|
+
const network = this.safeString(transaction, 'network');
|
|
1992
|
+
const networkCode = this.networkIdToCode(network);
|
|
1993
|
+
const timestamp = this.safeInteger2(transaction, 'creditedAt', 'requestedAt');
|
|
1994
|
+
const amount = this.safeNumber(transaction, 'quantity');
|
|
1995
|
+
const feeCost = this.safeNumber(transaction, 'fee');
|
|
1996
|
+
let fee = undefined;
|
|
1997
|
+
if (feeCost !== undefined) {
|
|
1998
|
+
fee = {
|
|
1999
|
+
'cost': feeCost,
|
|
2000
|
+
'currency': code,
|
|
2001
|
+
};
|
|
2002
|
+
}
|
|
2003
|
+
return {
|
|
2004
|
+
'info': transaction,
|
|
2005
|
+
'id': id,
|
|
2006
|
+
'txid': txid,
|
|
2007
|
+
'timestamp': timestamp,
|
|
2008
|
+
'datetime': this.iso8601(timestamp),
|
|
2009
|
+
'network': networkCode,
|
|
2010
|
+
'address': address,
|
|
2011
|
+
'addressTo': addressTo,
|
|
2012
|
+
'addressFrom': undefined,
|
|
2013
|
+
'tag': undefined,
|
|
2014
|
+
'tagTo': undefined,
|
|
2015
|
+
'tagFrom': undefined,
|
|
2016
|
+
'type': type,
|
|
2017
|
+
'amount': amount,
|
|
2018
|
+
'currency': code,
|
|
2019
|
+
'status': status,
|
|
2020
|
+
'updated': undefined,
|
|
2021
|
+
'internal': undefined,
|
|
2022
|
+
'comment': undefined,
|
|
2023
|
+
'fee': fee,
|
|
2024
|
+
};
|
|
2025
|
+
}
|
|
2026
|
+
parseDepositStatus(status) {
|
|
2027
|
+
const statuses = {
|
|
2028
|
+
'COMPLETED': 'ok',
|
|
2029
|
+
};
|
|
2030
|
+
return this.safeString(statuses, status, status);
|
|
2031
|
+
}
|
|
2032
|
+
parseWithdrawalStatus(status) {
|
|
2033
|
+
const statuses = {
|
|
2034
|
+
'COMPLETED': 'ok',
|
|
2035
|
+
'PROCESSING': 'pending',
|
|
2036
|
+
'IN SWEEPING': 'pending',
|
|
2037
|
+
'PENDING': 'pending',
|
|
2038
|
+
'ON HOLD': 'pending',
|
|
2039
|
+
'CANCELED': 'canceled',
|
|
2040
|
+
'FAILED': 'failed',
|
|
2041
|
+
};
|
|
2042
|
+
return this.safeString(statuses, status, status);
|
|
2043
|
+
}
|
|
2044
|
+
async withdraw(code, amount, address, tag = undefined, params = {}) {
|
|
2045
|
+
/**
|
|
2046
|
+
* @method
|
|
2047
|
+
* @name bitflex#withdraw
|
|
2048
|
+
* @description make a withdrawal
|
|
2049
|
+
* @see https://docs.bitflex.com/spot#withdraw
|
|
2050
|
+
* @param {string} code unified currency code
|
|
2051
|
+
* @param {float} amount the amount to withdraw
|
|
2052
|
+
* @param {string} address the address to withdraw to
|
|
2053
|
+
* @param {string} tag
|
|
2054
|
+
* @param {string} [params.network] network for withdraw
|
|
2055
|
+
* @param {bool} [params.externalFee] if false, then the fee is taken from the quantity, also with the burn fee for asset SOLO
|
|
2056
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2057
|
+
*
|
|
2058
|
+
* EXCHANGE SPECIFIC PARAMETERS
|
|
2059
|
+
* @param {string} [params.tfaType] GOOGLE, or AUTHY_SECRET, or YUBIKEY, for 2FA
|
|
2060
|
+
* @param {string} [params.code] 2FA code
|
|
2061
|
+
* @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
|
|
2062
|
+
*/
|
|
2063
|
+
[tag, params] = this.handleWithdrawTagAndParams(tag, params);
|
|
2064
|
+
await this.loadMarkets();
|
|
2065
|
+
const currency = this.currency(code);
|
|
2066
|
+
const stringAmount = this.currencyToPrecision(code, amount);
|
|
2067
|
+
const request = {
|
|
2068
|
+
'asset': currency['id'],
|
|
2069
|
+
'address': address,
|
|
2070
|
+
'quantity': stringAmount,
|
|
2071
|
+
};
|
|
2072
|
+
if (tag !== undefined) {
|
|
2073
|
+
request['memo'] = tag;
|
|
2074
|
+
}
|
|
2075
|
+
let networkCode = undefined;
|
|
2076
|
+
[networkCode, params] = this.handleNetworkCodeAndParams(params);
|
|
2077
|
+
if (networkCode !== undefined) {
|
|
2078
|
+
request['network'] = this.networkCodeToId(networkCode);
|
|
2079
|
+
}
|
|
2080
|
+
request['externalFee'] = false;
|
|
2081
|
+
const response = await this.privatePostV3Withdrawal(this.extend(request, params));
|
|
2082
|
+
//
|
|
2083
|
+
// {
|
|
2084
|
+
// "success": true,
|
|
2085
|
+
// "data": {
|
|
2086
|
+
// "id": "968364664449302529",
|
|
2087
|
+
// "asset": "OX",
|
|
2088
|
+
// "network": "Arbitrum",
|
|
2089
|
+
// "address": "0x90fc1fB49a4ED8f485dd02A2a1Cf576897f6Bfc9",
|
|
2090
|
+
// "quantity": "10",
|
|
2091
|
+
// "externalFee": false,
|
|
2092
|
+
// "fee": "1.6728",
|
|
2093
|
+
// "status": "PENDING",
|
|
2094
|
+
// "requestedAt": "1715591843616"
|
|
2095
|
+
// }
|
|
2096
|
+
// }
|
|
2097
|
+
//
|
|
2098
|
+
const data = this.safeDict(response, 'data', {});
|
|
2099
|
+
data['type'] = 'withdrawal';
|
|
2100
|
+
return this.parseTransaction(data, currency);
|
|
2101
|
+
}
|
|
2102
|
+
async fetchPositions(symbols = undefined, params = {}) {
|
|
2103
|
+
/**
|
|
2104
|
+
* @method
|
|
2105
|
+
* @name oxfun#fetchPositions
|
|
2106
|
+
* @description fetch all open positions
|
|
2107
|
+
* @see https://docs.ox.fun/?json#get-v3-positions
|
|
2108
|
+
* @param {string[]|undefined} symbols list of unified market symbols
|
|
2109
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2110
|
+
* @param {boolean} [params.subAcc]
|
|
2111
|
+
* @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
|
|
2112
|
+
*/
|
|
2113
|
+
// Calling this endpoint using an API key pair linked to the parent account with the parameter "subAcc"
|
|
2114
|
+
// allows the caller to include positions of additional sub-accounts in the response.
|
|
2115
|
+
// This feature does not work when using API key pairs linked to a sub-account
|
|
2116
|
+
await this.loadMarkets();
|
|
2117
|
+
symbols = this.marketSymbols(symbols);
|
|
2118
|
+
const response = await this.privateGetV3Positions(params);
|
|
2119
|
+
//
|
|
2120
|
+
// {
|
|
2121
|
+
// "success": true,
|
|
2122
|
+
// "data": [
|
|
2123
|
+
// {
|
|
2124
|
+
// "accountId": "106490",
|
|
2125
|
+
// "name": "main",
|
|
2126
|
+
// "positions": [
|
|
2127
|
+
// {
|
|
2128
|
+
// "marketCode": "BTC-USD-SWAP-LIN",
|
|
2129
|
+
// "baseAsset": "BTC",
|
|
2130
|
+
// "counterAsset": "USD",
|
|
2131
|
+
// "position": "0.00010",
|
|
2132
|
+
// "entryPrice": "64300.0",
|
|
2133
|
+
// "markPrice": "63278",
|
|
2134
|
+
// "positionPnl": "-10.1900",
|
|
2135
|
+
// "estLiquidationPrice": "0",
|
|
2136
|
+
// "lastUpdatedAt": "1714915841448"
|
|
2137
|
+
// },
|
|
2138
|
+
// ...
|
|
2139
|
+
// ]
|
|
2140
|
+
// },
|
|
2141
|
+
// {
|
|
2142
|
+
// "accountId": "106526",
|
|
2143
|
+
// "name": "testSubAccount",
|
|
2144
|
+
// "positions": [
|
|
2145
|
+
// {
|
|
2146
|
+
// "marketCode": "ETH-USD-SWAP-LIN",
|
|
2147
|
+
// "baseAsset": "ETH",
|
|
2148
|
+
// "counterAsset": "USD",
|
|
2149
|
+
// "position": "0.001",
|
|
2150
|
+
// "entryPrice": "3080.5",
|
|
2151
|
+
// "markPrice": "3062.0",
|
|
2152
|
+
// "positionPnl": "-1.8500",
|
|
2153
|
+
// "estLiquidationPrice": "0",
|
|
2154
|
+
// "lastUpdatedAt": "1715089678013"
|
|
2155
|
+
// },
|
|
2156
|
+
// ...
|
|
2157
|
+
// ]
|
|
2158
|
+
// }
|
|
2159
|
+
// ]
|
|
2160
|
+
// }
|
|
2161
|
+
//
|
|
2162
|
+
const data = this.safeList(response, 'data', []);
|
|
2163
|
+
let allPositions = [];
|
|
2164
|
+
for (let i = 0; i < data.length; i++) {
|
|
2165
|
+
const account = data[i];
|
|
2166
|
+
const positions = this.safeList(account, 'positions', []);
|
|
2167
|
+
allPositions = this.arrayConcat(allPositions, positions);
|
|
2168
|
+
}
|
|
2169
|
+
return this.parsePositions(allPositions, symbols);
|
|
2170
|
+
}
|
|
2171
|
+
parsePosition(position, market = undefined) {
|
|
2172
|
+
//
|
|
2173
|
+
// {
|
|
2174
|
+
// "marketCode": "ETH-USD-SWAP-LIN",
|
|
2175
|
+
// "baseAsset": "ETH",
|
|
2176
|
+
// "counterAsset": "USD",
|
|
2177
|
+
// "position": "0.001",
|
|
2178
|
+
// "entryPrice": "3080.5",
|
|
2179
|
+
// "markPrice": "3062.0",
|
|
2180
|
+
// "positionPnl": "-1.8500",
|
|
2181
|
+
// "estLiquidationPrice": "0",
|
|
2182
|
+
// "lastUpdatedAt": "1715089678013"
|
|
2183
|
+
// }
|
|
2184
|
+
//
|
|
2185
|
+
const marketId = this.safeString(position, 'marketCode');
|
|
2186
|
+
market = this.safeMarket(marketId, market);
|
|
2187
|
+
return this.safePosition({
|
|
2188
|
+
'info': position,
|
|
2189
|
+
'id': undefined,
|
|
2190
|
+
'symbol': market['symbol'],
|
|
2191
|
+
'notional': undefined,
|
|
2192
|
+
'marginMode': 'cross',
|
|
2193
|
+
'liquidationPrice': this.safeNumber(position, 'estLiquidationPrice'),
|
|
2194
|
+
'entryPrice': this.safeNumber(position, 'entryPrice'),
|
|
2195
|
+
'unrealizedPnl': this.safeNumber(position, 'positionPnl'),
|
|
2196
|
+
'realizedPnl': undefined,
|
|
2197
|
+
'percentage': undefined,
|
|
2198
|
+
'contracts': this.safeNumber(position, 'position'),
|
|
2199
|
+
'contractSize': undefined,
|
|
2200
|
+
'markPrice': this.safeNumber(position, 'markPrice'),
|
|
2201
|
+
'lastPrice': undefined,
|
|
2202
|
+
'side': undefined,
|
|
2203
|
+
'hedged': undefined,
|
|
2204
|
+
'timestamp': undefined,
|
|
2205
|
+
'datetime': undefined,
|
|
2206
|
+
'lastUpdateTimestamp': this.safeInteger(position, 'lastUpdatedAt'),
|
|
2207
|
+
'maintenanceMargin': undefined,
|
|
2208
|
+
'maintenanceMarginPercentage': undefined,
|
|
2209
|
+
'collateral': undefined,
|
|
2210
|
+
'initialMargin': undefined,
|
|
2211
|
+
'initialMarginPercentage': undefined,
|
|
2212
|
+
'leverage': undefined,
|
|
2213
|
+
'marginRatio': undefined,
|
|
2214
|
+
'stopLossPrice': undefined,
|
|
2215
|
+
'takeProfitPrice': undefined,
|
|
2216
|
+
});
|
|
2217
|
+
}
|
|
2218
|
+
async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
|
|
2219
|
+
/**
|
|
2220
|
+
* @method
|
|
2221
|
+
* @name oxfun#createOrder
|
|
2222
|
+
* @description create a trade order
|
|
2223
|
+
* @see https://docs.ox.fun/?json#post-v3-orders-place
|
|
2224
|
+
* @param {string} symbol unified symbol of the market to create an order in
|
|
2225
|
+
* @param {string} type 'market', 'limit', 'STOP_LIMIT' or 'STOP_MARKET'
|
|
2226
|
+
* @param {string} side 'buy' or 'sell'
|
|
2227
|
+
* @param {float} amount how much of currency you want to trade in units of base currency
|
|
2228
|
+
* @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
|
2229
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2230
|
+
* @param {int} [params.clientOrderId] a unique id for the order
|
|
2231
|
+
* @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.
|
|
2232
|
+
* @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.
|
|
2233
|
+
* @param {string} [params.responseType] FULL or ACK
|
|
2234
|
+
* @param {float} [params.cost] the quote quantity that can be used as an alternative for the amount for market buy orders
|
|
2235
|
+
* @param {float} [params.triggerPrice] The price at which a trigger order is triggered at
|
|
2236
|
+
* @param {float} [params.limitPrice] Limit price for the STOP_LIMIT order
|
|
2237
|
+
* @param {bool} [params.postOnly] if true, the order will only be posted if it will be a maker order
|
|
2238
|
+
* @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)
|
|
2239
|
+
* @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}
|
|
2240
|
+
* @param {string} [params.displayQuantity] for an iceberg order, pass both quantity and displayQuantity fields in the order request
|
|
2241
|
+
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
2242
|
+
*/
|
|
2243
|
+
await this.loadMarkets();
|
|
2244
|
+
const request = {
|
|
2245
|
+
'responseType': this.safeString(params, 'responseType', 'FULL'),
|
|
2246
|
+
'timestamp': this.safeInteger(params, 'timestamp', this.milliseconds()),
|
|
2247
|
+
};
|
|
2248
|
+
params = this.omit(params, ['responseType', 'timestamp']);
|
|
2249
|
+
const recvWindow = this.safeInteger(params, 'recvWindow');
|
|
2250
|
+
if (recvWindow !== undefined) {
|
|
2251
|
+
request['recvWindow'] = recvWindow;
|
|
2252
|
+
params = this.omit(params, 'recvWindow');
|
|
2253
|
+
}
|
|
2254
|
+
const orderRequest = this.createOrderRequest(symbol, type, side, amount, price, params);
|
|
2255
|
+
request['orders'] = [orderRequest];
|
|
2256
|
+
const response = await this.privatePostV3OrdersPlace(request);
|
|
2257
|
+
//
|
|
2258
|
+
// accepted market order responseType FULL
|
|
2259
|
+
// {
|
|
2260
|
+
// "success": true,
|
|
2261
|
+
// "data": [
|
|
2262
|
+
// {
|
|
2263
|
+
// "notice": "OrderMatched",
|
|
2264
|
+
// "accountId": "106490",
|
|
2265
|
+
// "orderId": "1000109901865",
|
|
2266
|
+
// "submitted": true,
|
|
2267
|
+
// "clientOrderId": "0",
|
|
2268
|
+
// "marketCode": "OX-USDT",
|
|
2269
|
+
// "status": "FILLED",
|
|
2270
|
+
// "side": "SELL",
|
|
2271
|
+
// "isTriggered": false,
|
|
2272
|
+
// "quantity": "150.0",
|
|
2273
|
+
// "amount": "0.0",
|
|
2274
|
+
// "remainQuantity": "0.0",
|
|
2275
|
+
// "matchId": "100017047880451399",
|
|
2276
|
+
// "matchPrice": "0.01465",
|
|
2277
|
+
// "matchQuantity": "150.0",
|
|
2278
|
+
// "feeInstrumentId": "USDT",
|
|
2279
|
+
// "fees": "0.0015382500",
|
|
2280
|
+
// "orderType": "MARKET",
|
|
2281
|
+
// "createdAt": "1715592472236",
|
|
2282
|
+
// "lastMatchedAt": "1715592472200",
|
|
2283
|
+
// "displayQuantity": "150.0"
|
|
2284
|
+
// }
|
|
2285
|
+
// ]
|
|
2286
|
+
// }
|
|
2287
|
+
//
|
|
2288
|
+
// accepted limit order responseType FULL
|
|
2289
|
+
// {
|
|
2290
|
+
// "success": true,
|
|
2291
|
+
// "data": [
|
|
2292
|
+
// {
|
|
2293
|
+
// "notice": "OrderOpened",
|
|
2294
|
+
// "accountId": "106490",
|
|
2295
|
+
// "orderId": "1000111482406",
|
|
2296
|
+
// "submitted": true,
|
|
2297
|
+
// "clientOrderId": "0",
|
|
2298
|
+
// "marketCode": "ETH-USD-SWAP-LIN",
|
|
2299
|
+
// "status": "OPEN",
|
|
2300
|
+
// "side": "SELL",
|
|
2301
|
+
// "price": "4000.0",
|
|
2302
|
+
// "isTriggered": false,
|
|
2303
|
+
// "quantity": "0.01",
|
|
2304
|
+
// "amount": "0.0",
|
|
2305
|
+
// "orderType": "LIMIT",
|
|
2306
|
+
// "timeInForce": "GTC",
|
|
2307
|
+
// "createdAt": "1715763507682",
|
|
2308
|
+
// "displayQuantity": "0.01"
|
|
2309
|
+
// }
|
|
2310
|
+
// ]
|
|
2311
|
+
// }
|
|
2312
|
+
//
|
|
2313
|
+
// accepted order responseType ACK
|
|
2314
|
+
// {
|
|
2315
|
+
// "success": true,
|
|
2316
|
+
// "data": [
|
|
2317
|
+
// {
|
|
2318
|
+
// "accountId": "106490",
|
|
2319
|
+
// "orderId": "1000109892193",
|
|
2320
|
+
// "submitted": true,
|
|
2321
|
+
// "marketCode": "OX-USDT",
|
|
2322
|
+
// "side": "BUY",
|
|
2323
|
+
// "price": "0.01961",
|
|
2324
|
+
// "isTriggered": false,
|
|
2325
|
+
// "quantity": "100",
|
|
2326
|
+
// "orderType": "MARKET",
|
|
2327
|
+
// "timeInForce": "IOC",
|
|
2328
|
+
// "createdAt": "1715591529057",
|
|
2329
|
+
// "selfTradePreventionMode": "NONE"
|
|
2330
|
+
// }
|
|
2331
|
+
// ]
|
|
2332
|
+
// }
|
|
2333
|
+
//
|
|
2334
|
+
// rejected order (balance insufficient)
|
|
2335
|
+
// {
|
|
2336
|
+
// "success": true,
|
|
2337
|
+
// "data": [
|
|
2338
|
+
// {
|
|
2339
|
+
// "code": "710001",
|
|
2340
|
+
// "message": "System failure, exception thrown -> null",
|
|
2341
|
+
// "submitted": false,
|
|
2342
|
+
// "marketCode": "OX-USDT",
|
|
2343
|
+
// "side": "BUY",
|
|
2344
|
+
// "price": "0.01961",
|
|
2345
|
+
// "amount": "100",
|
|
2346
|
+
// "orderType": "MARKET",
|
|
2347
|
+
// "timeInForce": "IOC",
|
|
2348
|
+
// "createdAt": "1715591678835",
|
|
2349
|
+
// "source": 11,
|
|
2350
|
+
// "selfTradePreventionMode": "NONE"
|
|
2351
|
+
// }
|
|
2352
|
+
// ]
|
|
2353
|
+
// }
|
|
2354
|
+
//
|
|
2355
|
+
// rejected order (bad request)
|
|
2356
|
+
// {
|
|
2357
|
+
// "success": true,
|
|
2358
|
+
// "data": [
|
|
2359
|
+
// {
|
|
2360
|
+
// "code": "20044",
|
|
2361
|
+
// "message": "Amount is not supported for this order type",
|
|
2362
|
+
// "submitted": false,
|
|
2363
|
+
// "marketCode": "OX-USDT",
|
|
2364
|
+
// "side": "SELL",
|
|
2365
|
+
// "amount": "200",
|
|
2366
|
+
// "orderType": "MARKET",
|
|
2367
|
+
// "createdAt": "1715592079986",
|
|
2368
|
+
// "source": 11
|
|
2369
|
+
// }
|
|
2370
|
+
// ]
|
|
2371
|
+
// }
|
|
2372
|
+
//
|
|
2373
|
+
const data = this.safeList(response, 'data', []);
|
|
2374
|
+
const order = this.safeDict(data, 0, {});
|
|
2375
|
+
return this.parseOrder(order);
|
|
2376
|
+
}
|
|
2377
|
+
async createOrders(orders, params = {}) {
|
|
2378
|
+
/**
|
|
2379
|
+
* @method
|
|
2380
|
+
* @name oxfun#createOrders
|
|
2381
|
+
* @description create a list of trade orders
|
|
2382
|
+
* @see https://docs.ox.fun/?json#post-v3-orders-place
|
|
2383
|
+
* @param {Array} orders list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
|
|
2384
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2385
|
+
* @param {int} [params.timestamp] *for all orders* in milliseconds. If orders reach the matching engine and the current timestamp exceeds timestamp + recvWindow, then all orders will be rejected.
|
|
2386
|
+
* @param {int} [params.recvWindow] *for all orders* in milliseconds. If orders reach the matching engine and the current timestamp exceeds timestamp + recvWindow, then all orders will be rejected. If timestamp is provided without recvWindow, then a default recvWindow of 1000ms is used.
|
|
2387
|
+
* @param {string} [params.responseType] *for all orders* FULL or ACK
|
|
2388
|
+
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
2389
|
+
*/
|
|
2390
|
+
await this.loadMarkets();
|
|
2391
|
+
const ordersRequests = [];
|
|
2392
|
+
for (let i = 0; i < orders.length; i++) {
|
|
2393
|
+
const rawOrder = orders[i];
|
|
2394
|
+
const symbol = this.safeString(rawOrder, 'symbol');
|
|
2395
|
+
const type = this.safeString(rawOrder, 'type');
|
|
2396
|
+
const side = this.safeString(rawOrder, 'side');
|
|
2397
|
+
const amount = this.safeNumber(rawOrder, 'amount');
|
|
2398
|
+
const price = this.safeNumber(rawOrder, 'price');
|
|
2399
|
+
const orderParams = this.safeDict(rawOrder, 'params', {});
|
|
2400
|
+
const orderRequest = this.createOrderRequest(symbol, type, side, amount, price, orderParams);
|
|
2401
|
+
ordersRequests.push(orderRequest);
|
|
2402
|
+
}
|
|
2403
|
+
const request = {
|
|
2404
|
+
'responseType': 'FULL',
|
|
2405
|
+
'timestamp': this.milliseconds(),
|
|
2406
|
+
'orders': ordersRequests,
|
|
2407
|
+
};
|
|
2408
|
+
const response = await this.privatePostV3OrdersPlace(this.extend(request, params));
|
|
2409
|
+
const data = this.safeList(response, 'data', []);
|
|
2410
|
+
return this.parseOrders(data);
|
|
2411
|
+
}
|
|
2412
|
+
createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
|
|
2413
|
+
/**
|
|
2414
|
+
* @param {string} symbol unified symbol of the market to create an order in
|
|
2415
|
+
* @param {string} type 'market', 'limit', 'STOP_LIMIT' or 'STOP_MARKET'
|
|
2416
|
+
* @param {string} side 'buy' or 'sell'
|
|
2417
|
+
* @param {float} amount how much of currency you want to trade in units of base currency
|
|
2418
|
+
* @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
|
2419
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2420
|
+
* @param {int} [params.clientOrderId] a unique id for the order
|
|
2421
|
+
* @param {float} [params.cost] the quote quantity that can be used as an alternative for the amount for market buy orders
|
|
2422
|
+
* @param {float} [params.triggerPrice] The price at which a trigger order is triggered at
|
|
2423
|
+
* @param {float} [params.limitPrice] Limit price for the STOP_LIMIT order
|
|
2424
|
+
* @param {bool} [params.postOnly] if true, the order will only be posted if it will be a maker order
|
|
2425
|
+
* @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)
|
|
2426
|
+
* @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}
|
|
2427
|
+
* @param {string} [params.displayQuantity] for an iceberg order, pass both quantity and displayQuantity fields in the order request
|
|
2428
|
+
*/
|
|
2429
|
+
const market = this.market(symbol);
|
|
2430
|
+
const request = {
|
|
2431
|
+
'marketCode': market['id'],
|
|
2432
|
+
'side': side.toUpperCase(),
|
|
2433
|
+
'source': 1000,
|
|
2434
|
+
};
|
|
2435
|
+
const cost = this.safeString2(params, 'cost', 'amount');
|
|
2436
|
+
if (cost !== undefined) {
|
|
2437
|
+
request['amount'] = cost; // todo costToPrecision
|
|
2438
|
+
params = this.omit(params, ['cost', 'amount']);
|
|
2439
|
+
}
|
|
2440
|
+
else {
|
|
2441
|
+
request['quantity'] = amount; // todo amountToPrecision
|
|
2442
|
+
}
|
|
2443
|
+
const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
|
|
2444
|
+
let orderType = type.toUpperCase();
|
|
2445
|
+
if (triggerPrice !== undefined) {
|
|
2446
|
+
if (orderType === 'MARKET') {
|
|
2447
|
+
orderType = 'STOP_MARKET';
|
|
2448
|
+
}
|
|
2449
|
+
else if (orderType === 'LIMIT') {
|
|
2450
|
+
orderType = 'STOP_LIMIT';
|
|
2451
|
+
}
|
|
2452
|
+
request['stopPrice'] = triggerPrice; // todo priceToPrecision
|
|
2453
|
+
params = this.omit(params, ['triggerPrice', 'stopPrice']);
|
|
2454
|
+
}
|
|
2455
|
+
request['orderType'] = orderType;
|
|
2456
|
+
if (orderType === 'STOP_LIMIT') {
|
|
2457
|
+
request['limitPrice'] = price; // todo priceToPrecision
|
|
2458
|
+
}
|
|
2459
|
+
else if (price !== undefined) {
|
|
2460
|
+
request['price'] = price; // todo priceToPrecision
|
|
2461
|
+
}
|
|
2462
|
+
let postOnly = undefined;
|
|
2463
|
+
const isMarketOrder = (orderType === 'MARKET') || (orderType === 'STOP_MARKET');
|
|
2464
|
+
[postOnly, params] = this.handlePostOnly(isMarketOrder, false, params);
|
|
2465
|
+
const timeInForce = this.safeStringUpper(params, 'timeInForce');
|
|
2466
|
+
if (postOnly && (timeInForce !== 'MAKER_ONLY_REPRICE')) {
|
|
2467
|
+
request['timeInForce'] = 'MAKER_ONLY';
|
|
2468
|
+
}
|
|
2469
|
+
return this.extend(request, params);
|
|
2470
|
+
}
|
|
2471
|
+
async createMarketBuyOrderWithCost(symbol, cost, params = {}) {
|
|
2472
|
+
/**
|
|
2473
|
+
* @method
|
|
2474
|
+
* @name oxfun#createMarketBuyOrderWithCost
|
|
2475
|
+
* @description create a market buy order by providing the symbol and cost
|
|
2476
|
+
* @see https://open.big.one/docs/spot_orders.html#create-order
|
|
2477
|
+
* @param {string} symbol unified symbol of the market to create an order in
|
|
2478
|
+
* @param {float} cost how much you want to trade in units of the quote currency
|
|
2479
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2480
|
+
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
2481
|
+
*/
|
|
2482
|
+
await this.loadMarkets();
|
|
2483
|
+
const market = this.market(symbol);
|
|
2484
|
+
if (!market['spot']) {
|
|
2485
|
+
throw new errors.NotSupported(this.id + ' createMarketBuyOrderWithCost() supports spot orders only');
|
|
2486
|
+
}
|
|
2487
|
+
const request = {
|
|
2488
|
+
'cost': cost,
|
|
2489
|
+
};
|
|
2490
|
+
return await this.createOrder(symbol, 'market', 'buy', undefined, undefined, this.extend(request, params));
|
|
2491
|
+
}
|
|
2492
|
+
async fetchOrder(id, symbol = undefined, params = {}) {
|
|
2493
|
+
/**
|
|
2494
|
+
* @method
|
|
2495
|
+
* @name oxfun#fetchOrder
|
|
2496
|
+
* @see https://docs.ox.fun/?json#get-v3-orders-status
|
|
2497
|
+
* @description fetches information on an order made by the user
|
|
2498
|
+
* @param {string} id a unique id for the order
|
|
2499
|
+
* @param {string} [symbol] not used by oxfun fetchOrder
|
|
2500
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2501
|
+
* @param {int} [params.clientOrderId] the client order id of the order
|
|
2502
|
+
* @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
2503
|
+
*/
|
|
2504
|
+
await this.loadMarkets();
|
|
2505
|
+
const request = {
|
|
2506
|
+
'orderId': id,
|
|
2507
|
+
};
|
|
2508
|
+
const response = await this.privateGetV3OrdersStatus(this.extend(request, params));
|
|
2509
|
+
//
|
|
2510
|
+
// {
|
|
2511
|
+
// "success": true,
|
|
2512
|
+
// "data": {
|
|
2513
|
+
// "orderId": "1000111762980",
|
|
2514
|
+
// "clientOrderId": "0",
|
|
2515
|
+
// "marketCode": "ETH-USD-SWAP-LIN",
|
|
2516
|
+
// "status": "OPEN",
|
|
2517
|
+
// "side": "BUY",
|
|
2518
|
+
// "price": "2700.0",
|
|
2519
|
+
// "isTriggered": false,
|
|
2520
|
+
// "remainQuantity": "0.01",
|
|
2521
|
+
// "totalQuantity": "0.01",
|
|
2522
|
+
// "amount": "0",
|
|
2523
|
+
// "displayQuantity": "0.01",
|
|
2524
|
+
// "cumulativeMatchedQuantity": "0",
|
|
2525
|
+
// "orderType": "STOP_LIMIT",
|
|
2526
|
+
// "timeInForce": "GTC",
|
|
2527
|
+
// "source": "11",
|
|
2528
|
+
// "createdAt": "1715794191277"
|
|
2529
|
+
// }
|
|
2530
|
+
// }
|
|
2531
|
+
//
|
|
2532
|
+
const data = this.safeDict(response, 'data', {});
|
|
2533
|
+
return this.parseOrder(data);
|
|
2534
|
+
}
|
|
2535
|
+
async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
2536
|
+
/**
|
|
2537
|
+
* @method
|
|
2538
|
+
* @name oxfun#fetchOpenOrders
|
|
2539
|
+
* @description fetch all unfilled currently open orders
|
|
2540
|
+
* @see https://docs.ox.fun/?json#get-v3-orders-working
|
|
2541
|
+
* @param {string} symbol unified market symbol
|
|
2542
|
+
* @param {int} [since] the earliest time in ms to fetch open orders for
|
|
2543
|
+
* @param {int} [limit] the maximum number of open orders structures to retrieve
|
|
2544
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2545
|
+
* @param {int} [params.orderId] a unique id for the order
|
|
2546
|
+
* @param {int} [params.clientOrderId] the client order id of the order
|
|
2547
|
+
* @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
2548
|
+
*/
|
|
2549
|
+
await this.loadMarkets();
|
|
2550
|
+
const request = {};
|
|
2551
|
+
let market = undefined;
|
|
2552
|
+
if (symbol !== undefined) {
|
|
2553
|
+
market = this.market(symbol);
|
|
2554
|
+
}
|
|
2555
|
+
const response = await this.privateGetV3OrdersWorking(this.extend(request, params));
|
|
2556
|
+
const data = this.safeList(response, 'data', []);
|
|
2557
|
+
return this.parseOrders(data, market, since, limit);
|
|
2558
|
+
}
|
|
2559
|
+
async cancelOrder(id, symbol = undefined, params = {}) {
|
|
2560
|
+
/**
|
|
2561
|
+
* @method
|
|
2562
|
+
* @name oxfun#cancelOrder
|
|
2563
|
+
* @description cancels an open order
|
|
2564
|
+
* @see https://docs.ox.fun/?json#delete-v3-orders-cancel
|
|
2565
|
+
* @param {string} id order id
|
|
2566
|
+
* @param {string} symbol unified symbol of the market the order was made in
|
|
2567
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2568
|
+
* @param {int} [params.clientOrderId] a unique id for the order
|
|
2569
|
+
* @param {int} [params.timestamp] in milliseconds
|
|
2570
|
+
* @param {int} [params.recvWindow] in milliseconds
|
|
2571
|
+
* @param {string} [params.responseType] 'FULL' or 'ACK'
|
|
2572
|
+
* @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
2573
|
+
*/
|
|
2574
|
+
if (symbol === undefined) {
|
|
2575
|
+
throw new errors.ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument');
|
|
2576
|
+
}
|
|
2577
|
+
const market = this.market(symbol);
|
|
2578
|
+
const marketId = market['id'];
|
|
2579
|
+
const request = {
|
|
2580
|
+
'timestamp': this.milliseconds(),
|
|
2581
|
+
'responseType': 'FULL',
|
|
2582
|
+
};
|
|
2583
|
+
const orderRequest = {
|
|
2584
|
+
'marketCode': marketId,
|
|
2585
|
+
'orderId': id,
|
|
2586
|
+
};
|
|
2587
|
+
const clientOrderId = this.safeInteger(params, 'clientOrderId');
|
|
2588
|
+
if (clientOrderId !== undefined) {
|
|
2589
|
+
orderRequest['clientOrderId'] = clientOrderId;
|
|
2590
|
+
}
|
|
2591
|
+
request['orders'] = [orderRequest];
|
|
2592
|
+
const response = await this.privateDeleteV3OrdersCancel(this.extend(request, params));
|
|
2593
|
+
const data = this.safeList(response, 'data', []);
|
|
2594
|
+
const order = this.safeDict(data, 0, {});
|
|
2595
|
+
return this.parseOrder(order);
|
|
2596
|
+
}
|
|
2597
|
+
async cancelAllOrders(symbol = undefined, params = {}) {
|
|
2598
|
+
/**
|
|
2599
|
+
* @method
|
|
2600
|
+
* @name oxfun#cancelAllOrders
|
|
2601
|
+
* @description cancel all open orders
|
|
2602
|
+
* @see https://docs.ox.fun/?json#delete-v3-orders-cancel-all
|
|
2603
|
+
* @param {string} symbol unified market symbol, only orders in the market of this symbol are cancelled when symbol is not undefined
|
|
2604
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2605
|
+
* @returns {object} response from exchange
|
|
2606
|
+
*/
|
|
2607
|
+
const request = {};
|
|
2608
|
+
if (symbol !== undefined) {
|
|
2609
|
+
const market = this.market(symbol);
|
|
2610
|
+
request['marketCode'] = market['id'];
|
|
2611
|
+
}
|
|
2612
|
+
//
|
|
2613
|
+
// {
|
|
2614
|
+
// "success": true,
|
|
2615
|
+
// "data": { "notice": "Orders queued for cancelation" }
|
|
2616
|
+
// }
|
|
2617
|
+
//
|
|
2618
|
+
// {
|
|
2619
|
+
// "success": true,
|
|
2620
|
+
// "data": { "notice": "No working orders found" }
|
|
2621
|
+
// }
|
|
2622
|
+
//
|
|
2623
|
+
return await this.privateDeleteV3OrdersCancelAll(this.extend(request, params));
|
|
2624
|
+
}
|
|
2625
|
+
async cancelOrders(ids, symbol = undefined, params = {}) {
|
|
2626
|
+
/**
|
|
2627
|
+
* @method
|
|
2628
|
+
* @name oxfun#cancelOrders
|
|
2629
|
+
* @description cancel multiple orders
|
|
2630
|
+
* @see https://docs.ox.fun/?json#delete-v3-orders-cancel
|
|
2631
|
+
* @param {string[]} ids order ids
|
|
2632
|
+
* @param {string} [symbol] unified market symbol
|
|
2633
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2634
|
+
* @param {int} [params.timestamp] in milliseconds
|
|
2635
|
+
* @param {int} [params.recvWindow] in milliseconds
|
|
2636
|
+
* @param {string} [params.responseType] 'FULL' or 'ACK'
|
|
2637
|
+
* @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
2638
|
+
*/
|
|
2639
|
+
if (symbol === undefined) {
|
|
2640
|
+
throw new errors.ArgumentsRequired(this.id + ' cancelOrders() requires a symbol argument');
|
|
2641
|
+
}
|
|
2642
|
+
await this.loadMarkets();
|
|
2643
|
+
const market = this.market(symbol);
|
|
2644
|
+
const marketId = market['id'];
|
|
2645
|
+
const request = {
|
|
2646
|
+
'timestamp': this.milliseconds(),
|
|
2647
|
+
'responseType': 'FULL',
|
|
2648
|
+
};
|
|
2649
|
+
const orders = [];
|
|
2650
|
+
for (let i = 0; i < ids.length; i++) {
|
|
2651
|
+
const order = {
|
|
2652
|
+
'marketCode': marketId,
|
|
2653
|
+
'orderId': ids[i],
|
|
2654
|
+
};
|
|
2655
|
+
orders.push(order);
|
|
2656
|
+
}
|
|
2657
|
+
request['orders'] = orders;
|
|
2658
|
+
const response = await this.privateDeleteV3OrdersCancel(this.extend(request, params));
|
|
2659
|
+
const data = this.safeList(response, 'data', []);
|
|
2660
|
+
return this.parseOrders(data, market);
|
|
2661
|
+
}
|
|
2662
|
+
parseOrder(order, market = undefined) {
|
|
2663
|
+
//
|
|
2664
|
+
// accepted market order responseType FULL
|
|
2665
|
+
// {
|
|
2666
|
+
// "notice": "OrderMatched",
|
|
2667
|
+
// "accountId": "106490",
|
|
2668
|
+
// "orderId": "1000109901865",
|
|
2669
|
+
// "submitted": true,
|
|
2670
|
+
// "clientOrderId": "0",
|
|
2671
|
+
// "marketCode": "OX-USDT",
|
|
2672
|
+
// "status": "FILLED",
|
|
2673
|
+
// "side": "SELL",
|
|
2674
|
+
// "isTriggered": false,
|
|
2675
|
+
// "quantity": "150.0",
|
|
2676
|
+
// "amount": "0.0",
|
|
2677
|
+
// "remainQuantity": "0.0",
|
|
2678
|
+
// "matchId": "100017047880451399",
|
|
2679
|
+
// "matchPrice": "0.01465",
|
|
2680
|
+
// "matchQuantity": "150.0",
|
|
2681
|
+
// "feeInstrumentId": "USDT",
|
|
2682
|
+
// "fees": "0.0015382500",
|
|
2683
|
+
// "orderType": "MARKET",
|
|
2684
|
+
// "createdAt": "1715592472236",
|
|
2685
|
+
// "lastMatchedAt": "1715592472200",
|
|
2686
|
+
// "displayQuantity": "150.0"
|
|
2687
|
+
// }
|
|
2688
|
+
//
|
|
2689
|
+
// accepted limit order responseType FULL
|
|
2690
|
+
// {
|
|
2691
|
+
// "notice": "OrderOpened",
|
|
2692
|
+
// "accountId": "106490",
|
|
2693
|
+
// "orderId": "1000111482406",
|
|
2694
|
+
// "submitted": true,
|
|
2695
|
+
// "clientOrderId": "0",
|
|
2696
|
+
// "marketCode": "ETH-USD-SWAP-LIN",
|
|
2697
|
+
// "status": "OPEN",
|
|
2698
|
+
// "side": "SELL",
|
|
2699
|
+
// "price": "4000.0",
|
|
2700
|
+
// "isTriggered": false,
|
|
2701
|
+
// "quantity": "0.01",
|
|
2702
|
+
// "amount": "0.0",
|
|
2703
|
+
// "orderType": "LIMIT",
|
|
2704
|
+
// "timeInForce": "GTC",
|
|
2705
|
+
// "createdAt": "1715763507682",
|
|
2706
|
+
// "displayQuantity": "0.01"
|
|
2707
|
+
// }
|
|
2708
|
+
//
|
|
2709
|
+
// accepted order responseType ACK
|
|
2710
|
+
// {
|
|
2711
|
+
// "accountId": "106490",
|
|
2712
|
+
// "orderId": "1000109892193",
|
|
2713
|
+
// "submitted": true,
|
|
2714
|
+
// "marketCode": "OX-USDT",
|
|
2715
|
+
// "side": "BUY",
|
|
2716
|
+
// "price": "0.01961",
|
|
2717
|
+
// "isTriggered": false,
|
|
2718
|
+
// "quantity": "100",
|
|
2719
|
+
// "orderType": "MARKET",
|
|
2720
|
+
// "timeInForce": "IOC",
|
|
2721
|
+
// "createdAt": "1715591529057",
|
|
2722
|
+
// "selfTradePreventionMode": "NONE"
|
|
2723
|
+
// }
|
|
2724
|
+
//
|
|
2725
|
+
// rejected order (balance insufficient)
|
|
2726
|
+
// {
|
|
2727
|
+
// "code": "710001",
|
|
2728
|
+
// "message": "System failure, exception thrown -> null",
|
|
2729
|
+
// "submitted": false,
|
|
2730
|
+
// "marketCode": "OX-USDT",
|
|
2731
|
+
// "side": "BUY",
|
|
2732
|
+
// "price": "0.01961",
|
|
2733
|
+
// "amount": "100",
|
|
2734
|
+
// "orderType": "MARKET",
|
|
2735
|
+
// "timeInForce": "IOC",
|
|
2736
|
+
// "createdAt": "1715591678835",
|
|
2737
|
+
// "source": 11,
|
|
2738
|
+
// "selfTradePreventionMode": "NONE"
|
|
2739
|
+
// }
|
|
2740
|
+
//
|
|
2741
|
+
// rejected order (bad request)
|
|
2742
|
+
// {
|
|
2743
|
+
// "code": "20044",
|
|
2744
|
+
// "message": "Amount is not supported for this order type",
|
|
2745
|
+
// "submitted": false,
|
|
2746
|
+
// "marketCode": "OX-USDT",
|
|
2747
|
+
// "side": "SELL",
|
|
2748
|
+
// "amount": "200",
|
|
2749
|
+
// "orderType": "MARKET",
|
|
2750
|
+
// "createdAt": "1715592079986",
|
|
2751
|
+
// "source": 11
|
|
2752
|
+
// }
|
|
2753
|
+
//
|
|
2754
|
+
// fetchOrder
|
|
2755
|
+
// {
|
|
2756
|
+
// "orderId": "1000111762980",
|
|
2757
|
+
// "clientOrderId": "0",
|
|
2758
|
+
// "marketCode": "ETH-USD-SWAP-LIN",
|
|
2759
|
+
// "status": "OPEN",
|
|
2760
|
+
// "side": "BUY",
|
|
2761
|
+
// "price": "2700.0",
|
|
2762
|
+
// "isTriggered": false,
|
|
2763
|
+
// "remainQuantity": "0.01",
|
|
2764
|
+
// "totalQuantity": "0.01",
|
|
2765
|
+
// "amount": "0",
|
|
2766
|
+
// "displayQuantity": "0.01",
|
|
2767
|
+
// "cumulativeMatchedQuantity": "0",
|
|
2768
|
+
// "orderType": "STOP_LIMIT",
|
|
2769
|
+
// "timeInForce": "GTC",
|
|
2770
|
+
// "source": "11",
|
|
2771
|
+
// "createdAt": "1715794191277"
|
|
2772
|
+
// }
|
|
2773
|
+
//
|
|
2774
|
+
const marketId = this.safeString(order, 'marketCode');
|
|
2775
|
+
market = this.safeMarket(marketId, market);
|
|
2776
|
+
const timestamp = this.safeInteger(order, 'createdAt');
|
|
2777
|
+
let fee = undefined;
|
|
2778
|
+
const feeCurrency = this.safeString(order, 'feeInstrumentId');
|
|
2779
|
+
if (feeCurrency !== undefined) {
|
|
2780
|
+
fee = {
|
|
2781
|
+
'currency': this.safeCurrencyCode(feeCurrency),
|
|
2782
|
+
'cost': this.safeNumber(order, 'fees'),
|
|
2783
|
+
};
|
|
2784
|
+
}
|
|
2785
|
+
let status = this.safeString(order, 'status');
|
|
2786
|
+
const code = this.safeInteger(order, 'code'); // rejected orders have code of the error
|
|
2787
|
+
if (code !== undefined) {
|
|
2788
|
+
status = 'rejected';
|
|
2789
|
+
}
|
|
2790
|
+
const triggerPrice = this.safeString(order, 'stopPrice');
|
|
2791
|
+
return this.safeOrder({
|
|
2792
|
+
'id': this.safeString(order, 'orderId'),
|
|
2793
|
+
'clientOrderId': this.safeString(order, 'clientOrderId'),
|
|
2794
|
+
'timestamp': timestamp,
|
|
2795
|
+
'datetime': this.iso8601(timestamp),
|
|
2796
|
+
'lastTradeTimestamp': this.safeInteger(order, 'lastMatchedAt'),
|
|
2797
|
+
'lastUpdateTimestamp': this.safeInteger(order, 'lastModifiedAt'),
|
|
2798
|
+
'status': this.parseOrderStatus(status),
|
|
2799
|
+
'symbol': market['symbol'],
|
|
2800
|
+
'type': this.parseOrderType(this.safeString(order, 'orderType')),
|
|
2801
|
+
'timeInForce': this.parseOrderTimeInForce(this.safeString(order, 'timeInForce')),
|
|
2802
|
+
'side': this.safeStringLower(order, 'side'),
|
|
2803
|
+
'price': this.safeStringN(order, ['price', 'matchPrice', 'limitPrice']),
|
|
2804
|
+
'average': undefined,
|
|
2805
|
+
'amount': this.safeString2(order, 'totalQuantity', 'quantity'),
|
|
2806
|
+
'filled': this.safeString2(order, 'cumulativeMatchedQuantity', 'matchQuantity'),
|
|
2807
|
+
'remaining': this.safeString(order, 'remainQuantity'),
|
|
2808
|
+
'triggerPrice': triggerPrice,
|
|
2809
|
+
'stopLossPrice': triggerPrice,
|
|
2810
|
+
'cost': this.omitZero(this.safeString(order, 'amount')),
|
|
2811
|
+
'trades': undefined,
|
|
2812
|
+
'fee': fee,
|
|
2813
|
+
'info': order,
|
|
2814
|
+
}, market);
|
|
2815
|
+
}
|
|
2816
|
+
parseOrderStatus(status) {
|
|
2817
|
+
const statuses = {
|
|
2818
|
+
'OPEN': 'open',
|
|
2819
|
+
'PARTIALLY_FILLED': 'open',
|
|
2820
|
+
'PARTIAL_FILL': 'open',
|
|
2821
|
+
'FILLED': 'closed',
|
|
2822
|
+
'CANCELED': 'canceled',
|
|
2823
|
+
'CANCELED_BY_USER': 'canceled',
|
|
2824
|
+
'CANCELED_BY_MAKER_ONLY': 'rejected',
|
|
2825
|
+
'CANCELED_BY_FOK': 'rejected',
|
|
2826
|
+
'CANCELED_ALL_BY_IOC': 'rejected',
|
|
2827
|
+
'CANCELED_PARTIAL_BY_IOC': 'canceled',
|
|
2828
|
+
'CANCELED_BY_SELF_TRADE_PROTECTION': 'rejected',
|
|
2829
|
+
};
|
|
2830
|
+
return this.safeString(statuses, status, status);
|
|
2831
|
+
}
|
|
2832
|
+
parseOrderType(type) {
|
|
2833
|
+
const types = {
|
|
2834
|
+
'LIMIT': 'limit',
|
|
2835
|
+
'STOP_LIMIT': 'limit',
|
|
2836
|
+
'MARKET': 'market',
|
|
2837
|
+
'STOP_MARKET': 'market',
|
|
2838
|
+
};
|
|
2839
|
+
return this.safeString(types, type, type);
|
|
2840
|
+
}
|
|
2841
|
+
parseOrderTimeInForce(type) {
|
|
2842
|
+
const types = {
|
|
2843
|
+
'GTC': 'GTC',
|
|
2844
|
+
'IOC': 'IOC',
|
|
2845
|
+
'FOK': 'FOK',
|
|
2846
|
+
'MAKER_ONLY': 'PO',
|
|
2847
|
+
'MAKER_ONLY_REPRICE': 'PO',
|
|
2848
|
+
};
|
|
2849
|
+
return this.safeString(types, type, type);
|
|
2850
|
+
}
|
|
2851
|
+
sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
|
|
2852
|
+
const baseUrl = this.urls['api'][api];
|
|
2853
|
+
let url = baseUrl + '/' + path;
|
|
2854
|
+
let queryString = '';
|
|
2855
|
+
if (method === 'GET') {
|
|
2856
|
+
queryString = this.urlencode(params);
|
|
2857
|
+
if (queryString.length !== 0) {
|
|
2858
|
+
url += '?' + queryString;
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
if (api === 'private') {
|
|
2862
|
+
this.checkRequiredCredentials();
|
|
2863
|
+
const timestamp = this.milliseconds();
|
|
2864
|
+
const isoDatetime = this.iso8601(timestamp);
|
|
2865
|
+
const datetimeParts = isoDatetime.split('.');
|
|
2866
|
+
const datetime = datetimeParts[0];
|
|
2867
|
+
const nonce = this.nonce();
|
|
2868
|
+
const urlParts = baseUrl.split('//');
|
|
2869
|
+
if ((method === 'POST') || (method === 'DELETE')) {
|
|
2870
|
+
body = this.json(params);
|
|
2871
|
+
queryString = body;
|
|
2872
|
+
}
|
|
2873
|
+
const msgString = datetime + '\n' + nonce.toString() + '\n' + method + '\n' + urlParts[1] + '\n/' + path + '\n' + queryString;
|
|
2874
|
+
const signature = this.hmac(this.encode(msgString), this.encode(this.secret), sha256.sha256, 'base64');
|
|
2875
|
+
headers = {
|
|
2876
|
+
'Content-Type': 'application/json',
|
|
2877
|
+
'AccessKey': this.apiKey,
|
|
2878
|
+
'Timestamp': datetime,
|
|
2879
|
+
'Signature': signature,
|
|
2880
|
+
'Nonce': nonce,
|
|
2881
|
+
};
|
|
2882
|
+
}
|
|
2883
|
+
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
|
|
2884
|
+
}
|
|
2885
|
+
handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
|
|
2886
|
+
if (response === undefined) {
|
|
2887
|
+
return undefined;
|
|
2888
|
+
}
|
|
2889
|
+
if (code !== 200) {
|
|
2890
|
+
const responseCode = this.safeString(response, 'code', undefined);
|
|
2891
|
+
const feedback = this.id + ' ' + body;
|
|
2892
|
+
this.throwBroadlyMatchedException(this.exceptions['broad'], body, feedback);
|
|
2893
|
+
this.throwExactlyMatchedException(this.exceptions['exact'], responseCode, feedback);
|
|
2894
|
+
throw new errors.ExchangeError(feedback);
|
|
2895
|
+
}
|
|
2896
|
+
return undefined;
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
|
|
2900
|
+
module.exports = oxfun;
|