ccxt 4.3.18__py2.py3-none-any.whl → 4.3.19__py2.py3-none-any.whl

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