ccxt 4.4.85 → 4.4.87

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.
Files changed (115) hide show
  1. package/README.md +18 -7
  2. package/dist/ccxt.browser.min.js +3 -3
  3. package/dist/cjs/ccxt.js +16 -9
  4. package/dist/cjs/src/abstract/bittrade.js +9 -0
  5. package/dist/cjs/src/abstract/modetrade.js +9 -0
  6. package/dist/cjs/src/ascendex.js +189 -155
  7. package/dist/cjs/src/base/Exchange.js +10 -8
  8. package/dist/cjs/src/bequant.js +1 -1
  9. package/dist/cjs/src/binance.js +1 -1
  10. package/dist/cjs/src/bitget.js +5 -4
  11. package/dist/cjs/src/bitmart.js +1 -1
  12. package/dist/cjs/src/bitteam.js +31 -0
  13. package/dist/cjs/src/bittrade.js +2049 -0
  14. package/dist/cjs/src/coinbase.js +2 -6
  15. package/dist/cjs/src/coinmetro.js +5 -1
  16. package/dist/cjs/src/deribit.js +4 -5
  17. package/dist/cjs/src/derive.js +4 -5
  18. package/dist/cjs/src/ellipx.js +2 -3
  19. package/dist/cjs/src/gate.js +92 -76
  20. package/dist/cjs/src/hollaex.js +107 -49
  21. package/dist/cjs/src/htx.js +30 -52
  22. package/dist/cjs/src/hyperliquid.js +36 -20
  23. package/dist/cjs/src/kraken.js +5 -8
  24. package/dist/cjs/src/mexc.js +2 -2
  25. package/dist/cjs/src/modetrade.js +2839 -0
  26. package/dist/cjs/src/ndax.js +25 -24
  27. package/dist/cjs/src/okcoin.js +12 -31
  28. package/dist/cjs/src/okx.js +104 -2
  29. package/dist/cjs/src/okxus.js +53 -0
  30. package/dist/cjs/src/onetrading.js +9 -6
  31. package/dist/cjs/src/oxfun.js +42 -114
  32. package/dist/cjs/src/paradex.js +10 -1
  33. package/dist/cjs/src/phemex.js +4 -6
  34. package/dist/cjs/src/poloniex.js +181 -170
  35. package/dist/cjs/src/pro/binance.js +1 -0
  36. package/dist/cjs/src/pro/bittrade.js +605 -0
  37. package/dist/cjs/src/pro/luno.js +6 -5
  38. package/dist/cjs/src/pro/mexc.js +3 -0
  39. package/dist/cjs/src/pro/modetrade.js +1334 -0
  40. package/dist/cjs/src/pro/okxus.js +38 -0
  41. package/dist/cjs/src/probit.js +18 -51
  42. package/dist/cjs/src/timex.js +5 -10
  43. package/dist/cjs/src/vertex.js +3 -4
  44. package/dist/cjs/src/whitebit.js +41 -11
  45. package/dist/cjs/src/woo.js +101 -77
  46. package/dist/cjs/src/woofipro.js +24 -21
  47. package/dist/cjs/src/xt.js +36 -44
  48. package/js/ccxt.d.ts +20 -11
  49. package/js/ccxt.js +14 -8
  50. package/js/src/abstract/modetrade.d.ts +122 -0
  51. package/js/src/abstract/myokx.d.ts +2 -0
  52. package/js/src/abstract/okx.d.ts +2 -0
  53. package/js/src/abstract/okxus.d.ts +352 -0
  54. package/js/src/abstract/okxus.js +11 -0
  55. package/js/src/ascendex.d.ts +2 -0
  56. package/js/src/ascendex.js +189 -155
  57. package/js/src/base/Exchange.js +10 -8
  58. package/js/src/bequant.js +1 -1
  59. package/js/src/binance.js +1 -1
  60. package/js/src/bitget.js +5 -4
  61. package/js/src/bitmart.js +1 -1
  62. package/js/src/bitteam.js +31 -0
  63. package/js/src/{huobijp.d.ts → bittrade.d.ts} +29 -29
  64. package/js/src/{huobijp.js → bittrade.js} +35 -35
  65. package/js/src/coinbase.js +2 -6
  66. package/js/src/coinmetro.js +5 -1
  67. package/js/src/deribit.js +4 -5
  68. package/js/src/derive.js +4 -3
  69. package/js/src/ellipx.d.ts +1 -1
  70. package/js/src/ellipx.js +3 -5
  71. package/js/src/gate.js +92 -76
  72. package/js/src/hollaex.js +107 -49
  73. package/js/src/htx.js +30 -52
  74. package/js/src/hyperliquid.js +36 -20
  75. package/js/src/kraken.js +5 -8
  76. package/js/src/mexc.js +2 -2
  77. package/js/src/modetrade.d.ts +475 -0
  78. package/js/src/modetrade.js +2840 -0
  79. package/js/src/ndax.js +25 -24
  80. package/js/src/okcoin.js +12 -31
  81. package/js/src/okx.d.ts +24 -1
  82. package/js/src/okx.js +104 -2
  83. package/js/src/okxus.d.ts +4 -0
  84. package/js/src/okxus.js +54 -0
  85. package/js/src/onetrading.js +9 -6
  86. package/js/src/oxfun.js +42 -114
  87. package/js/src/paradex.js +10 -1
  88. package/js/src/phemex.js +4 -6
  89. package/js/src/poloniex.d.ts +2 -0
  90. package/js/src/poloniex.js +181 -170
  91. package/js/src/pro/binance.js +1 -0
  92. package/js/src/pro/{huobijp.d.ts → bittrade.d.ts} +6 -6
  93. package/js/src/pro/{huobijp.js → bittrade.js} +7 -7
  94. package/js/src/pro/luno.js +6 -5
  95. package/js/src/pro/mexc.js +3 -0
  96. package/js/src/pro/modetrade.d.ts +155 -0
  97. package/js/src/pro/modetrade.js +1335 -0
  98. package/js/src/pro/okxus.d.ts +4 -0
  99. package/js/src/pro/okxus.js +39 -0
  100. package/js/src/probit.js +18 -51
  101. package/js/src/timex.js +5 -10
  102. package/js/src/vertex.js +3 -4
  103. package/js/src/whitebit.js +42 -11
  104. package/js/src/woo.d.ts +2 -0
  105. package/js/src/woo.js +101 -77
  106. package/js/src/woofipro.d.ts +2 -1
  107. package/js/src/woofipro.js +24 -21
  108. package/js/src/xt.js +36 -44
  109. package/package.json +1 -1
  110. package/js/src/abstract/kuna.d.ts +0 -185
  111. package/js/src/kuna.d.ts +0 -335
  112. package/js/src/kuna.js +0 -2006
  113. /package/js/src/abstract/{huobijp.d.ts → bittrade.d.ts} +0 -0
  114. /package/js/src/abstract/{huobijp.js → bittrade.js} +0 -0
  115. /package/js/src/abstract/{kuna.js → modetrade.js} +0 -0
@@ -0,0 +1,2839 @@
1
+ 'use strict';
2
+
3
+ var modetrade$1 = require('./abstract/modetrade.js');
4
+ var errors = require('./base/errors.js');
5
+ var number = require('./base/functions/number.js');
6
+ var Precise = require('./base/Precise.js');
7
+ var crypto = require('./base/functions/crypto.js');
8
+ var ed25519 = require('./static_dependencies/noble-curves/ed25519.js');
9
+ var sha3 = require('./static_dependencies/noble-hashes/sha3.js');
10
+ var secp256k1 = require('./static_dependencies/noble-curves/secp256k1.js');
11
+
12
+ // ----------------------------------------------------------------------------
13
+ // ---------------------------------------------------------------------------
14
+ /**
15
+ * @class modetrade
16
+ * @augments Exchange
17
+ */
18
+ class modetrade extends modetrade$1 {
19
+ describe() {
20
+ return this.deepExtend(super.describe(), {
21
+ 'id': 'modetrade',
22
+ 'name': 'Mode Trade',
23
+ 'countries': ['KY'],
24
+ 'rateLimit': 100,
25
+ 'version': 'v1',
26
+ 'certified': true,
27
+ 'pro': true,
28
+ 'dex': true,
29
+ 'hostname': 'trade.mode.network',
30
+ 'has': {
31
+ 'CORS': undefined,
32
+ 'spot': false,
33
+ 'margin': false,
34
+ 'swap': true,
35
+ 'future': false,
36
+ 'option': false,
37
+ 'addMargin': false,
38
+ 'cancelAllOrders': true,
39
+ 'cancelOrder': true,
40
+ 'cancelOrders': true,
41
+ 'cancelWithdraw': false,
42
+ 'closeAllPositions': false,
43
+ 'closePosition': false,
44
+ 'createConvertTrade': false,
45
+ 'createDepositAddress': false,
46
+ 'createMarketBuyOrderWithCost': false,
47
+ 'createMarketOrder': false,
48
+ 'createMarketOrderWithCost': false,
49
+ 'createMarketSellOrderWithCost': false,
50
+ 'createOrder': true,
51
+ 'createOrderWithTakeProfitAndStopLoss': true,
52
+ 'createReduceOnlyOrder': true,
53
+ 'createStopLimitOrder': false,
54
+ 'createStopLossOrder': true,
55
+ 'createStopMarketOrder': false,
56
+ 'createStopOrder': false,
57
+ 'createTakeProfitOrder': true,
58
+ 'createTrailingAmountOrder': false,
59
+ 'createTrailingPercentOrder': false,
60
+ 'createTriggerOrder': true,
61
+ 'fetchAccounts': false,
62
+ 'fetchBalance': true,
63
+ 'fetchCanceledOrders': false,
64
+ 'fetchClosedOrder': false,
65
+ 'fetchClosedOrders': true,
66
+ 'fetchConvertCurrencies': false,
67
+ 'fetchConvertQuote': false,
68
+ 'fetchCurrencies': true,
69
+ 'fetchDepositAddress': false,
70
+ 'fetchDeposits': true,
71
+ 'fetchDepositsWithdrawals': true,
72
+ 'fetchFundingHistory': true,
73
+ 'fetchFundingInterval': true,
74
+ 'fetchFundingIntervals': false,
75
+ 'fetchFundingRate': true,
76
+ 'fetchFundingRateHistory': true,
77
+ 'fetchFundingRates': true,
78
+ 'fetchIndexOHLCV': false,
79
+ 'fetchLedger': true,
80
+ 'fetchLeverage': true,
81
+ 'fetchMarginAdjustmentHistory': false,
82
+ 'fetchMarginMode': false,
83
+ 'fetchMarkets': true,
84
+ 'fetchMarkOHLCV': false,
85
+ 'fetchMyTrades': true,
86
+ 'fetchOHLCV': true,
87
+ 'fetchOpenInterestHistory': false,
88
+ 'fetchOpenOrder': false,
89
+ 'fetchOpenOrders': true,
90
+ 'fetchOrder': true,
91
+ 'fetchOrderBook': true,
92
+ 'fetchOrders': true,
93
+ 'fetchOrderTrades': true,
94
+ 'fetchPosition': true,
95
+ 'fetchPositionMode': false,
96
+ 'fetchPositions': true,
97
+ 'fetchPremiumIndexOHLCV': false,
98
+ 'fetchStatus': true,
99
+ 'fetchTicker': false,
100
+ 'fetchTickers': false,
101
+ 'fetchTime': true,
102
+ 'fetchTrades': true,
103
+ 'fetchTradingFee': false,
104
+ 'fetchTradingFees': true,
105
+ 'fetchTransactions': 'emulated',
106
+ 'fetchTransfers': false,
107
+ 'fetchWithdrawals': true,
108
+ 'reduceMargin': false,
109
+ 'setLeverage': true,
110
+ 'setMargin': false,
111
+ 'setPositionMode': false,
112
+ 'transfer': false,
113
+ 'withdraw': true, // exchange have that endpoint disabled atm, but was once implemented in ccxt per old docs: https://kronosresearch.github.io/wootrade-documents/#token-withdraw
114
+ },
115
+ 'timeframes': {
116
+ '1m': '1m',
117
+ '5m': '5m',
118
+ '15m': '15m',
119
+ '30m': '30m',
120
+ '1h': '1h',
121
+ '4h': '4h',
122
+ '12h': '12h',
123
+ '1d': '1d',
124
+ '1w': '1w',
125
+ '1M': '1mon',
126
+ '1y': '1y',
127
+ },
128
+ 'urls': {
129
+ 'logo': 'https://github.com/user-attachments/assets/cec2b7f1-3b2b-4502-971b-447ee1937d6b',
130
+ 'api': {
131
+ 'public': 'https://api-evm.orderly.org',
132
+ 'private': 'https://api-evm.orderly.org',
133
+ },
134
+ 'test': {
135
+ 'public': 'https://testnet-api-evm.orderly.org',
136
+ 'private': 'https://testnet-api-evm.orderly.org',
137
+ },
138
+ 'www': 'https://trade.mode.network',
139
+ 'referral': {
140
+ 'url': 'https://trade.mode.network?ref=MODETRADE',
141
+ 'discount': 0.2,
142
+ },
143
+ },
144
+ 'api': {
145
+ 'v1': {
146
+ 'public': {
147
+ 'get': {
148
+ 'public/volume/stats': 1,
149
+ 'public/broker/name': 1,
150
+ 'public/chain_info/{broker_id}': 1,
151
+ 'public/system_info': 1,
152
+ 'public/vault_balance': 1,
153
+ 'public/insurancefund': 1,
154
+ 'public/chain_info': 1,
155
+ 'faucet/usdc': 1,
156
+ 'public/account': 1,
157
+ 'get_account': 1,
158
+ 'registration_nonce': 1,
159
+ 'get_orderly_key': 1,
160
+ 'public/liquidation': 1,
161
+ 'public/liquidated_positions': 1,
162
+ 'public/config': 1,
163
+ 'public/campaign/ranking': 10,
164
+ 'public/campaign/stats': 10,
165
+ 'public/campaign/user': 10,
166
+ 'public/campaign/stats/details': 10,
167
+ 'public/campaigns': 10,
168
+ 'public/points/leaderboard': 1,
169
+ 'client/points': 1,
170
+ 'public/points/epoch': 1,
171
+ 'public/points/epoch_dates': 1,
172
+ 'public/referral/check_ref_code': 1,
173
+ 'public/referral/verify_ref_code': 1,
174
+ 'referral/admin_info': 1,
175
+ 'referral/info': 1,
176
+ 'referral/referee_info': 1,
177
+ 'referral/referee_rebate_summary': 1,
178
+ 'referral/referee_history': 1,
179
+ 'referral/referral_history': 1,
180
+ 'referral/rebate_summary': 1,
181
+ 'client/distribution_history': 1,
182
+ 'tv/config': 1,
183
+ 'tv/history': 1,
184
+ 'tv/symbol_info': 1,
185
+ 'public/funding_rate_history': 1,
186
+ 'public/funding_rate/{symbol}': 0.33,
187
+ 'public/funding_rates': 1,
188
+ 'public/info': 1,
189
+ 'public/info/{symbol}': 1,
190
+ 'public/market_trades': 1,
191
+ 'public/token': 1,
192
+ 'public/futures': 1,
193
+ 'public/futures/{symbol}': 1,
194
+ },
195
+ 'post': {
196
+ 'register_account': 1,
197
+ },
198
+ },
199
+ 'private': {
200
+ 'get': {
201
+ 'client/key_info': 6,
202
+ 'client/orderly_key_ip_restriction': 6,
203
+ 'order/{oid}': 1,
204
+ 'client/order/{client_order_id}': 1,
205
+ 'algo/order/{oid}': 1,
206
+ 'algo/client/order/{client_order_id}': 1,
207
+ 'orders': 1,
208
+ 'algo/orders': 1,
209
+ 'trade/{tid}': 1,
210
+ 'trades': 1,
211
+ 'order/{oid}/trades': 1,
212
+ 'client/liquidator_liquidations': 1,
213
+ 'liquidations': 1,
214
+ 'asset/history': 60,
215
+ 'client/holding': 1,
216
+ 'withdraw_nonce': 1,
217
+ 'settle_nonce': 1,
218
+ 'pnl_settlement/history': 1,
219
+ 'volume/user/daily': 60,
220
+ 'volume/user/stats': 60,
221
+ 'client/statistics': 60,
222
+ 'client/info': 60,
223
+ 'client/statistics/daily': 60,
224
+ 'positions': 3.33,
225
+ 'position/{symbol}': 3.33,
226
+ 'funding_fee/history': 30,
227
+ 'notification/inbox/notifications': 60,
228
+ 'notification/inbox/unread': 60,
229
+ 'volume/broker/daily': 60,
230
+ 'broker/fee_rate/default': 10,
231
+ 'broker/user_info': 10,
232
+ 'orderbook/{symbol}': 1,
233
+ 'kline': 1,
234
+ },
235
+ 'post': {
236
+ 'orderly_key': 1,
237
+ 'client/set_orderly_key_ip_restriction': 6,
238
+ 'client/reset_orderly_key_ip_restriction': 6,
239
+ 'order': 1,
240
+ 'batch-order': 10,
241
+ 'algo/order': 1,
242
+ 'liquidation': 1,
243
+ 'claim_insurance_fund': 1,
244
+ 'withdraw_request': 1,
245
+ 'settle_pnl': 1,
246
+ 'notification/inbox/mark_read': 60,
247
+ 'notification/inbox/mark_read_all': 60,
248
+ 'client/leverage': 120,
249
+ 'client/maintenance_config': 60,
250
+ 'delegate_signer': 10,
251
+ 'delegate_orderly_key': 10,
252
+ 'delegate_settle_pnl': 10,
253
+ 'delegate_withdraw_request': 10,
254
+ 'broker/fee_rate/set': 10,
255
+ 'broker/fee_rate/set_default': 10,
256
+ 'broker/fee_rate/default': 10,
257
+ 'referral/create': 10,
258
+ 'referral/update': 10,
259
+ 'referral/bind': 10,
260
+ 'referral/edit_split': 10,
261
+ },
262
+ 'put': {
263
+ 'order': 1,
264
+ 'algo/order': 1,
265
+ },
266
+ 'delete': {
267
+ 'order': 1,
268
+ 'algo/order': 1,
269
+ 'client/order': 1,
270
+ 'algo/client/order': 1,
271
+ 'algo/orders': 1,
272
+ 'orders': 1,
273
+ 'batch-order': 1,
274
+ 'client/batch-order': 1,
275
+ },
276
+ },
277
+ },
278
+ },
279
+ 'requiredCredentials': {
280
+ 'apiKey': true,
281
+ 'secret': true,
282
+ 'accountId': true,
283
+ 'privateKey': false,
284
+ },
285
+ 'fees': {
286
+ 'trading': {
287
+ 'tierBased': true,
288
+ 'percentage': true,
289
+ 'maker': this.parseNumber('0.0002'),
290
+ 'taker': this.parseNumber('0.0005'),
291
+ },
292
+ },
293
+ 'options': {
294
+ 'sandboxMode': false,
295
+ 'brokerId': 'CCXT',
296
+ 'verifyingContractAddress': '0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203',
297
+ },
298
+ 'features': {
299
+ 'default': {
300
+ 'sandbox': true,
301
+ 'createOrder': {
302
+ 'marginMode': false,
303
+ 'triggerPrice': true,
304
+ 'triggerPriceType': undefined,
305
+ 'triggerDirection': false,
306
+ 'stopLossPrice': false,
307
+ 'takeProfitPrice': false,
308
+ 'attachedStopLossTakeProfit': undefined,
309
+ 'timeInForce': {
310
+ 'IOC': true,
311
+ 'FOK': true,
312
+ 'PO': true,
313
+ 'GTD': false,
314
+ },
315
+ 'hedged': false,
316
+ 'trailing': true,
317
+ 'leverage': true,
318
+ 'marketBuyByCost': false,
319
+ 'marketBuyRequiresPrice': false,
320
+ 'selfTradePrevention': false,
321
+ 'iceberg': true, // todo implement
322
+ },
323
+ 'createOrders': {
324
+ 'max': 10,
325
+ },
326
+ 'fetchMyTrades': {
327
+ 'marginMode': false,
328
+ 'limit': 500,
329
+ 'daysBack': undefined,
330
+ 'untilDays': 100000,
331
+ 'symbolRequired': false,
332
+ },
333
+ 'fetchOrder': {
334
+ 'marginMode': false,
335
+ 'trigger': true,
336
+ 'trailing': false,
337
+ 'symbolRequired': false,
338
+ },
339
+ 'fetchOpenOrders': {
340
+ 'marginMode': false,
341
+ 'limit': 500,
342
+ 'trigger': true,
343
+ 'trailing': false,
344
+ 'symbolRequired': false,
345
+ },
346
+ 'fetchOrders': undefined,
347
+ 'fetchClosedOrders': {
348
+ 'marginMode': false,
349
+ 'limit': 500,
350
+ 'daysBack': undefined,
351
+ 'daysBackCanceled': undefined,
352
+ 'untilDays': 100000,
353
+ 'trigger': true,
354
+ 'trailing': false,
355
+ 'symbolRequired': false,
356
+ },
357
+ 'fetchOHLCV': {
358
+ 'limit': 1000,
359
+ },
360
+ },
361
+ 'spot': {
362
+ 'extends': 'default',
363
+ },
364
+ 'forDerivatives': {
365
+ 'extends': 'default',
366
+ 'createOrder': {
367
+ // todo: implementation needs unification
368
+ 'triggerPriceType': undefined,
369
+ 'attachedStopLossTakeProfit': {
370
+ // todo: implementation needs unification
371
+ 'triggerPriceType': undefined,
372
+ 'price': false,
373
+ },
374
+ },
375
+ },
376
+ 'swap': {
377
+ 'linear': {
378
+ 'extends': 'forDerivatives',
379
+ },
380
+ 'inverse': undefined,
381
+ },
382
+ 'future': {
383
+ 'linear': undefined,
384
+ 'inverse': undefined,
385
+ },
386
+ },
387
+ 'commonCurrencies': {},
388
+ 'exceptions': {
389
+ 'exact': {
390
+ '-1000': errors.ExchangeError,
391
+ '-1001': errors.AuthenticationError,
392
+ '-1002': errors.AuthenticationError,
393
+ '-1003': errors.RateLimitExceeded,
394
+ '-1004': errors.BadRequest,
395
+ '-1005': errors.BadRequest,
396
+ '-1006': errors.InvalidOrder,
397
+ '-1007': errors.BadRequest,
398
+ '-1008': errors.InvalidOrder,
399
+ '-1009': errors.InsufficientFunds,
400
+ '-1011': errors.NetworkError,
401
+ '-1012': errors.BadRequest,
402
+ '-1101': errors.InsufficientFunds,
403
+ '-1102': errors.InvalidOrder,
404
+ '-1103': errors.InvalidOrder,
405
+ '-1104': errors.InvalidOrder,
406
+ '-1105': errors.InvalidOrder,
407
+ '-1201': errors.BadRequest,
408
+ '-1202': errors.BadRequest,
409
+ '29': errors.BadRequest,
410
+ '9': errors.AuthenticationError,
411
+ '3': errors.AuthenticationError,
412
+ '2': errors.BadRequest,
413
+ '15': errors.BadRequest, // {"success":false,"code":15,"message":"BrokerId is not exist"}
414
+ },
415
+ 'broad': {},
416
+ },
417
+ 'precisionMode': number.TICK_SIZE,
418
+ });
419
+ }
420
+ setSandboxMode(enable) {
421
+ super.setSandboxMode(enable);
422
+ this.options['sandboxMode'] = enable;
423
+ }
424
+ /**
425
+ * @method
426
+ * @name modetrade#fetchStatus
427
+ * @description the latest known information on the availability of the exchange API
428
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-system-maintenance-status
429
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
430
+ * @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure}
431
+ */
432
+ async fetchStatus(params = {}) {
433
+ const response = await this.v1PublicGetPublicSystemInfo(params);
434
+ //
435
+ // {
436
+ // "success": true,
437
+ // "data": {
438
+ // "status": 0,
439
+ // "msg": "System is functioning properly."
440
+ // },
441
+ // "timestamp": "1709274106602"
442
+ // }
443
+ //
444
+ const data = this.safeDict(response, 'data', {});
445
+ let status = this.safeString(data, 'status');
446
+ if (status === undefined) {
447
+ status = 'error';
448
+ }
449
+ else if (status === '0') {
450
+ status = 'ok';
451
+ }
452
+ else {
453
+ status = 'maintenance';
454
+ }
455
+ return {
456
+ 'status': status,
457
+ 'updated': undefined,
458
+ 'eta': undefined,
459
+ 'url': undefined,
460
+ 'info': response,
461
+ };
462
+ }
463
+ /**
464
+ * @method
465
+ * @name modetrade#fetchTime
466
+ * @description fetches the current integer timestamp in milliseconds from the exchange server
467
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-system-maintenance-status
468
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
469
+ * @returns {int} the current integer timestamp in milliseconds from the exchange server
470
+ */
471
+ async fetchTime(params = {}) {
472
+ const response = await this.v1PublicGetPublicSystemInfo(params);
473
+ //
474
+ // {
475
+ // "success": true,
476
+ // "data": {
477
+ // "status": 0,
478
+ // "msg": "System is functioning properly."
479
+ // },
480
+ // "timestamp": "1709274106602"
481
+ // }
482
+ //
483
+ return this.safeInteger(response, 'timestamp');
484
+ }
485
+ parseMarket(market) {
486
+ //
487
+ // {
488
+ // "symbol": "PERP_BTC_USDC",
489
+ // "quote_min": 123,
490
+ // "quote_max": 100000,
491
+ // "quote_tick": 0.1,
492
+ // "base_min": 0.00001,
493
+ // "base_max": 20,
494
+ // "base_tick": 0.00001,
495
+ // "min_notional": 1,
496
+ // "price_range": 0.02,
497
+ // "price_scope": 0.4,
498
+ // "std_liquidation_fee": 0.03,
499
+ // "liquidator_fee": 0.015,
500
+ // "claim_insurance_fund_discount": 0.0075,
501
+ // "funding_period": 8,
502
+ // "cap_funding": 0.000375,
503
+ // "floor_funding": -0.000375,
504
+ // "interest_rate": 0.0001,
505
+ // "created_time": 1684140107326,
506
+ // "updated_time": 1685345968053,
507
+ // "base_mmr": 0.05,
508
+ // "base_imr": 0.1,
509
+ // "imr_factor": 0.0002512,
510
+ // "liquidation_tier": "1"
511
+ // }
512
+ //
513
+ const marketId = this.safeString(market, 'symbol');
514
+ const parts = marketId.split('_');
515
+ const marketType = 'swap';
516
+ const baseId = this.safeString(parts, 1);
517
+ const quoteId = this.safeString(parts, 2);
518
+ const base = this.safeCurrencyCode(baseId);
519
+ const quote = this.safeCurrencyCode(quoteId);
520
+ const settleId = this.safeString(parts, 2);
521
+ const settle = this.safeCurrencyCode(settleId);
522
+ const symbol = base + '/' + quote + ':' + settle;
523
+ return {
524
+ 'id': marketId,
525
+ 'symbol': symbol,
526
+ 'base': base,
527
+ 'quote': quote,
528
+ 'settle': settle,
529
+ 'baseId': baseId,
530
+ 'quoteId': quoteId,
531
+ 'settleId': settleId,
532
+ 'type': marketType,
533
+ 'spot': false,
534
+ 'margin': false,
535
+ 'swap': true,
536
+ 'future': false,
537
+ 'option': false,
538
+ 'active': undefined,
539
+ 'contract': true,
540
+ 'linear': true,
541
+ 'inverse': false,
542
+ 'contractSize': this.parseNumber('1'),
543
+ 'expiry': undefined,
544
+ 'expiryDatetime': undefined,
545
+ 'strike': undefined,
546
+ 'optionType': undefined,
547
+ 'precision': {
548
+ 'amount': this.safeNumber(market, 'base_tick'),
549
+ 'price': this.safeNumber(market, 'quote_tick'),
550
+ },
551
+ 'limits': {
552
+ 'leverage': {
553
+ 'min': undefined,
554
+ 'max': undefined,
555
+ },
556
+ 'amount': {
557
+ 'min': this.safeNumber(market, 'base_min'),
558
+ 'max': this.safeNumber(market, 'base_max'),
559
+ },
560
+ 'price': {
561
+ 'min': this.safeNumber(market, 'quote_min'),
562
+ 'max': this.safeNumber(market, 'quote_max'),
563
+ },
564
+ 'cost': {
565
+ 'min': this.safeNumber(market, 'min_notional'),
566
+ 'max': undefined,
567
+ },
568
+ },
569
+ 'created': this.safeInteger(market, 'created_time'),
570
+ 'info': market,
571
+ };
572
+ }
573
+ /**
574
+ * @method
575
+ * @name modetrade#fetchMarkets
576
+ * @description retrieves data on all markets for modetrade
577
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-available-symbols
578
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
579
+ * @returns {object[]} an array of objects representing market data
580
+ */
581
+ async fetchMarkets(params = {}) {
582
+ const response = await this.v1PublicGetPublicInfo(params);
583
+ //
584
+ // {
585
+ // "success": true,
586
+ // "timestamp": 1702989203989,
587
+ // "data": {
588
+ // "rows": [
589
+ // {
590
+ // "symbol": "PERP_BTC_USDC",
591
+ // "quote_min": 123,
592
+ // "quote_max": 100000,
593
+ // "quote_tick": 0.1,
594
+ // "base_min": 0.00001,
595
+ // "base_max": 20,
596
+ // "base_tick": 0.00001,
597
+ // "min_notional": 1,
598
+ // "price_range": 0.02,
599
+ // "price_scope": 0.4,
600
+ // "std_liquidation_fee": 0.03,
601
+ // "liquidator_fee": 0.015,
602
+ // "claim_insurance_fund_discount": 0.0075,
603
+ // "funding_period": 8,
604
+ // "cap_funding": 0.000375,
605
+ // "floor_funding": -0.000375,
606
+ // "interest_rate": 0.0001,
607
+ // "created_time": 1684140107326,
608
+ // "updated_time": 1685345968053,
609
+ // "base_mmr": 0.05,
610
+ // "base_imr": 0.1,
611
+ // "imr_factor": 0.0002512,
612
+ // "liquidation_tier": "1"
613
+ // }
614
+ // ]
615
+ // }
616
+ // }
617
+ //
618
+ const data = this.safeDict(response, 'data', {});
619
+ const rows = this.safeList(data, 'rows', []);
620
+ return this.parseMarkets(rows);
621
+ }
622
+ /**
623
+ * @method
624
+ * @name modetrade#fetchCurrencies
625
+ * @description fetches all available currencies on an exchange
626
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-token-info
627
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
628
+ * @returns {object} an associative dictionary of currencies
629
+ */
630
+ async fetchCurrencies(params = {}) {
631
+ const result = {};
632
+ const response = await this.v1PublicGetPublicToken(params);
633
+ //
634
+ // {
635
+ // "success": true,
636
+ // "timestamp": 1702989203989,
637
+ // "data": {
638
+ // "rows": [{
639
+ // "token": "USDC",
640
+ // "decimals": 6,
641
+ // "minimum_withdraw_amount": 0.000001,
642
+ // "token_hash": "0xd6aca1be9729c13d677335161321649cccae6a591554772516700f986f942eaa",
643
+ // "chain_details": [{
644
+ // "chain_id": 43113,
645
+ // "contract_address": "0x5d64c9cfb0197775b4b3ad9be4d3c7976e0d8dc3",
646
+ // "cross_chain_withdrawal_fee": 123,
647
+ // "decimals": 6,
648
+ // "withdraw_fee": 2
649
+ // }]
650
+ // }
651
+ // ]
652
+ // }
653
+ // }
654
+ //
655
+ const data = this.safeDict(response, 'data', {});
656
+ const tokenRows = this.safeList(data, 'rows', []);
657
+ for (let i = 0; i < tokenRows.length; i++) {
658
+ const token = tokenRows[i];
659
+ const currencyId = this.safeString(token, 'token');
660
+ const networks = this.safeList(token, 'chain_details');
661
+ const code = this.safeCurrencyCode(currencyId);
662
+ let minPrecision = undefined;
663
+ const resultingNetworks = {};
664
+ for (let j = 0; j < networks.length; j++) {
665
+ const network = networks[j];
666
+ // TODO: transform chain id to human readable name
667
+ const networkId = this.safeString(network, 'chain_id');
668
+ const precision = this.parsePrecision(this.safeString(network, 'decimals'));
669
+ if (precision !== undefined) {
670
+ minPrecision = (minPrecision === undefined) ? precision : Precise["default"].stringMin(precision, minPrecision);
671
+ }
672
+ resultingNetworks[networkId] = {
673
+ 'id': networkId,
674
+ 'network': networkId,
675
+ 'limits': {
676
+ 'withdraw': {
677
+ 'min': undefined,
678
+ 'max': undefined,
679
+ },
680
+ 'deposit': {
681
+ 'min': undefined,
682
+ 'max': undefined,
683
+ },
684
+ },
685
+ 'active': undefined,
686
+ 'deposit': undefined,
687
+ 'withdraw': undefined,
688
+ 'fee': this.safeNumber(network, 'withdrawal_fee'),
689
+ 'precision': this.parseNumber(precision),
690
+ 'info': network,
691
+ };
692
+ }
693
+ result[code] = this.safeCurrencyStructure({
694
+ 'id': currencyId,
695
+ 'name': currencyId,
696
+ 'code': code,
697
+ 'precision': this.parseNumber(minPrecision),
698
+ 'active': undefined,
699
+ 'fee': undefined,
700
+ 'networks': resultingNetworks,
701
+ 'deposit': undefined,
702
+ 'withdraw': undefined,
703
+ 'limits': {
704
+ 'deposit': {
705
+ 'min': undefined,
706
+ 'max': undefined,
707
+ },
708
+ 'withdraw': {
709
+ 'min': this.safeNumber(token, 'minimum_withdraw_amount'),
710
+ 'max': undefined,
711
+ },
712
+ },
713
+ 'info': token,
714
+ });
715
+ }
716
+ return result;
717
+ }
718
+ parseTokenAndFeeTemp(item, feeTokenKey, feeAmountKey) {
719
+ const feeCost = this.safeString(item, feeAmountKey);
720
+ let fee = undefined;
721
+ if (feeCost !== undefined) {
722
+ const feeCurrencyId = this.safeString(item, feeTokenKey);
723
+ const feeCurrencyCode = this.safeCurrencyCode(feeCurrencyId);
724
+ fee = {
725
+ 'cost': feeCost,
726
+ 'currency': feeCurrencyCode,
727
+ };
728
+ }
729
+ return fee;
730
+ }
731
+ parseTrade(trade, market = undefined) {
732
+ //
733
+ // public/market_trades
734
+ //
735
+ // {
736
+ // "symbol": "PERP_ETH_USDC",
737
+ // "side": "SELL",
738
+ // "executed_price": 46222.35,
739
+ // "executed_quantity": 0.0012,
740
+ // "executed_timestamp": "1683878609166"
741
+ // }
742
+ //
743
+ // fetchOrderTrades, fetchOrder
744
+ //
745
+ // {
746
+ // "id": "99119876",
747
+ // "symbol": "PERP_BTC_USDC",
748
+ // "fee": "0.0024",
749
+ // "side": "BUY",
750
+ // "executed_timestamp": "1641481113084",
751
+ // "order_id": "87001234",
752
+ // "order_tag": "default", <-- this param only in "fetchOrderTrades"
753
+ // "executed_price": "1",
754
+ // "executed_quantity": "12",
755
+ // "fee_asset": "BTC",
756
+ // "is_maker": "1"
757
+ // }
758
+ //
759
+ const isFromFetchOrder = ('id' in trade);
760
+ const timestamp = this.safeInteger(trade, 'executed_timestamp');
761
+ const marketId = this.safeString(trade, 'symbol');
762
+ market = this.safeMarket(marketId, market);
763
+ const symbol = market['symbol'];
764
+ const price = this.safeString(trade, 'executed_price');
765
+ const amount = this.safeString(trade, 'executed_quantity');
766
+ const order_id = this.safeString(trade, 'order_id');
767
+ const fee = this.parseTokenAndFeeTemp(trade, 'fee_asset', 'fee');
768
+ const feeCost = this.safeString(fee, 'cost');
769
+ if (feeCost !== undefined) {
770
+ fee['cost'] = feeCost;
771
+ }
772
+ const cost = Precise["default"].stringMul(price, amount);
773
+ const side = this.safeStringLower(trade, 'side');
774
+ const id = this.safeString(trade, 'id');
775
+ let takerOrMaker = undefined;
776
+ if (isFromFetchOrder) {
777
+ const isMaker = this.safeString(trade, 'is_maker') === '1';
778
+ takerOrMaker = isMaker ? 'maker' : 'taker';
779
+ }
780
+ return this.safeTrade({
781
+ 'id': id,
782
+ 'timestamp': timestamp,
783
+ 'datetime': this.iso8601(timestamp),
784
+ 'symbol': symbol,
785
+ 'side': side,
786
+ 'price': price,
787
+ 'amount': amount,
788
+ 'cost': cost,
789
+ 'order': order_id,
790
+ 'takerOrMaker': takerOrMaker,
791
+ 'type': undefined,
792
+ 'fee': fee,
793
+ 'info': trade,
794
+ }, market);
795
+ }
796
+ /**
797
+ * @method
798
+ * @name modetrade#fetchTrades
799
+ * @description get the list of most recent trades for a particular symbol
800
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-market-trades
801
+ * @param {string} symbol unified symbol of the market to fetch trades for
802
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
803
+ * @param {int} [limit] the maximum amount of trades to fetch
804
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
805
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
806
+ */
807
+ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
808
+ await this.loadMarkets();
809
+ const market = this.market(symbol);
810
+ const request = {
811
+ 'symbol': market['id'],
812
+ };
813
+ if (limit !== undefined) {
814
+ request['limit'] = limit;
815
+ }
816
+ const response = await this.v1PublicGetPublicMarketTrades(this.extend(request, params));
817
+ //
818
+ // {
819
+ // "success": true,
820
+ // "timestamp": 1702989203989,
821
+ // "data": {
822
+ // "rows": [{
823
+ // "symbol": "PERP_ETH_USDC",
824
+ // "side": "BUY",
825
+ // "executed_price": 2050,
826
+ // "executed_quantity": 1,
827
+ // "executed_timestamp": 1683878609166
828
+ // }]
829
+ // }
830
+ // }
831
+ //
832
+ const data = this.safeDict(response, 'data', {});
833
+ const rows = this.safeList(data, 'rows', []);
834
+ return this.parseTrades(rows, market, since, limit);
835
+ }
836
+ parseFundingRate(fundingRate, market = undefined) {
837
+ //
838
+ // {
839
+ // "symbol":"PERP_AAVE_USDT",
840
+ // "est_funding_rate":-0.00003447,
841
+ // "est_funding_rate_timestamp":1653633959001,
842
+ // "last_funding_rate":-0.00002094,
843
+ // "last_funding_rate_timestamp":1653631200000,
844
+ // "next_funding_time":1653634800000,
845
+ // "sum_unitary_funding": 521.367
846
+ // }
847
+ //
848
+ const symbol = this.safeString(fundingRate, 'symbol');
849
+ market = this.market(symbol);
850
+ const nextFundingTimestamp = this.safeInteger(fundingRate, 'next_funding_time');
851
+ const estFundingRateTimestamp = this.safeInteger(fundingRate, 'est_funding_rate_timestamp');
852
+ const lastFundingRateTimestamp = this.safeInteger(fundingRate, 'last_funding_rate_timestamp');
853
+ const fundingTimeString = this.safeString(fundingRate, 'last_funding_rate_timestamp');
854
+ const nextFundingTimeString = this.safeString(fundingRate, 'next_funding_time');
855
+ const millisecondsInterval = Precise["default"].stringSub(nextFundingTimeString, fundingTimeString);
856
+ return {
857
+ 'info': fundingRate,
858
+ 'symbol': market['symbol'],
859
+ 'markPrice': undefined,
860
+ 'indexPrice': undefined,
861
+ 'interestRate': this.parseNumber('0'),
862
+ 'estimatedSettlePrice': undefined,
863
+ 'timestamp': estFundingRateTimestamp,
864
+ 'datetime': this.iso8601(estFundingRateTimestamp),
865
+ 'fundingRate': this.safeNumber(fundingRate, 'est_funding_rate'),
866
+ 'fundingTimestamp': nextFundingTimestamp,
867
+ 'fundingDatetime': this.iso8601(nextFundingTimestamp),
868
+ 'nextFundingRate': undefined,
869
+ 'nextFundingTimestamp': undefined,
870
+ 'nextFundingDatetime': undefined,
871
+ 'previousFundingRate': this.safeNumber(fundingRate, 'last_funding_rate'),
872
+ 'previousFundingTimestamp': lastFundingRateTimestamp,
873
+ 'previousFundingDatetime': this.iso8601(lastFundingRateTimestamp),
874
+ 'interval': this.parseFundingInterval(millisecondsInterval),
875
+ };
876
+ }
877
+ parseFundingInterval(interval) {
878
+ const intervals = {
879
+ '3600000': '1h',
880
+ '14400000': '4h',
881
+ '28800000': '8h',
882
+ '57600000': '16h',
883
+ '86400000': '24h',
884
+ };
885
+ return this.safeString(intervals, interval, interval);
886
+ }
887
+ /**
888
+ * @method
889
+ * @name modetrade#fetchFundingInterval
890
+ * @description fetch the current funding rate interval
891
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-predicted-funding-rate-for-one-market
892
+ * @param {string} symbol unified market symbol
893
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
894
+ * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
895
+ */
896
+ async fetchFundingInterval(symbol, params = {}) {
897
+ return await this.fetchFundingRate(symbol, params);
898
+ }
899
+ /**
900
+ * @method
901
+ * @name modetrade#fetchFundingRate
902
+ * @description fetch the current funding rate
903
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-predicted-funding-rate-for-one-market
904
+ * @param {string} symbol unified market symbol
905
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
906
+ * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
907
+ */
908
+ async fetchFundingRate(symbol, params = {}) {
909
+ await this.loadMarkets();
910
+ const market = this.market(symbol);
911
+ const request = {
912
+ 'symbol': market['id'],
913
+ };
914
+ const response = await this.v1PublicGetPublicFundingRateSymbol(this.extend(request, params));
915
+ //
916
+ // {
917
+ // "success": true,
918
+ // "timestamp": 1702989203989,
919
+ // "data": {
920
+ // "symbol": "PERP_ETH_USDC",
921
+ // "est_funding_rate": 123,
922
+ // "est_funding_rate_timestamp": 1683880020000,
923
+ // "last_funding_rate": 0.0001,
924
+ // "last_funding_rate_timestamp": 1683878400000,
925
+ // "next_funding_time": 1683907200000,
926
+ // "sum_unitary_funding": 521.367
927
+ // }
928
+ // }
929
+ //
930
+ const data = this.safeDict(response, 'data', {});
931
+ return this.parseFundingRate(data, market);
932
+ }
933
+ /**
934
+ * @method
935
+ * @name modetrade#fetchFundingRates
936
+ * @description fetch the current funding rate for multiple markets
937
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-predicted-funding-rates-for-all-markets
938
+ * @param {string[]} symbols unified market symbols
939
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
940
+ * @returns {object[]} an array of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
941
+ */
942
+ async fetchFundingRates(symbols = undefined, params = {}) {
943
+ await this.loadMarkets();
944
+ symbols = this.marketSymbols(symbols);
945
+ const response = await this.v1PublicGetPublicFundingRates(params);
946
+ //
947
+ // {
948
+ // "success": true,
949
+ // "timestamp": 1702989203989,
950
+ // "data": {
951
+ // "rows": [{
952
+ // "symbol": "PERP_ETH_USDC",
953
+ // "est_funding_rate": 123,
954
+ // "est_funding_rate_timestamp": 1683880020000,
955
+ // "last_funding_rate": 0.0001,
956
+ // "last_funding_rate_timestamp": 1683878400000,
957
+ // "next_funding_time": 1683907200000,
958
+ // "sum_unitary_funding": 521.367
959
+ // }]
960
+ // }
961
+ // }
962
+ //
963
+ const data = this.safeDict(response, 'data', {});
964
+ const rows = this.safeList(data, 'rows', []);
965
+ return this.parseFundingRates(rows, symbols);
966
+ }
967
+ /**
968
+ * @method
969
+ * @name modetrade#fetchFundingRateHistory
970
+ * @description fetches historical funding rate prices
971
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-funding-rate-history-for-one-market
972
+ * @param {string} symbol unified symbol of the market to fetch the funding rate history for
973
+ * @param {int} [since] timestamp in ms of the earliest funding rate to fetch
974
+ * @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} to fetch
975
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
976
+ * @param {int} [params.until] timestamp in ms of the latest funding rate
977
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
978
+ * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure}
979
+ */
980
+ async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
981
+ await this.loadMarkets();
982
+ let paginate = false;
983
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchFundingRateHistory', 'paginate');
984
+ if (paginate) {
985
+ return await this.fetchPaginatedCallIncremental('fetchFundingRateHistory', symbol, since, limit, params, 'page', 25);
986
+ }
987
+ let request = {};
988
+ if (symbol !== undefined) {
989
+ const market = this.market(symbol);
990
+ symbol = market['symbol'];
991
+ request['symbol'] = market['id'];
992
+ }
993
+ if (since !== undefined) {
994
+ request['start_t'] = since;
995
+ }
996
+ [request, params] = this.handleUntilOption('end_t', request, params, 0.001);
997
+ const response = await this.v1PublicGetPublicFundingRateHistory(this.extend(request, params));
998
+ //
999
+ // {
1000
+ // "success": true,
1001
+ // "timestamp": 1702989203989,
1002
+ // "data": {
1003
+ // "rows": [{
1004
+ // "symbol": "PERP_ETH_USDC",
1005
+ // "funding_rate": 0.0001,
1006
+ // "funding_rate_timestamp": 1684224000000,
1007
+ // "next_funding_time": 1684252800000
1008
+ // }],
1009
+ // "meta": {
1010
+ // "total": 9,
1011
+ // "records_per_page": 25,
1012
+ // "current_page": 1
1013
+ // }
1014
+ // }
1015
+ // }
1016
+ //
1017
+ const data = this.safeDict(response, 'data', {});
1018
+ const result = this.safeList(data, 'rows', []);
1019
+ const rates = [];
1020
+ for (let i = 0; i < result.length; i++) {
1021
+ const entry = result[i];
1022
+ const marketId = this.safeString(entry, 'symbol');
1023
+ const timestamp = this.safeInteger(entry, 'funding_rate_timestamp');
1024
+ rates.push({
1025
+ 'info': entry,
1026
+ 'symbol': this.safeSymbol(marketId),
1027
+ 'fundingRate': this.safeNumber(entry, 'funding_rate'),
1028
+ 'timestamp': timestamp,
1029
+ 'datetime': this.iso8601(timestamp),
1030
+ });
1031
+ }
1032
+ const sorted = this.sortBy(rates, 'timestamp');
1033
+ return this.filterBySymbolSinceLimit(sorted, symbol, since, limit);
1034
+ }
1035
+ /**
1036
+ * @method
1037
+ * @name modetrade#fetchTradingFees
1038
+ * @description fetch the trading fees for multiple markets
1039
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-account-information
1040
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1041
+ * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols
1042
+ */
1043
+ async fetchTradingFees(params = {}) {
1044
+ await this.loadMarkets();
1045
+ const response = await this.v1PrivateGetClientInfo(params);
1046
+ //
1047
+ // {
1048
+ // "success": true,
1049
+ // "timestamp": 1702989203989,
1050
+ // "data": {
1051
+ // "account_id": "<string>",
1052
+ // "email": "test@test.com",
1053
+ // "account_mode": "FUTURES",
1054
+ // "max_leverage": 20,
1055
+ // "taker_fee_rate": 123,
1056
+ // "maker_fee_rate": 123,
1057
+ // "futures_taker_fee_rate": 123,
1058
+ // "futures_maker_fee_rate": 123,
1059
+ // "maintenance_cancel_orders": true,
1060
+ // "imr_factor": {
1061
+ // "PERP_BTC_USDC": 123,
1062
+ // "PERP_ETH_USDC": 123,
1063
+ // "PERP_NEAR_USDC": 123
1064
+ // },
1065
+ // "max_notional": {
1066
+ // "PERP_BTC_USDC": 123,
1067
+ // "PERP_ETH_USDC": 123,
1068
+ // "PERP_NEAR_USDC": 123
1069
+ // }
1070
+ // }
1071
+ // }
1072
+ //
1073
+ const data = this.safeDict(response, 'data', {});
1074
+ const maker = this.safeString(data, 'futures_maker_fee_rate');
1075
+ const taker = this.safeString(data, 'futures_taker_fee_rate');
1076
+ const result = {};
1077
+ for (let i = 0; i < this.symbols.length; i++) {
1078
+ const symbol = this.symbols[i];
1079
+ result[symbol] = {
1080
+ 'info': response,
1081
+ 'symbol': symbol,
1082
+ 'maker': this.parseNumber(Precise["default"].stringDiv(maker, '10000')),
1083
+ 'taker': this.parseNumber(Precise["default"].stringDiv(taker, '10000')),
1084
+ 'percentage': true,
1085
+ 'tierBased': true,
1086
+ };
1087
+ }
1088
+ return result;
1089
+ }
1090
+ /**
1091
+ * @method
1092
+ * @name modetrade#fetchOrderBook
1093
+ * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
1094
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/orderbook-snapshot
1095
+ * @param {string} symbol unified symbol of the market to fetch the order book for
1096
+ * @param {int} [limit] the maximum amount of order book entries to return
1097
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1098
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
1099
+ */
1100
+ async fetchOrderBook(symbol, limit = undefined, params = {}) {
1101
+ await this.loadMarkets();
1102
+ const market = this.market(symbol);
1103
+ const request = {
1104
+ 'symbol': market['id'],
1105
+ };
1106
+ if (limit !== undefined) {
1107
+ limit = Math.min(limit, 1000);
1108
+ request['max_level'] = limit;
1109
+ }
1110
+ const response = await this.v1PrivateGetOrderbookSymbol(this.extend(request, params));
1111
+ //
1112
+ // {
1113
+ // "success": true,
1114
+ // "timestamp": 1702989203989,
1115
+ // "data": {
1116
+ // "asks": [{
1117
+ // "price": 10669.4,
1118
+ // "quantity": 1.56263218
1119
+ // }],
1120
+ // "bids": [{
1121
+ // "price": 10669.4,
1122
+ // "quantity": 1.56263218
1123
+ // }],
1124
+ // "timestamp": 123
1125
+ // }
1126
+ // }
1127
+ //
1128
+ const data = this.safeDict(response, 'data', {});
1129
+ const timestamp = this.safeInteger(data, 'timestamp');
1130
+ return this.parseOrderBook(data, symbol, timestamp, 'bids', 'asks', 'price', 'quantity');
1131
+ }
1132
+ parseOHLCV(ohlcv, market = undefined) {
1133
+ return [
1134
+ this.safeInteger(ohlcv, 'start_timestamp'),
1135
+ this.safeNumber(ohlcv, 'open'),
1136
+ this.safeNumber(ohlcv, 'high'),
1137
+ this.safeNumber(ohlcv, 'low'),
1138
+ this.safeNumber(ohlcv, 'close'),
1139
+ this.safeNumber(ohlcv, 'volume'),
1140
+ ];
1141
+ }
1142
+ /**
1143
+ * @method
1144
+ * @name modetrade#fetchOHLCV
1145
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-kline
1146
+ * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1147
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
1148
+ * @param {string} timeframe the length of time each candle represents
1149
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
1150
+ * @param {int} [limit] max=1000, max=100 when since is defined and is less than (now - (999 * (timeframe in ms)))
1151
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1152
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
1153
+ */
1154
+ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
1155
+ await this.loadMarkets();
1156
+ const market = this.market(symbol);
1157
+ const request = {
1158
+ 'symbol': market['id'],
1159
+ 'type': this.safeString(this.timeframes, timeframe, timeframe),
1160
+ };
1161
+ if (limit !== undefined) {
1162
+ request['limit'] = Math.min(limit, 1000);
1163
+ }
1164
+ const response = await this.v1PrivateGetKline(this.extend(request, params));
1165
+ const data = this.safeDict(response, 'data', {});
1166
+ //
1167
+ // {
1168
+ // "success": true,
1169
+ // "timestamp": 1702989203989,
1170
+ // "data": {
1171
+ // "rows": [{
1172
+ // "open": 66166.23,
1173
+ // "close": 66124.56,
1174
+ // "low": 66038.06,
1175
+ // "high": 66176.97,
1176
+ // "volume": 23.45528526,
1177
+ // "amount": 1550436.21725288,
1178
+ // "symbol": "PERP_BTC_USDC",
1179
+ // "type": "1m",
1180
+ // "start_timestamp": 1636388220000,
1181
+ // "end_timestamp": 1636388280000
1182
+ // }]
1183
+ // }
1184
+ // }
1185
+ //
1186
+ const rows = this.safeList(data, 'rows', []);
1187
+ return this.parseOHLCVs(rows, market, timeframe, since, limit);
1188
+ }
1189
+ parseOrder(order, market = undefined) {
1190
+ //
1191
+ // Possible input functions:
1192
+ // * createOrder
1193
+ // * createOrders
1194
+ // * cancelOrder
1195
+ // * fetchOrder
1196
+ // * fetchOrders
1197
+ // const isFromFetchOrder = ('order_tag' in order); TO_DO
1198
+ //
1199
+ // stop order after creating it:
1200
+ // {
1201
+ // "orderId": "1578938",
1202
+ // "clientOrderId": "0",
1203
+ // "algoType": "STOP_LOSS",
1204
+ // "quantity": "0.1"
1205
+ // }
1206
+ // stop order after fetching it:
1207
+ // {
1208
+ // "algoOrderId": "1578958",
1209
+ // "clientOrderId": "0",
1210
+ // "rootAlgoOrderId": "1578958",
1211
+ // "parentAlgoOrderId": "0",
1212
+ // "symbol": "SPOT_LTC_USDT",
1213
+ // "orderTag": "default",
1214
+ // "algoType": "STOP_LOSS",
1215
+ // "side": "BUY",
1216
+ // "quantity": "0.1",
1217
+ // "isTriggered": false,
1218
+ // "triggerPrice": "100",
1219
+ // "triggerStatus": "USELESS",
1220
+ // "type": "LIMIT",
1221
+ // "rootAlgoStatus": "CANCELLED",
1222
+ // "algoStatus": "CANCELLED",
1223
+ // "triggerPriceType": "MARKET_PRICE",
1224
+ // "price": "75",
1225
+ // "triggerTime": "0",
1226
+ // "totalExecutedQuantity": "0",
1227
+ // "averageExecutedPrice": "0",
1228
+ // "totalFee": "0",
1229
+ // "feeAsset": '',
1230
+ // "reduceOnly": false,
1231
+ // "createdTime": "1686149609.744",
1232
+ // "updatedTime": "1686149903.362"
1233
+ // }
1234
+ //
1235
+ const timestamp = this.safeIntegerN(order, ['timestamp', 'created_time', 'createdTime']);
1236
+ const orderId = this.safeStringN(order, ['order_id', 'orderId', 'algoOrderId']);
1237
+ const clientOrderId = this.omitZero(this.safeString2(order, 'client_order_id', 'clientOrderId')); // Somehow, this always returns 0 for limit order
1238
+ const marketId = this.safeString(order, 'symbol');
1239
+ market = this.safeMarket(marketId, market);
1240
+ const symbol = market['symbol'];
1241
+ const price = this.safeString2(order, 'order_price', 'price');
1242
+ const amount = this.safeString2(order, 'order_quantity', 'quantity'); // This is base amount
1243
+ const cost = this.safeString2(order, 'order_amount', 'amount'); // This is quote amount
1244
+ const orderType = this.safeStringLower2(order, 'order_type', 'type');
1245
+ let status = this.safeValue2(order, 'status', 'algoStatus');
1246
+ const success = this.safeBool(order, 'success');
1247
+ if (success !== undefined) {
1248
+ status = (success) ? 'NEW' : 'REJECTED';
1249
+ }
1250
+ const side = this.safeStringLower(order, 'side');
1251
+ const filled = this.omitZero(this.safeValue2(order, 'executed', 'totalExecutedQuantity'));
1252
+ const average = this.omitZero(this.safeString2(order, 'average_executed_price', 'averageExecutedPrice'));
1253
+ const remaining = Precise["default"].stringSub(cost, filled);
1254
+ const fee = this.safeValue2(order, 'total_fee', 'totalFee');
1255
+ const feeCurrency = this.safeString2(order, 'fee_asset', 'feeAsset');
1256
+ const transactions = this.safeValue(order, 'Transactions');
1257
+ const triggerPrice = this.safeNumber(order, 'triggerPrice');
1258
+ let takeProfitPrice = undefined;
1259
+ let stopLossPrice = undefined;
1260
+ const childOrders = this.safeValue(order, 'childOrders');
1261
+ if (childOrders !== undefined) {
1262
+ const first = this.safeValue(childOrders, 0);
1263
+ const innerChildOrders = this.safeValue(first, 'childOrders', []);
1264
+ const innerChildOrdersLength = innerChildOrders.length;
1265
+ if (innerChildOrdersLength > 0) {
1266
+ const takeProfitOrder = this.safeValue(innerChildOrders, 0);
1267
+ const stopLossOrder = this.safeValue(innerChildOrders, 1);
1268
+ takeProfitPrice = this.safeNumber(takeProfitOrder, 'triggerPrice');
1269
+ stopLossPrice = this.safeNumber(stopLossOrder, 'triggerPrice');
1270
+ }
1271
+ }
1272
+ const lastUpdateTimestamp = this.safeInteger2(order, 'updatedTime', 'updated_time');
1273
+ return this.safeOrder({
1274
+ 'id': orderId,
1275
+ 'clientOrderId': clientOrderId,
1276
+ 'timestamp': timestamp,
1277
+ 'datetime': this.iso8601(timestamp),
1278
+ 'lastTradeTimestamp': undefined,
1279
+ 'lastUpdateTimestamp': lastUpdateTimestamp,
1280
+ 'status': this.parseOrderStatus(status),
1281
+ 'symbol': symbol,
1282
+ 'type': this.parseOrderType(orderType),
1283
+ 'timeInForce': this.parseTimeInForce(orderType),
1284
+ 'postOnly': undefined,
1285
+ 'reduceOnly': this.safeBool(order, 'reduce_only'),
1286
+ 'side': side,
1287
+ 'price': price,
1288
+ 'triggerPrice': triggerPrice,
1289
+ 'takeProfitPrice': takeProfitPrice,
1290
+ 'stopLossPrice': stopLossPrice,
1291
+ 'average': average,
1292
+ 'amount': amount,
1293
+ 'filled': filled,
1294
+ 'remaining': remaining,
1295
+ 'cost': cost,
1296
+ 'trades': transactions,
1297
+ 'fee': {
1298
+ 'cost': fee,
1299
+ 'currency': feeCurrency,
1300
+ },
1301
+ 'info': order,
1302
+ }, market);
1303
+ }
1304
+ parseTimeInForce(timeInForce) {
1305
+ const timeInForces = {
1306
+ 'ioc': 'IOC',
1307
+ 'fok': 'FOK',
1308
+ 'post_only': 'PO',
1309
+ };
1310
+ return this.safeString(timeInForces, timeInForce, undefined);
1311
+ }
1312
+ parseOrderStatus(status) {
1313
+ if (status !== undefined) {
1314
+ const statuses = {
1315
+ 'NEW': 'open',
1316
+ 'FILLED': 'closed',
1317
+ 'CANCEL_SENT': 'canceled',
1318
+ 'CANCEL_ALL_SENT': 'canceled',
1319
+ 'CANCELLED': 'canceled',
1320
+ 'PARTIAL_FILLED': 'open',
1321
+ 'REJECTED': 'rejected',
1322
+ 'INCOMPLETE': 'open',
1323
+ 'COMPLETED': 'closed',
1324
+ };
1325
+ return this.safeString(statuses, status, status);
1326
+ }
1327
+ return status;
1328
+ }
1329
+ parseOrderType(type) {
1330
+ const types = {
1331
+ 'LIMIT': 'limit',
1332
+ 'MARKET': 'market',
1333
+ 'POST_ONLY': 'limit',
1334
+ };
1335
+ return this.safeStringLower(types, type, type);
1336
+ }
1337
+ createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
1338
+ /**
1339
+ * @method
1340
+ * @ignore
1341
+ * @name modetrade#createOrderRequest
1342
+ * @description helper function to build the request
1343
+ * @param {string} symbol unified symbol of the market to create an order in
1344
+ * @param {string} type 'market' or 'limit'
1345
+ * @param {string} side 'buy' or 'sell'
1346
+ * @param {float} amount how much you want to trade in units of the base currency
1347
+ * @param {float} [price] the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
1348
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1349
+ * @returns {object} request to be sent to the exchange
1350
+ */
1351
+ const reduceOnly = this.safeBool2(params, 'reduceOnly', 'reduce_only');
1352
+ const orderType = type.toUpperCase();
1353
+ const market = this.market(symbol);
1354
+ const orderSide = side.toUpperCase();
1355
+ const request = {
1356
+ 'symbol': market['id'],
1357
+ 'side': orderSide,
1358
+ };
1359
+ const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
1360
+ const stopLoss = this.safeValue(params, 'stopLoss');
1361
+ const takeProfit = this.safeValue(params, 'takeProfit');
1362
+ const algoType = this.safeString(params, 'algoType');
1363
+ const isConditional = triggerPrice !== undefined || stopLoss !== undefined || takeProfit !== undefined || (this.safeValue(params, 'childOrders') !== undefined);
1364
+ const isMarket = orderType === 'MARKET';
1365
+ const timeInForce = this.safeStringLower(params, 'timeInForce');
1366
+ const postOnly = this.isPostOnly(isMarket, undefined, params);
1367
+ const orderQtyKey = isConditional ? 'quantity' : 'order_quantity';
1368
+ const priceKey = isConditional ? 'price' : 'order_price';
1369
+ const typeKey = isConditional ? 'type' : 'order_type';
1370
+ request[typeKey] = orderType; // LIMIT/MARKET/IOC/FOK/POST_ONLY/ASK/BID
1371
+ if (!isConditional) {
1372
+ if (postOnly) {
1373
+ request['order_type'] = 'POST_ONLY';
1374
+ }
1375
+ else if (timeInForce === 'fok') {
1376
+ request['order_type'] = 'FOK';
1377
+ }
1378
+ else if (timeInForce === 'ioc') {
1379
+ request['order_type'] = 'IOC';
1380
+ }
1381
+ }
1382
+ if (reduceOnly) {
1383
+ request['reduce_only'] = reduceOnly;
1384
+ }
1385
+ if (price !== undefined) {
1386
+ request[priceKey] = this.priceToPrecision(symbol, price);
1387
+ }
1388
+ if (isMarket && !isConditional) {
1389
+ request[orderQtyKey] = this.amountToPrecision(symbol, amount);
1390
+ }
1391
+ else if (algoType !== 'POSITIONAL_TP_SL') {
1392
+ request[orderQtyKey] = this.amountToPrecision(symbol, amount);
1393
+ }
1394
+ const clientOrderId = this.safeStringN(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
1395
+ if (clientOrderId !== undefined) {
1396
+ request['client_order_id'] = clientOrderId;
1397
+ }
1398
+ if (triggerPrice !== undefined) {
1399
+ request['trigger_price'] = this.priceToPrecision(symbol, triggerPrice);
1400
+ request['algo_type'] = 'STOP';
1401
+ }
1402
+ else if ((stopLoss !== undefined) || (takeProfit !== undefined)) {
1403
+ request['algo_type'] = 'TP_SL';
1404
+ const outterOrder = {
1405
+ 'symbol': market['id'],
1406
+ 'reduce_only': false,
1407
+ 'algo_type': 'POSITIONAL_TP_SL',
1408
+ 'child_orders': [],
1409
+ };
1410
+ const childOrders = outterOrder['child_orders'];
1411
+ const closeSide = (orderSide === 'BUY') ? 'SELL' : 'BUY';
1412
+ if (stopLoss !== undefined) {
1413
+ const stopLossPrice = this.safeNumber2(stopLoss, 'triggerPrice', 'price', stopLoss);
1414
+ const stopLossOrder = {
1415
+ 'side': closeSide,
1416
+ 'algo_type': 'TP_SL',
1417
+ 'trigger_price': this.priceToPrecision(symbol, stopLossPrice),
1418
+ 'type': 'LIMIT',
1419
+ 'reduce_only': true,
1420
+ };
1421
+ childOrders.push(stopLossOrder);
1422
+ }
1423
+ if (takeProfit !== undefined) {
1424
+ const takeProfitPrice = this.safeNumber2(takeProfit, 'triggerPrice', 'price', takeProfit);
1425
+ const takeProfitOrder = {
1426
+ 'side': closeSide,
1427
+ 'algo_type': 'TP_SL',
1428
+ 'trigger_price': this.priceToPrecision(symbol, takeProfitPrice),
1429
+ 'type': 'LIMIT',
1430
+ 'reduce_only': true,
1431
+ };
1432
+ outterOrder.push(takeProfitOrder);
1433
+ }
1434
+ request['child_orders'] = [outterOrder];
1435
+ }
1436
+ params = this.omit(params, ['reduceOnly', 'reduce_only', 'clOrdID', 'clientOrderId', 'client_order_id', 'postOnly', 'timeInForce', 'stopPrice', 'triggerPrice', 'stopLoss', 'takeProfit']);
1437
+ return this.extend(request, params);
1438
+ }
1439
+ /**
1440
+ * @method
1441
+ * @name modetrade#createOrder
1442
+ * @description create a trade order
1443
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/create-order
1444
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/create-algo-order
1445
+ * @param {string} symbol unified symbol of the market to create an order in
1446
+ * @param {string} type 'market' or 'limit'
1447
+ * @param {string} side 'buy' or 'sell'
1448
+ * @param {float} amount how much of currency you want to trade in units of base currency
1449
+ * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1450
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1451
+ * @param {float} [params.triggerPrice] The price a trigger order is triggered at
1452
+ * @param {object} [params.takeProfit] *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered (perpetual swap markets only)
1453
+ * @param {float} [params.takeProfit.triggerPrice] take profit trigger price
1454
+ * @param {object} [params.stopLoss] *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered (perpetual swap markets only)
1455
+ * @param {float} [params.stopLoss.triggerPrice] stop loss trigger price
1456
+ * @param {float} [params.algoType] 'STOP'or 'TP_SL' or 'POSITIONAL_TP_SL'
1457
+ * @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount
1458
+ * @param {string} [params.clientOrderId] a unique id for the order
1459
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1460
+ */
1461
+ async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
1462
+ await this.loadMarkets();
1463
+ const market = this.market(symbol);
1464
+ const request = this.createOrderRequest(symbol, type, side, amount, price, params);
1465
+ const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
1466
+ const stopLoss = this.safeValue(params, 'stopLoss');
1467
+ const takeProfit = this.safeValue(params, 'takeProfit');
1468
+ const isConditional = triggerPrice !== undefined || stopLoss !== undefined || takeProfit !== undefined || (this.safeValue(params, 'childOrders') !== undefined);
1469
+ let response = undefined;
1470
+ if (isConditional) {
1471
+ response = await this.v1PrivatePostAlgoOrder(request);
1472
+ //
1473
+ // {
1474
+ // "success": true,
1475
+ // "timestamp": 1702989203989,
1476
+ // "data": {
1477
+ // "order_id": 13,
1478
+ // "client_order_id": "testclientid",
1479
+ // "algo_type": "STOP",
1480
+ // "quantity": 100.12
1481
+ // }
1482
+ // }
1483
+ //
1484
+ }
1485
+ else {
1486
+ response = await this.v1PrivatePostOrder(request);
1487
+ //
1488
+ // {
1489
+ // "success": true,
1490
+ // "timestamp": 1702989203989,
1491
+ // "data": {
1492
+ // "order_id": 13,
1493
+ // "client_order_id": "testclientid",
1494
+ // "order_type": "LIMIT",
1495
+ // "order_price": 100.12,
1496
+ // "order_quantity": 0.987654,
1497
+ // "order_amount": 0.8,
1498
+ // "error_message": "none"
1499
+ // }
1500
+ // }
1501
+ //
1502
+ }
1503
+ const data = this.safeDict(response, 'data');
1504
+ data['timestamp'] = this.safeInteger(response, 'timestamp');
1505
+ const order = this.parseOrder(data, market);
1506
+ order['type'] = type;
1507
+ return order;
1508
+ }
1509
+ /**
1510
+ * @method
1511
+ * @name modetrade#createOrders
1512
+ * @description *contract only* create a list of trade orders
1513
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/batch-create-order
1514
+ * @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
1515
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1516
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1517
+ */
1518
+ async createOrders(orders, params = {}) {
1519
+ await this.loadMarkets();
1520
+ const ordersRequests = [];
1521
+ for (let i = 0; i < orders.length; i++) {
1522
+ const rawOrder = orders[i];
1523
+ const marketId = this.safeString(rawOrder, 'symbol');
1524
+ const type = this.safeString(rawOrder, 'type');
1525
+ const side = this.safeString(rawOrder, 'side');
1526
+ const amount = this.safeValue(rawOrder, 'amount');
1527
+ const price = this.safeValue(rawOrder, 'price');
1528
+ const orderParams = this.safeDict(rawOrder, 'params', {});
1529
+ const triggerPrice = this.safeString2(orderParams, 'triggerPrice', 'stopPrice');
1530
+ const stopLoss = this.safeValue(orderParams, 'stopLoss');
1531
+ const takeProfit = this.safeValue(orderParams, 'takeProfit');
1532
+ const isConditional = triggerPrice !== undefined || stopLoss !== undefined || takeProfit !== undefined || (this.safeValue(orderParams, 'childOrders') !== undefined);
1533
+ if (isConditional) {
1534
+ throw new errors.NotSupported(this.id + ' createOrders() only support non-stop order');
1535
+ }
1536
+ const orderRequest = this.createOrderRequest(marketId, type, side, amount, price, orderParams);
1537
+ ordersRequests.push(orderRequest);
1538
+ }
1539
+ const request = {
1540
+ 'orders': ordersRequests,
1541
+ };
1542
+ const response = await this.v1PrivatePostBatchOrder(this.extend(request, params));
1543
+ //
1544
+ // {
1545
+ // "success": true,
1546
+ // "timestamp": 1702989203989,
1547
+ // "data": {
1548
+ // "rows": [{
1549
+ // "order_id": 13,
1550
+ // "client_order_id": "testclientid",
1551
+ // "order_type": "LIMIT",
1552
+ // "order_price": 100.12,
1553
+ // "order_quantity": 0.987654,
1554
+ // "order_amount": 0.8,
1555
+ // "error_message": "none"
1556
+ // }]
1557
+ // }
1558
+ // }
1559
+ //
1560
+ const data = this.safeDict(response, 'data', {});
1561
+ const rows = this.safeList(data, 'rows', []);
1562
+ return this.parseOrders(rows);
1563
+ }
1564
+ /**
1565
+ * @method
1566
+ * @name modetrade#editOrder
1567
+ * @description edit a trade order
1568
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/edit-order
1569
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/edit-algo-order
1570
+ * @param {string} id order id
1571
+ * @param {string} symbol unified symbol of the market to create an order in
1572
+ * @param {string} type 'market' or 'limit'
1573
+ * @param {string} side 'buy' or 'sell'
1574
+ * @param {float} amount how much of currency you want to trade in units of base currency
1575
+ * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1576
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1577
+ * @param {float} [params.triggerPrice] The price a trigger order is triggered at
1578
+ * @param {float} [params.stopLossPrice] price to trigger stop-loss orders
1579
+ * @param {float} [params.takeProfitPrice] price to trigger take-profit orders
1580
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1581
+ */
1582
+ async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
1583
+ await this.loadMarkets();
1584
+ const market = this.market(symbol);
1585
+ const request = {
1586
+ 'order_id': id,
1587
+ };
1588
+ const triggerPrice = this.safeStringN(params, ['triggerPrice', 'stopPrice', 'takeProfitPrice', 'stopLossPrice']);
1589
+ if (triggerPrice !== undefined) {
1590
+ request['triggerPrice'] = this.priceToPrecision(symbol, triggerPrice);
1591
+ }
1592
+ const isConditional = (triggerPrice !== undefined) || (this.safeValue(params, 'childOrders') !== undefined);
1593
+ const orderQtyKey = isConditional ? 'quantity' : 'order_quantity';
1594
+ const priceKey = isConditional ? 'price' : 'order_price';
1595
+ if (price !== undefined) {
1596
+ request[priceKey] = this.priceToPrecision(symbol, price);
1597
+ }
1598
+ if (amount !== undefined) {
1599
+ request[orderQtyKey] = this.amountToPrecision(symbol, amount);
1600
+ }
1601
+ params = this.omit(params, ['stopPrice', 'triggerPrice', 'takeProfitPrice', 'stopLossPrice', 'trailingTriggerPrice', 'trailingAmount', 'trailingPercent']);
1602
+ let response = undefined;
1603
+ if (isConditional) {
1604
+ response = await this.v1PrivatePutAlgoOrder(this.extend(request, params));
1605
+ }
1606
+ else {
1607
+ request['symbol'] = market['id'];
1608
+ request['side'] = side.toUpperCase();
1609
+ const orderType = type.toUpperCase();
1610
+ const timeInForce = this.safeStringLower(params, 'timeInForce');
1611
+ const isMarket = orderType === 'MARKET';
1612
+ const postOnly = this.isPostOnly(isMarket, undefined, params);
1613
+ if (postOnly) {
1614
+ request['order_type'] = 'POST_ONLY';
1615
+ }
1616
+ else if (timeInForce === 'fok') {
1617
+ request['order_type'] = 'FOK';
1618
+ }
1619
+ else if (timeInForce === 'ioc') {
1620
+ request['order_type'] = 'IOC';
1621
+ }
1622
+ else {
1623
+ request['order_type'] = orderType;
1624
+ }
1625
+ const clientOrderId = this.safeStringN(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
1626
+ params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id', 'postOnly', 'timeInForce']);
1627
+ if (clientOrderId !== undefined) {
1628
+ request['client_order_id'] = clientOrderId;
1629
+ }
1630
+ // request['side'] = side.toUpperCase ();
1631
+ // request['symbol'] = market['id'];
1632
+ response = await this.v1PrivatePutOrder(this.extend(request, params));
1633
+ }
1634
+ //
1635
+ // {
1636
+ // "success": true,
1637
+ // "timestamp": 1702989203989,
1638
+ // "data": {
1639
+ // "status": "EDIT_SENT"
1640
+ // }
1641
+ // }
1642
+ //
1643
+ const data = this.safeDict(response, 'data', {});
1644
+ data['timestamp'] = this.safeInteger(response, 'timestamp');
1645
+ return this.parseOrder(data, market);
1646
+ }
1647
+ /**
1648
+ * @method
1649
+ * @name modetrade#cancelOrder
1650
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/cancel-order
1651
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/cancel-order-by-client_order_id
1652
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/cancel-algo-order
1653
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/cancel-algo-order-by-client_order_id
1654
+ * @description cancels an open order
1655
+ * @param {string} id order id
1656
+ * @param {string} symbol unified symbol of the market the order was made in
1657
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1658
+ * @param {boolean} [params.trigger] whether the order is a stop/algo order
1659
+ * @param {string} [params.clientOrderId] a unique id for the order
1660
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1661
+ */
1662
+ async cancelOrder(id, symbol = undefined, params = {}) {
1663
+ const trigger = this.safeBool2(params, 'stop', 'trigger', false);
1664
+ params = this.omit(params, ['stop', 'trigger']);
1665
+ if (!trigger && (symbol === undefined)) {
1666
+ throw new errors.ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument');
1667
+ }
1668
+ await this.loadMarkets();
1669
+ let market = undefined;
1670
+ if (symbol !== undefined) {
1671
+ market = this.market(symbol);
1672
+ }
1673
+ const request = {
1674
+ 'symbol': market['id'],
1675
+ };
1676
+ const clientOrderIdUnified = this.safeString2(params, 'clOrdID', 'clientOrderId');
1677
+ const clientOrderIdExchangeSpecific = this.safeString(params, 'client_order_id', clientOrderIdUnified);
1678
+ const isByClientOrder = clientOrderIdExchangeSpecific !== undefined;
1679
+ let response = undefined;
1680
+ if (trigger) {
1681
+ if (isByClientOrder) {
1682
+ request['client_order_id'] = clientOrderIdExchangeSpecific;
1683
+ params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
1684
+ response = await this.v1PrivateDeleteAlgoClientOrder(this.extend(request, params));
1685
+ }
1686
+ else {
1687
+ request['order_id'] = id;
1688
+ response = await this.v1PrivateDeleteAlgoOrder(this.extend(request, params));
1689
+ }
1690
+ }
1691
+ else {
1692
+ if (isByClientOrder) {
1693
+ request['client_order_id'] = clientOrderIdExchangeSpecific;
1694
+ params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
1695
+ response = await this.v1PrivateDeleteClientOrder(this.extend(request, params));
1696
+ }
1697
+ else {
1698
+ request['order_id'] = id;
1699
+ response = await this.v1PrivateDeleteOrder(this.extend(request, params));
1700
+ }
1701
+ }
1702
+ //
1703
+ // {
1704
+ // "success": true,
1705
+ // "timestamp": 1702989203989,
1706
+ // "data": {
1707
+ // "status": "CANCEL_SENT"
1708
+ // }
1709
+ // }
1710
+ //
1711
+ // {
1712
+ // "success": true,
1713
+ // "timestamp": 1702989203989,
1714
+ // "status": "CANCEL_SENT"
1715
+ // }
1716
+ //
1717
+ const extendParams = { 'symbol': symbol };
1718
+ if (isByClientOrder) {
1719
+ extendParams['client_order_id'] = clientOrderIdExchangeSpecific;
1720
+ }
1721
+ else {
1722
+ extendParams['id'] = id;
1723
+ }
1724
+ if (trigger) {
1725
+ return this.extend(this.parseOrder(response), extendParams);
1726
+ }
1727
+ const data = this.safeDict(response, 'data', {});
1728
+ return this.extend(this.parseOrder(data), extendParams);
1729
+ }
1730
+ /**
1731
+ * @method
1732
+ * @name modetrade#cancelOrders
1733
+ * @description cancel multiple orders
1734
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/batch-cancel-orders
1735
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/batch-cancel-orders-by-client_order_id
1736
+ * @param {string[]} ids order ids
1737
+ * @param {string} [symbol] unified market symbol
1738
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1739
+ * @param {string[]} [params.client_order_ids] max length 10 e.g. ["my_id_1","my_id_2"], encode the double quotes. No space after comma
1740
+ * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
1741
+ */
1742
+ async cancelOrders(ids, symbol = undefined, params = {}) {
1743
+ await this.loadMarkets();
1744
+ const clientOrderIds = this.safeListN(params, ['clOrdIDs', 'clientOrderIds', 'client_order_ids']);
1745
+ params = this.omit(params, ['clOrdIDs', 'clientOrderIds', 'client_order_ids']);
1746
+ const request = {};
1747
+ let response = undefined;
1748
+ if (clientOrderIds) {
1749
+ request['client_order_ids'] = clientOrderIds.join(',');
1750
+ response = await this.v1PrivateDeleteClientBatchOrder(this.extend(request, params));
1751
+ }
1752
+ else {
1753
+ request['order_ids'] = ids.join(',');
1754
+ response = await this.v1PrivateDeleteBatchOrder(this.extend(request, params));
1755
+ }
1756
+ //
1757
+ // {
1758
+ // "success": true,
1759
+ // "timestamp": 1702989203989,
1760
+ // "data": {
1761
+ // "status": "CANCEL_ALL_SENT"
1762
+ // }
1763
+ // }
1764
+ //
1765
+ return [this.safeOrder({
1766
+ 'info': response,
1767
+ })];
1768
+ }
1769
+ /**
1770
+ * @method
1771
+ * @name modetrade#cancelAllOrders
1772
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/cancel-all-pending-algo-orders
1773
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/cancel-orders-in-bulk
1774
+ * @description cancel all open orders in a market
1775
+ * @param {string} symbol unified market symbol
1776
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1777
+ * @param {boolean} [params.trigger] whether the order is a stop/algo order
1778
+ * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
1779
+ */
1780
+ async cancelAllOrders(symbol = undefined, params = {}) {
1781
+ await this.loadMarkets();
1782
+ const trigger = this.safeBool2(params, 'stop', 'trigger');
1783
+ params = this.omit(params, ['stop', 'trigger']);
1784
+ const request = {};
1785
+ if (symbol !== undefined) {
1786
+ const market = this.market(symbol);
1787
+ request['symbol'] = market['id'];
1788
+ }
1789
+ let response = undefined;
1790
+ if (trigger) {
1791
+ response = await this.v1PrivateDeleteAlgoOrders(this.extend(request, params));
1792
+ }
1793
+ else {
1794
+ response = await this.v1PrivateDeleteOrders(this.extend(request, params));
1795
+ }
1796
+ // trigger
1797
+ // {
1798
+ // "success": true,
1799
+ // "timestamp": 1702989203989,
1800
+ // "status": "CANCEL_ALL_SENT"
1801
+ // }
1802
+ //
1803
+ // {
1804
+ // "success": true,
1805
+ // "timestamp": 1702989203989,
1806
+ // "data": {
1807
+ // "status": "CANCEL_ALL_SENT"
1808
+ // }
1809
+ // }
1810
+ //
1811
+ return [
1812
+ {
1813
+ 'info': response,
1814
+ },
1815
+ ];
1816
+ }
1817
+ /**
1818
+ * @method
1819
+ * @name modetrade#fetchOrder
1820
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-order-by-order_id
1821
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-order-by-client_order_id
1822
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-algo-order-by-order_id
1823
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-algo-order-by-client_order_id
1824
+ * @description fetches information on an order made by the user
1825
+ * @param {string} id the order id
1826
+ * @param {string} symbol unified symbol of the market the order was made in
1827
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1828
+ * @param {boolean} [params.trigger] whether the order is a stop/algo order
1829
+ * @param {string} [params.clientOrderId] a unique id for the order
1830
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1831
+ */
1832
+ async fetchOrder(id, symbol = undefined, params = {}) {
1833
+ await this.loadMarkets();
1834
+ let market = undefined;
1835
+ if (symbol !== undefined) {
1836
+ market = this.market(symbol);
1837
+ }
1838
+ const trigger = this.safeBool2(params, 'stop', 'trigger', false);
1839
+ const request = {};
1840
+ const clientOrderId = this.safeStringN(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
1841
+ params = this.omit(params, ['stop', 'trigger', 'clOrdID', 'clientOrderId', 'client_order_id']);
1842
+ let response = undefined;
1843
+ if (trigger) {
1844
+ if (clientOrderId) {
1845
+ request['client_order_id'] = clientOrderId;
1846
+ response = await this.v1PrivateGetAlgoClientOrderClientOrderId(this.extend(request, params));
1847
+ }
1848
+ else {
1849
+ request['oid'] = id;
1850
+ response = await this.v1PrivateGetAlgoOrderOid(this.extend(request, params));
1851
+ }
1852
+ }
1853
+ else {
1854
+ if (clientOrderId) {
1855
+ request['client_order_id'] = clientOrderId;
1856
+ response = await this.v1PrivateGetClientOrderClientOrderId(this.extend(request, params));
1857
+ }
1858
+ else {
1859
+ request['oid'] = id;
1860
+ response = await this.v1PrivateGetOrderOid(this.extend(request, params));
1861
+ }
1862
+ }
1863
+ //
1864
+ // {
1865
+ // "success": true,
1866
+ // "timestamp": 1702989203989,
1867
+ // "data": {
1868
+ // "order_id": 78151,
1869
+ // "user_id": 12345,
1870
+ // "price": 0.67772,
1871
+ // "type": "LIMIT",
1872
+ // "quantity": 20,
1873
+ // "amount": 10,
1874
+ // "executed_quantity": 20,
1875
+ // "total_executed_quantity": 20,
1876
+ // "visible_quantity": 1,
1877
+ // "symbol": "PERP_BTC_USDC",
1878
+ // "side": "BUY",
1879
+ // "status": "FILLED",
1880
+ // "total_fee": 0.5,
1881
+ // "fee_asset": "BTC",
1882
+ // "client_order_id": 1,
1883
+ // "average_executed_price": 0.67772,
1884
+ // "created_time": 1653563963000,
1885
+ // "updated_time": 1653564213000,
1886
+ // "realized_pnl": 123
1887
+ // }
1888
+ // }
1889
+ //
1890
+ const orders = this.safeDict(response, 'data', response);
1891
+ return this.parseOrder(orders, market);
1892
+ }
1893
+ /**
1894
+ * @method
1895
+ * @name modetrade#fetchOrders
1896
+ * @description fetches information on multiple orders made by the user
1897
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-orders
1898
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-algo-orders
1899
+ * @param {string} symbol unified market symbol of the market orders were made in
1900
+ * @param {int} [since] the earliest time in ms to fetch orders for
1901
+ * @param {int} [limit] the maximum number of order structures to retrieve
1902
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1903
+ * @param {boolean} [params.trigger] whether the order is a stop/algo order
1904
+ * @param {boolean} [params.is_triggered] whether the order has been triggered (false by default)
1905
+ * @param {string} [params.side] 'buy' or 'sell'
1906
+ * @param {boolean} [params.paginate] set to true if you want to fetch orders with pagination
1907
+ * @param {int} params.until timestamp in ms of the latest order to fetch
1908
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
1909
+ */
1910
+ async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1911
+ await this.loadMarkets();
1912
+ let paginate = false;
1913
+ const isTrigger = this.safeBool2(params, 'stop', 'trigger', false);
1914
+ const maxLimit = (isTrigger) ? 100 : 500;
1915
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchOrders', 'paginate');
1916
+ if (paginate) {
1917
+ return await this.fetchPaginatedCallIncremental('fetchOrders', symbol, since, limit, params, 'page', maxLimit);
1918
+ }
1919
+ let request = {};
1920
+ let market = undefined;
1921
+ params = this.omit(params, ['stop', 'trigger']);
1922
+ if (symbol !== undefined) {
1923
+ market = this.market(symbol);
1924
+ request['symbol'] = market['id'];
1925
+ }
1926
+ if (since !== undefined) {
1927
+ request['start_t'] = since;
1928
+ }
1929
+ if (limit !== undefined) {
1930
+ request['size'] = limit;
1931
+ }
1932
+ else {
1933
+ request['size'] = maxLimit;
1934
+ }
1935
+ if (isTrigger) {
1936
+ request['algo_type'] = 'STOP';
1937
+ }
1938
+ [request, params] = this.handleUntilOption('end_t', request, params);
1939
+ let response = undefined;
1940
+ if (isTrigger) {
1941
+ response = await this.v1PrivateGetAlgoOrders(this.extend(request, params));
1942
+ }
1943
+ else {
1944
+ response = await this.v1PrivateGetOrders(this.extend(request, params));
1945
+ }
1946
+ //
1947
+ // {
1948
+ // "success": true,
1949
+ // "timestamp": 1702989203989,
1950
+ // "data": {
1951
+ // "meta": {
1952
+ // "total": 9,
1953
+ // "records_per_page": 25,
1954
+ // "current_page": 1
1955
+ // },
1956
+ // "rows": [{
1957
+ // "order_id": 78151,
1958
+ // "user_id": 12345,
1959
+ // "price": 0.67772,
1960
+ // "type": "LIMIT",
1961
+ // "quantity": 20,
1962
+ // "amount": 10,
1963
+ // "executed_quantity": 20,
1964
+ // "total_executed_quantity": 20,
1965
+ // "visible_quantity": 1,
1966
+ // "symbol": "PERP_BTC_USDC",
1967
+ // "side": "BUY",
1968
+ // "status": "FILLED",
1969
+ // "total_fee": 0.5,
1970
+ // "fee_asset": "BTC",
1971
+ // "client_order_id": 1,
1972
+ // "average_executed_price": 0.67772,
1973
+ // "created_time": 1653563963000,
1974
+ // "updated_time": 1653564213000,
1975
+ // "realized_pnl": 123
1976
+ // }]
1977
+ // }
1978
+ // }
1979
+ //
1980
+ const data = this.safeValue(response, 'data', response);
1981
+ const orders = this.safeList(data, 'rows');
1982
+ return this.parseOrders(orders, market, since, limit);
1983
+ }
1984
+ /**
1985
+ * @method
1986
+ * @name modetrade#fetchOpenOrders
1987
+ * @description fetches information on multiple orders made by the user
1988
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-orders
1989
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-algo-orders
1990
+ * @param {string} symbol unified market symbol of the market orders were made in
1991
+ * @param {int} [since] the earliest time in ms to fetch orders for
1992
+ * @param {int} [limit] the maximum number of order structures to retrieve
1993
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1994
+ * @param {boolean} [params.trigger] whether the order is a stop/algo order
1995
+ * @param {boolean} [params.is_triggered] whether the order has been triggered (false by default)
1996
+ * @param {string} [params.side] 'buy' or 'sell'
1997
+ * @param {int} params.until timestamp in ms of the latest order to fetch
1998
+ * @param {boolean} [params.paginate] set to true if you want to fetch orders with pagination
1999
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2000
+ */
2001
+ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2002
+ await this.loadMarkets();
2003
+ const extendedParams = this.extend(params, { 'status': 'INCOMPLETE' });
2004
+ return await this.fetchOrders(symbol, since, limit, extendedParams);
2005
+ }
2006
+ /**
2007
+ * @method
2008
+ * @name modetrade#fetchClosedOrders
2009
+ * @description fetches information on multiple orders made by the user
2010
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-orders
2011
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-algo-orders
2012
+ * @param {string} symbol unified market symbol of the market orders were made in
2013
+ * @param {int} [since] the earliest time in ms to fetch orders for
2014
+ * @param {int} [limit] the maximum number of order structures to retrieve
2015
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2016
+ * @param {boolean} [params.trigger] whether the order is a stop/algo order
2017
+ * @param {boolean} [params.is_triggered] whether the order has been triggered (false by default)
2018
+ * @param {string} [params.side] 'buy' or 'sell'
2019
+ * @param {int} params.until timestamp in ms of the latest order to fetch
2020
+ * @param {boolean} [params.paginate] set to true if you want to fetch orders with pagination
2021
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2022
+ */
2023
+ async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2024
+ await this.loadMarkets();
2025
+ const extendedParams = this.extend(params, { 'status': 'COMPLETED' });
2026
+ return await this.fetchOrders(symbol, since, limit, extendedParams);
2027
+ }
2028
+ /**
2029
+ * @method
2030
+ * @name modetrade#fetchOrderTrades
2031
+ * @description fetch all the trades made from a single order
2032
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-all-trades-of-specific-order
2033
+ * @param {string} id order id
2034
+ * @param {string} symbol unified market symbol
2035
+ * @param {int} [since] the earliest time in ms to fetch trades for
2036
+ * @param {int} [limit] the maximum number of trades to retrieve
2037
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2038
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
2039
+ */
2040
+ async fetchOrderTrades(id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
2041
+ await this.loadMarkets();
2042
+ let market = undefined;
2043
+ if (symbol !== undefined) {
2044
+ market = this.market(symbol);
2045
+ }
2046
+ const request = {
2047
+ 'oid': id,
2048
+ };
2049
+ const response = await this.v1PrivateGetOrderOidTrades(this.extend(request, params));
2050
+ //
2051
+ // {
2052
+ // "success": true,
2053
+ // "timestamp": 1702989203989,
2054
+ // "data": {
2055
+ // "rows": [{
2056
+ // "id": 2,
2057
+ // "symbol": "PERP_BTC_USDC",
2058
+ // "fee": 0.0001,
2059
+ // "fee_asset": "USDC",
2060
+ // "side": "BUY",
2061
+ // "order_id": 1,
2062
+ // "executed_price": 123,
2063
+ // "executed_quantity": 0.05,
2064
+ // "executed_timestamp": 1567382401000,
2065
+ // "is_maker": 1,
2066
+ // "realized_pnl": 123
2067
+ // }]
2068
+ // }
2069
+ // }
2070
+ //
2071
+ const data = this.safeDict(response, 'data', {});
2072
+ const trades = this.safeList(data, 'rows', []);
2073
+ return this.parseTrades(trades, market, since, limit, params);
2074
+ }
2075
+ /**
2076
+ * @method
2077
+ * @name modetrade#fetchMyTrades
2078
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-trades
2079
+ * @description fetch all trades made by the user
2080
+ * @param {string} symbol unified market symbol
2081
+ * @param {int} [since] the earliest time in ms to fetch trades for
2082
+ * @param {int} [limit] the maximum number of trades structures to retrieve
2083
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2084
+ * @param {boolean} [params.paginate] set to true if you want to fetch trades with pagination
2085
+ * @param {int} params.until timestamp in ms of the latest trade to fetch
2086
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
2087
+ */
2088
+ async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2089
+ await this.loadMarkets();
2090
+ let paginate = false;
2091
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate');
2092
+ if (paginate) {
2093
+ return await this.fetchPaginatedCallIncremental('fetchMyTrades', symbol, since, limit, params, 'page', 500);
2094
+ }
2095
+ let request = {};
2096
+ let market = undefined;
2097
+ if (symbol !== undefined) {
2098
+ market = this.market(symbol);
2099
+ request['symbol'] = market['id'];
2100
+ }
2101
+ if (since !== undefined) {
2102
+ request['start_t'] = since;
2103
+ }
2104
+ if (limit !== undefined) {
2105
+ request['size'] = limit;
2106
+ }
2107
+ else {
2108
+ request['size'] = 500;
2109
+ }
2110
+ [request, params] = this.handleUntilOption('end_t', request, params);
2111
+ const response = await this.v1PrivateGetTrades(this.extend(request, params));
2112
+ //
2113
+ // {
2114
+ // "success": true,
2115
+ // "timestamp": 1702989203989,
2116
+ // "data": {
2117
+ // "meta": {
2118
+ // "total": 9,
2119
+ // "records_per_page": 25,
2120
+ // "current_page": 1
2121
+ // },
2122
+ // "rows": [{
2123
+ // "id": 2,
2124
+ // "symbol": "PERP_BTC_USDC",
2125
+ // "fee": 0.0001,
2126
+ // "fee_asset": "USDC",
2127
+ // "side": "BUY",
2128
+ // "order_id": 1,
2129
+ // "executed_price": 123,
2130
+ // "executed_quantity": 0.05,
2131
+ // "executed_timestamp": 1567382401000,
2132
+ // "is_maker": 1,
2133
+ // "realized_pnl": 123
2134
+ // }]
2135
+ // }
2136
+ // }
2137
+ //
2138
+ const data = this.safeDict(response, 'data', {});
2139
+ const trades = this.safeList(data, 'rows', []);
2140
+ return this.parseTrades(trades, market, since, limit, params);
2141
+ }
2142
+ parseBalance(response) {
2143
+ const result = {
2144
+ 'info': response,
2145
+ };
2146
+ const balances = this.safeList(response, 'holding', []);
2147
+ for (let i = 0; i < balances.length; i++) {
2148
+ const balance = balances[i];
2149
+ const code = this.safeCurrencyCode(this.safeString(balance, 'token'));
2150
+ const account = this.account();
2151
+ account['total'] = this.safeString(balance, 'holding');
2152
+ account['frozen'] = this.safeString(balance, 'frozen');
2153
+ result[code] = account;
2154
+ }
2155
+ return this.safeBalance(result);
2156
+ }
2157
+ /**
2158
+ * @method
2159
+ * @name modetrade#fetchBalance
2160
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
2161
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-current-holding
2162
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2163
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
2164
+ */
2165
+ async fetchBalance(params = {}) {
2166
+ await this.loadMarkets();
2167
+ const response = await this.v1PrivateGetClientHolding(params);
2168
+ //
2169
+ // {
2170
+ // "success": true,
2171
+ // "timestamp": 1702989203989,
2172
+ // "data": {
2173
+ // "holding": [{
2174
+ // "updated_time": 1580794149000,
2175
+ // "token": "BTC",
2176
+ // "holding": -28.000752,
2177
+ // "frozen": 123,
2178
+ // "pending_short": -2000
2179
+ // }]
2180
+ // }
2181
+ // }
2182
+ //
2183
+ const data = this.safeDict(response, 'data');
2184
+ return this.parseBalance(data);
2185
+ }
2186
+ async getAssetHistoryRows(code = undefined, since = undefined, limit = undefined, params = {}) {
2187
+ await this.loadMarkets();
2188
+ const request = {};
2189
+ let currency = undefined;
2190
+ if (code !== undefined) {
2191
+ currency = this.currency(code);
2192
+ request['balance_token'] = currency['id'];
2193
+ }
2194
+ if (since !== undefined) {
2195
+ request['start_t'] = since;
2196
+ }
2197
+ if (limit !== undefined) {
2198
+ request['pageSize'] = limit;
2199
+ }
2200
+ const transactionType = this.safeString(params, 'type');
2201
+ params = this.omit(params, 'type');
2202
+ if (transactionType !== undefined) {
2203
+ request['type'] = transactionType;
2204
+ }
2205
+ const response = await this.v1PrivateGetAssetHistory(this.extend(request, params));
2206
+ //
2207
+ // {
2208
+ // "success": true,
2209
+ // "timestamp": 1702989203989,
2210
+ // "data": {
2211
+ // "meta": {
2212
+ // "total": 9,
2213
+ // "records_per_page": 25,
2214
+ // "current_page": 1
2215
+ // },
2216
+ // "rows": [{
2217
+ // "id": "230707030600002",
2218
+ // "tx_id": "0x4b0714c63cc7abae72bf68e84e25860b88ca651b7d27dad1e32bf4c027fa5326",
2219
+ // "side": "WITHDRAW",
2220
+ // "token": "USDC",
2221
+ // "amount": 555,
2222
+ // "fee": 123,
2223
+ // "trans_status": "FAILED",
2224
+ // "created_time": 1688699193034,
2225
+ // "updated_time": 1688699193096,
2226
+ // "chain_id": "986532"
2227
+ // }]
2228
+ // }
2229
+ // }
2230
+ //
2231
+ const data = this.safeDict(response, 'data', {});
2232
+ return [currency, this.safeList(data, 'rows', [])];
2233
+ }
2234
+ parseLedgerEntry(item, currency = undefined) {
2235
+ const currencyId = this.safeString(item, 'token');
2236
+ const code = this.safeCurrencyCode(currencyId, currency);
2237
+ currency = this.safeCurrency(currencyId, currency);
2238
+ const amount = this.safeNumber(item, 'amount');
2239
+ const side = this.safeString(item, 'token_side');
2240
+ const direction = (side === 'DEPOSIT') ? 'in' : 'out';
2241
+ const timestamp = this.safeInteger(item, 'created_time');
2242
+ const fee = this.parseTokenAndFeeTemp(item, 'fee_token', 'fee_amount');
2243
+ return this.safeLedgerEntry({
2244
+ 'id': this.safeString(item, 'id'),
2245
+ 'currency': code,
2246
+ 'account': this.safeString(item, 'account'),
2247
+ 'referenceAccount': undefined,
2248
+ 'referenceId': this.safeString(item, 'tx_id'),
2249
+ 'status': this.parseTransactionStatus(this.safeString(item, 'status')),
2250
+ 'amount': amount,
2251
+ 'before': undefined,
2252
+ 'after': undefined,
2253
+ 'fee': fee,
2254
+ 'direction': direction,
2255
+ 'timestamp': timestamp,
2256
+ 'datetime': this.iso8601(timestamp),
2257
+ 'type': this.parseLedgerEntryType(this.safeString(item, 'type')),
2258
+ 'info': item,
2259
+ }, currency);
2260
+ }
2261
+ parseLedgerEntryType(type) {
2262
+ const types = {
2263
+ 'BALANCE': 'transaction',
2264
+ 'COLLATERAL': 'transfer', // Funds moved between portfolios
2265
+ };
2266
+ return this.safeString(types, type, type);
2267
+ }
2268
+ /**
2269
+ * @method
2270
+ * @name modetrade#fetchLedger
2271
+ * @description fetch the history of changes, actions done by the user or operations that altered the balance of the user
2272
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-asset-history
2273
+ * @param {string} [code] unified currency code, default is undefined
2274
+ * @param {int} [since] timestamp in ms of the earliest ledger entry, default is undefined
2275
+ * @param {int} [limit] max number of ledger entries to return, default is undefined
2276
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2277
+ * @returns {object} a [ledger structure]{@link https://docs.ccxt.com/#/?id=ledger}
2278
+ */
2279
+ async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
2280
+ const currencyRows = await this.getAssetHistoryRows(code, since, limit, params);
2281
+ const currency = this.safeValue(currencyRows, 0);
2282
+ const rows = this.safeList(currencyRows, 1);
2283
+ return this.parseLedger(rows, currency, since, limit, params);
2284
+ }
2285
+ parseTransaction(transaction, currency = undefined) {
2286
+ // example in fetchLedger
2287
+ const code = this.safeString(transaction, 'token');
2288
+ let movementDirection = this.safeStringLower(transaction, 'token_side');
2289
+ if (movementDirection === 'withdraw') {
2290
+ movementDirection = 'withdrawal';
2291
+ }
2292
+ const fee = this.parseTokenAndFeeTemp(transaction, 'fee_token', 'fee_amount');
2293
+ const addressTo = this.safeString(transaction, 'target_address');
2294
+ const addressFrom = this.safeString(transaction, 'source_address');
2295
+ const timestamp = this.safeInteger(transaction, 'created_time');
2296
+ return {
2297
+ 'info': transaction,
2298
+ 'id': this.safeString2(transaction, 'id', 'withdraw_id'),
2299
+ 'txid': this.safeString(transaction, 'tx_id'),
2300
+ 'timestamp': timestamp,
2301
+ 'datetime': this.iso8601(timestamp),
2302
+ 'address': undefined,
2303
+ 'addressFrom': addressFrom,
2304
+ 'addressTo': addressTo,
2305
+ 'tag': this.safeString(transaction, 'extra'),
2306
+ 'tagFrom': undefined,
2307
+ 'tagTo': undefined,
2308
+ 'type': movementDirection,
2309
+ 'amount': this.safeNumber(transaction, 'amount'),
2310
+ 'currency': code,
2311
+ 'status': this.parseTransactionStatus(this.safeString(transaction, 'status')),
2312
+ 'updated': this.safeInteger(transaction, 'updated_time'),
2313
+ 'comment': undefined,
2314
+ 'internal': undefined,
2315
+ 'fee': fee,
2316
+ 'network': undefined,
2317
+ };
2318
+ }
2319
+ parseTransactionStatus(status) {
2320
+ const statuses = {
2321
+ 'NEW': 'pending',
2322
+ 'CONFIRMING': 'pending',
2323
+ 'PROCESSING': 'pending',
2324
+ 'COMPLETED': 'ok',
2325
+ 'CANCELED': 'canceled',
2326
+ };
2327
+ return this.safeString(statuses, status, status);
2328
+ }
2329
+ /**
2330
+ * @method
2331
+ * @name modetrade#fetchDeposits
2332
+ * @description fetch all deposits made to an account
2333
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-asset-history
2334
+ * @param {string} code unified currency code
2335
+ * @param {int} [since] the earliest time in ms to fetch deposits for
2336
+ * @param {int} [limit] the maximum number of deposits structures to retrieve
2337
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2338
+ * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
2339
+ */
2340
+ async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
2341
+ const request = {
2342
+ 'side': 'DEPOSIT',
2343
+ };
2344
+ return await this.fetchDepositsWithdrawals(code, since, limit, this.extend(request, params));
2345
+ }
2346
+ /**
2347
+ * @method
2348
+ * @name modetrade#fetchWithdrawals
2349
+ * @description fetch all withdrawals made from an account
2350
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-asset-history
2351
+ * @param {string} code unified currency code
2352
+ * @param {int} [since] the earliest time in ms to fetch withdrawals for
2353
+ * @param {int} [limit] the maximum number of withdrawals structures to retrieve
2354
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2355
+ * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
2356
+ */
2357
+ async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
2358
+ const request = {
2359
+ 'side': 'WITHDRAW',
2360
+ };
2361
+ return await this.fetchDepositsWithdrawals(code, since, limit, this.extend(request, params));
2362
+ }
2363
+ /**
2364
+ * @method
2365
+ * @name modetrade#fetchDepositsWithdrawals
2366
+ * @description fetch history of deposits and withdrawals
2367
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-asset-history
2368
+ * @param {string} [code] unified currency code for the currency of the deposit/withdrawals, default is undefined
2369
+ * @param {int} [since] timestamp in ms of the earliest deposit/withdrawal, default is undefined
2370
+ * @param {int} [limit] max number of deposit/withdrawals to return, default is undefined
2371
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2372
+ * @returns {object} a list of [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
2373
+ */
2374
+ async fetchDepositsWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
2375
+ const request = {};
2376
+ const currencyRows = await this.getAssetHistoryRows(code, since, limit, this.extend(request, params));
2377
+ const currency = this.safeValue(currencyRows, 0);
2378
+ const rows = this.safeList(currencyRows, 1);
2379
+ //
2380
+ // {
2381
+ // "rows":[],
2382
+ // "meta":{
2383
+ // "total":0,
2384
+ // "records_per_page":25,
2385
+ // "current_page":1
2386
+ // },
2387
+ // "success":true
2388
+ // }
2389
+ //
2390
+ return this.parseTransactions(rows, currency, since, limit, params);
2391
+ }
2392
+ async getWithdrawNonce(params = {}) {
2393
+ const response = await this.v1PrivateGetWithdrawNonce(params);
2394
+ //
2395
+ // {
2396
+ // "success": true,
2397
+ // "timestamp": 1702989203989,
2398
+ // "data": {
2399
+ // "withdraw_nonce": 1
2400
+ // }
2401
+ // }
2402
+ //
2403
+ const data = this.safeDict(response, 'data', {});
2404
+ return this.safeNumber(data, 'withdraw_nonce');
2405
+ }
2406
+ hashMessage(message) {
2407
+ return '0x' + this.hash(message, sha3.keccak_256, 'hex');
2408
+ }
2409
+ signHash(hash, privateKey) {
2410
+ const signature = crypto.ecdsa(hash.slice(-64), privateKey.slice(-64), secp256k1.secp256k1, undefined);
2411
+ const r = signature['r'];
2412
+ const s = signature['s'];
2413
+ const v = this.intToBase16(this.sum(27, signature['v']));
2414
+ return '0x' + r.padStart(64, '0') + s.padStart(64, '0') + v;
2415
+ }
2416
+ signMessage(message, privateKey) {
2417
+ return this.signHash(this.hashMessage(message), privateKey.slice(-64));
2418
+ }
2419
+ /**
2420
+ * @method
2421
+ * @name modetrade#withdraw
2422
+ * @description make a withdrawal
2423
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/create-withdraw-request
2424
+ * @param {string} code unified currency code
2425
+ * @param {float} amount the amount to withdraw
2426
+ * @param {string} address the address to withdraw to
2427
+ * @param {string} tag
2428
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2429
+ * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
2430
+ */
2431
+ async withdraw(code, amount, address, tag = undefined, params = {}) {
2432
+ await this.loadMarkets();
2433
+ this.checkAddress(address);
2434
+ if (code !== undefined) {
2435
+ code = code.toUpperCase();
2436
+ if (code !== 'USDC') {
2437
+ throw new errors.NotSupported(this.id + ' withdraw() only support USDC');
2438
+ }
2439
+ }
2440
+ const currency = this.currency(code);
2441
+ const verifyingContractAddress = this.safeString(this.options, 'verifyingContractAddress');
2442
+ const chainId = this.safeString(params, 'chainId');
2443
+ const currencyNetworks = this.safeDict(currency, 'networks', {});
2444
+ const coinNetwork = this.safeDict(currencyNetworks, chainId, {});
2445
+ const coinNetworkId = this.safeNumber(coinNetwork, 'id');
2446
+ if (coinNetworkId === undefined) {
2447
+ throw new errors.BadRequest(this.id + ' withdraw() require chainId parameter');
2448
+ }
2449
+ const withdrawNonce = await this.getWithdrawNonce(params);
2450
+ const nonce = this.nonce();
2451
+ const domain = {
2452
+ 'chainId': chainId,
2453
+ 'name': 'Orderly',
2454
+ 'verifyingContract': verifyingContractAddress,
2455
+ 'version': '1',
2456
+ };
2457
+ const messageTypes = {
2458
+ 'Withdraw': [
2459
+ { 'name': 'brokerId', 'type': 'string' },
2460
+ { 'name': 'chainId', 'type': 'uint256' },
2461
+ { 'name': 'receiver', 'type': 'address' },
2462
+ { 'name': 'token', 'type': 'string' },
2463
+ { 'name': 'amount', 'type': 'uint256' },
2464
+ { 'name': 'withdrawNonce', 'type': 'uint64' },
2465
+ { 'name': 'timestamp', 'type': 'uint64' },
2466
+ ],
2467
+ };
2468
+ const withdrawRequest = {
2469
+ 'brokerId': this.safeString(this.options, 'keyBrokerId', 'mode'),
2470
+ 'chainId': this.parseToInt(chainId),
2471
+ 'receiver': address,
2472
+ 'token': code,
2473
+ 'amount': amount.toString(),
2474
+ 'withdrawNonce': withdrawNonce,
2475
+ 'timestamp': nonce,
2476
+ };
2477
+ const msg = this.ethEncodeStructuredData(domain, messageTypes, withdrawRequest);
2478
+ const signature = this.signMessage(msg, this.privateKey);
2479
+ const request = {
2480
+ 'signature': signature,
2481
+ 'userAddress': address,
2482
+ 'verifyingContract': verifyingContractAddress,
2483
+ 'message': withdrawRequest,
2484
+ };
2485
+ params = this.omit(params, 'chainId');
2486
+ const response = await this.v1PrivatePostWithdrawRequest(this.extend(request, params));
2487
+ //
2488
+ // {
2489
+ // "success": true,
2490
+ // "timestamp": 1702989203989,
2491
+ // "data": {
2492
+ // "withdraw_id": 123
2493
+ // }
2494
+ // }
2495
+ //
2496
+ const data = this.safeDict(response, 'data', {});
2497
+ return this.parseTransaction(data, currency);
2498
+ }
2499
+ parseLeverage(leverage, market = undefined) {
2500
+ const leverageValue = this.safeInteger(leverage, 'max_leverage');
2501
+ return {
2502
+ 'info': leverage,
2503
+ 'symbol': market['symbol'],
2504
+ 'marginMode': undefined,
2505
+ 'longLeverage': leverageValue,
2506
+ 'shortLeverage': leverageValue,
2507
+ };
2508
+ }
2509
+ /**
2510
+ * @method
2511
+ * @name modetrade#fetchLeverage
2512
+ * @description fetch the set leverage for a market
2513
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-account-information
2514
+ * @param {string} symbol unified market symbol
2515
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2516
+ * @returns {object} a [leverage structure]{@link https://docs.ccxt.com/#/?id=leverage-structure}
2517
+ */
2518
+ async fetchLeverage(symbol, params = {}) {
2519
+ await this.loadMarkets();
2520
+ const market = this.market(symbol);
2521
+ const response = await this.v1PrivateGetClientInfo(params);
2522
+ //
2523
+ // {
2524
+ // "success": true,
2525
+ // "timestamp": 1702989203989,
2526
+ // "data": {
2527
+ // "account_id": "<string>",
2528
+ // "email": "test@test.com",
2529
+ // "account_mode": "FUTURES",
2530
+ // "max_leverage": 20,
2531
+ // "taker_fee_rate": 123,
2532
+ // "maker_fee_rate": 123,
2533
+ // "futures_taker_fee_rate": 123,
2534
+ // "futures_maker_fee_rate": 123,
2535
+ // "maintenance_cancel_orders": true,
2536
+ // "imr_factor": {
2537
+ // "PERP_BTC_USDC": 123,
2538
+ // "PERP_ETH_USDC": 123,
2539
+ // "PERP_NEAR_USDC": 123
2540
+ // },
2541
+ // "max_notional": {
2542
+ // "PERP_BTC_USDC": 123,
2543
+ // "PERP_ETH_USDC": 123,
2544
+ // "PERP_NEAR_USDC": 123
2545
+ // }
2546
+ // }
2547
+ // }
2548
+ //
2549
+ const data = this.safeDict(response, 'data', {});
2550
+ return this.parseLeverage(data, market);
2551
+ }
2552
+ /**
2553
+ * @method
2554
+ * @name modetrade#setLeverage
2555
+ * @description set the level of leverage for a market
2556
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/update-leverage-setting
2557
+ * @param {int} [leverage] the rate of leverage
2558
+ * @param {string} [symbol] unified market symbol
2559
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2560
+ * @returns {object} response from the exchange
2561
+ */
2562
+ async setLeverage(leverage, symbol = undefined, params = {}) {
2563
+ await this.loadMarkets();
2564
+ const isMinLeverage = leverage < 1;
2565
+ const isMaxLeverage = leverage > 50;
2566
+ if (isMinLeverage || isMaxLeverage) {
2567
+ throw new errors.BadRequest(this.id + ' leverage should be between 1 and 50');
2568
+ }
2569
+ const request = {
2570
+ 'leverage': leverage,
2571
+ };
2572
+ return await this.v1PrivatePostClientLeverage(this.extend(request, params));
2573
+ }
2574
+ parsePosition(position, market = undefined) {
2575
+ //
2576
+ // {
2577
+ // "IMR_withdraw_orders": 0.1,
2578
+ // "MMR_with_orders": 0.05,
2579
+ // "average_open_price": 27908.14386047,
2580
+ // "cost_position": -139329.358492,
2581
+ // "est_liq_price": 117335.92899428,
2582
+ // "fee_24_h": 123,
2583
+ // "imr": 0.1,
2584
+ // "last_sum_unitary_funding": 70.38,
2585
+ // "mark_price": 27794.9,
2586
+ // "mmr": 0.05,
2587
+ // "pending_long_qty": 123,
2588
+ // "pending_short_qty": 123,
2589
+ // "pnl_24_h": 123,
2590
+ // "position_qty": -5,
2591
+ // "settle_price": 27865.8716984,
2592
+ // "symbol": "PERP_BTC_USDC",
2593
+ // "timestamp": 1685429350571,
2594
+ // "unsettled_pnl": 354.858492
2595
+ // }
2596
+ //
2597
+ const contract = this.safeString(position, 'symbol');
2598
+ market = this.safeMarket(contract, market);
2599
+ let size = this.safeString(position, 'position_qty');
2600
+ let side = undefined;
2601
+ if (Precise["default"].stringGt(size, '0')) {
2602
+ side = 'long';
2603
+ }
2604
+ else {
2605
+ side = 'short';
2606
+ }
2607
+ const contractSize = this.safeString(market, 'contractSize');
2608
+ const markPrice = this.safeString(position, 'mark_price');
2609
+ const timestamp = this.safeInteger(position, 'timestamp');
2610
+ const entryPrice = this.safeString(position, 'average_open_price');
2611
+ const unrealisedPnl = this.safeString(position, 'unsettled_pnl');
2612
+ size = Precise["default"].stringAbs(size);
2613
+ const notional = Precise["default"].stringMul(size, markPrice);
2614
+ return this.safePosition({
2615
+ 'info': position,
2616
+ 'id': undefined,
2617
+ 'symbol': this.safeString(market, 'symbol'),
2618
+ 'timestamp': timestamp,
2619
+ 'datetime': this.iso8601(timestamp),
2620
+ 'lastUpdateTimestamp': undefined,
2621
+ 'initialMargin': undefined,
2622
+ 'initialMarginPercentage': undefined,
2623
+ 'maintenanceMargin': undefined,
2624
+ 'maintenanceMarginPercentage': undefined,
2625
+ 'entryPrice': this.parseNumber(entryPrice),
2626
+ 'notional': this.parseNumber(notional),
2627
+ 'leverage': undefined,
2628
+ 'unrealizedPnl': this.parseNumber(unrealisedPnl),
2629
+ 'contracts': this.parseNumber(size),
2630
+ 'contractSize': this.parseNumber(contractSize),
2631
+ 'marginRatio': undefined,
2632
+ 'liquidationPrice': this.safeNumber(position, 'est_liq_price'),
2633
+ 'markPrice': this.parseNumber(markPrice),
2634
+ 'lastPrice': undefined,
2635
+ 'collateral': undefined,
2636
+ 'marginMode': 'cross',
2637
+ 'marginType': undefined,
2638
+ 'side': side,
2639
+ 'percentage': undefined,
2640
+ 'hedged': undefined,
2641
+ 'stopLossPrice': undefined,
2642
+ 'takeProfitPrice': undefined,
2643
+ });
2644
+ }
2645
+ /**
2646
+ * @method
2647
+ * @name modetrade#fetchPosition
2648
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-one-position-info
2649
+ * @description fetch data on an open position
2650
+ * @param {string} symbol unified market symbol of the market the position is held in
2651
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2652
+ * @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
2653
+ */
2654
+ async fetchPosition(symbol, params = {}) {
2655
+ await this.loadMarkets();
2656
+ const market = this.market(symbol);
2657
+ const request = {
2658
+ 'symbol': market['id'],
2659
+ };
2660
+ const response = await this.v1PrivateGetPositionSymbol(this.extend(request, params));
2661
+ //
2662
+ // {
2663
+ // "success": true,
2664
+ // "timestamp": 1702989203989,
2665
+ // "data": {
2666
+ // "IMR_withdraw_orders": 0.1,
2667
+ // "MMR_with_orders": 0.05,
2668
+ // "average_open_price": 27908.14386047,
2669
+ // "cost_position": -139329.358492,
2670
+ // "est_liq_price": 117335.92899428,
2671
+ // "fee_24_h": 123,
2672
+ // "imr": 0.1,
2673
+ // "last_sum_unitary_funding": 70.38,
2674
+ // "mark_price": 27794.9,
2675
+ // "mmr": 0.05,
2676
+ // "pending_long_qty": 123,
2677
+ // "pending_short_qty": 123,
2678
+ // "pnl_24_h": 123,
2679
+ // "position_qty": -5,
2680
+ // "settle_price": 27865.8716984,
2681
+ // "symbol": "PERP_BTC_USDC",
2682
+ // "timestamp": 1685429350571,
2683
+ // "unsettled_pnl": 354.858492
2684
+ // }
2685
+ // }
2686
+ //
2687
+ const data = this.safeDict(response, 'data');
2688
+ return this.parsePosition(data, market);
2689
+ }
2690
+ /**
2691
+ * @method
2692
+ * @name modetrade#fetchPositions
2693
+ * @description fetch all open positions
2694
+ * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-all-positions-info
2695
+ * @param {string[]} [symbols] list of unified market symbols
2696
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2697
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
2698
+ */
2699
+ async fetchPositions(symbols = undefined, params = {}) {
2700
+ await this.loadMarkets();
2701
+ const response = await this.v1PrivateGetPositions(params);
2702
+ //
2703
+ // {
2704
+ // "success": true,
2705
+ // "timestamp": 1702989203989,
2706
+ // "data": {
2707
+ // "current_margin_ratio_with_orders": 1.2385,
2708
+ // "free_collateral": 450315.09115,
2709
+ // "initial_margin_ratio": 0.1,
2710
+ // "initial_margin_ratio_with_orders": 0.1,
2711
+ // "maintenance_margin_ratio": 0.05,
2712
+ // "maintenance_margin_ratio_with_orders": 0.05,
2713
+ // "margin_ratio": 1.2385,
2714
+ // "open_margin_ratio": 1.2102,
2715
+ // "total_collateral_value": 489865.71329,
2716
+ // "total_pnl_24_h": 123,
2717
+ // "rows": [{
2718
+ // "IMR_withdraw_orders": 0.1,
2719
+ // "MMR_with_orders": 0.05,
2720
+ // "average_open_price": 27908.14386047,
2721
+ // "cost_position": -139329.358492,
2722
+ // "est_liq_price": 117335.92899428,
2723
+ // "fee_24_h": 123,
2724
+ // "imr": 0.1,
2725
+ // "last_sum_unitary_funding": 70.38,
2726
+ // "mark_price": 27794.9,
2727
+ // "mmr": 0.05,
2728
+ // "pending_long_qty": 123,
2729
+ // "pending_short_qty": 123,
2730
+ // "pnl_24_h": 123,
2731
+ // "position_qty": -5,
2732
+ // "settle_price": 27865.8716984,
2733
+ // "symbol": "PERP_BTC_USDC",
2734
+ // "timestamp": 1685429350571,
2735
+ // "unsettled_pnl": 354.858492
2736
+ // }]
2737
+ // }
2738
+ // }
2739
+ //
2740
+ const result = this.safeDict(response, 'data', {});
2741
+ const positions = this.safeList(result, 'rows', []);
2742
+ return this.parsePositions(positions, symbols);
2743
+ }
2744
+ nonce() {
2745
+ return this.milliseconds();
2746
+ }
2747
+ sign(path, section = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
2748
+ const version = section[0];
2749
+ const access = section[1];
2750
+ const pathWithParams = this.implodeParams(path, params);
2751
+ let url = this.implodeHostname(this.urls['api'][access]);
2752
+ url += '/' + version + '/';
2753
+ params = this.omit(params, this.extractParams(path));
2754
+ params = this.keysort(params);
2755
+ if (access === 'public') {
2756
+ url += pathWithParams;
2757
+ if (Object.keys(params).length) {
2758
+ url += '?' + this.urlencode(params);
2759
+ }
2760
+ }
2761
+ else {
2762
+ this.checkRequiredCredentials();
2763
+ const isPostOrPut = method === 'POST' || method === 'PUT';
2764
+ const isOrder = path === 'algo/order' || path === 'order' || path === 'batch-order';
2765
+ if (isPostOrPut && isOrder) {
2766
+ const isSandboxMode = this.safeBool(this.options, 'sandboxMode', false);
2767
+ if (!isSandboxMode) {
2768
+ const brokerId = this.safeString(this.options, 'brokerId', 'CCXT');
2769
+ if (path === 'batch-order') {
2770
+ const ordersList = this.safeList(params, 'orders', []);
2771
+ for (let i = 0; i < ordersList.length; i++) {
2772
+ params['orders'][i]['order_tag'] = brokerId;
2773
+ }
2774
+ }
2775
+ else {
2776
+ params['order_tag'] = brokerId;
2777
+ }
2778
+ }
2779
+ params = this.keysort(params);
2780
+ }
2781
+ let auth = '';
2782
+ const ts = this.nonce().toString();
2783
+ url += pathWithParams;
2784
+ let apiKey = this.apiKey;
2785
+ if (apiKey.indexOf('ed25519:') < 0) {
2786
+ apiKey = 'ed25519:' + apiKey;
2787
+ }
2788
+ headers = {
2789
+ 'orderly-account-id': this.accountId,
2790
+ 'orderly-key': apiKey,
2791
+ 'orderly-timestamp': ts,
2792
+ };
2793
+ auth = ts + method + '/' + version + '/' + pathWithParams;
2794
+ if (method === 'POST' || method === 'PUT') {
2795
+ body = this.json(params);
2796
+ auth += body;
2797
+ headers['content-type'] = 'application/json';
2798
+ }
2799
+ else {
2800
+ if (Object.keys(params).length) {
2801
+ url += '?' + this.urlencode(params);
2802
+ auth += '?' + this.rawencode(params);
2803
+ }
2804
+ headers['content-type'] = 'application/x-www-form-urlencoded';
2805
+ if (method === 'DELETE') {
2806
+ body = '';
2807
+ }
2808
+ }
2809
+ let secret = this.secret;
2810
+ if (secret.indexOf('ed25519:') >= 0) {
2811
+ const parts = secret.split('ed25519:');
2812
+ secret = parts[1];
2813
+ }
2814
+ const signature = crypto.eddsa(this.encode(auth), this.base58ToBinary(secret), ed25519.ed25519);
2815
+ headers['orderly-signature'] = this.urlencodeBase64(this.base64ToBinary(signature));
2816
+ }
2817
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
2818
+ }
2819
+ handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
2820
+ if (!response) {
2821
+ return undefined; // fallback to default error handler
2822
+ }
2823
+ //
2824
+ // 400 Bad Request {"success":false,"code":-1012,"message":"Amount is required for buy market orders when margin disabled."}
2825
+ // {"code":"-1011","message":"The system is under maintenance.","success":false}
2826
+ //
2827
+ const success = this.safeBool(response, 'success');
2828
+ const errorCode = this.safeString(response, 'code');
2829
+ if (!success) {
2830
+ const feedback = this.id + ' ' + this.json(response);
2831
+ this.throwBroadlyMatchedException(this.exceptions['broad'], body, feedback);
2832
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
2833
+ throw new errors.ExchangeError(feedback);
2834
+ }
2835
+ return undefined;
2836
+ }
2837
+ }
2838
+
2839
+ module.exports = modetrade;