ccxt 4.5.5 → 4.5.7

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 (151) hide show
  1. package/README.md +4 -4
  2. package/dist/ccxt.browser.min.js +15 -15
  3. package/dist/cjs/ccxt.js +6 -6
  4. package/dist/cjs/src/abstract/toobit.js +11 -0
  5. package/dist/cjs/src/abstract/tradeogre.js +1 -1
  6. package/dist/cjs/src/apex.js +2 -2
  7. package/dist/cjs/src/backpack.js +1 -1
  8. package/dist/cjs/src/base/Exchange.js +129 -2
  9. package/dist/cjs/src/bigone.js +4 -4
  10. package/dist/cjs/src/binance.js +82 -20
  11. package/dist/cjs/src/bingx.js +5 -2
  12. package/dist/cjs/src/bitbank.js +1 -0
  13. package/dist/cjs/src/bitbns.js +1 -0
  14. package/dist/cjs/src/bitflyer.js +1 -0
  15. package/dist/cjs/src/bitget.js +16 -9
  16. package/dist/cjs/src/bithumb.js +1 -0
  17. package/dist/cjs/src/bitso.js +1 -0
  18. package/dist/cjs/src/bitvavo.js +26 -40
  19. package/dist/cjs/src/blockchaincom.js +1 -0
  20. package/dist/cjs/src/btcalpha.js +1 -0
  21. package/dist/cjs/src/btcbox.js +1 -0
  22. package/dist/cjs/src/btcmarkets.js +1 -0
  23. package/dist/cjs/src/btcturk.js +1 -0
  24. package/dist/cjs/src/bybit.js +186 -127
  25. package/dist/cjs/src/coinsph.js +4 -1
  26. package/dist/cjs/src/cryptocom.js +6 -3
  27. package/dist/cjs/src/deribit.js +3 -2
  28. package/dist/cjs/src/digifinex.js +1 -1
  29. package/dist/cjs/src/gate.js +9 -13
  30. package/dist/cjs/src/gemini.js +5 -5
  31. package/dist/cjs/src/htx.js +11 -1
  32. package/dist/cjs/src/hyperliquid.js +3 -0
  33. package/dist/cjs/src/independentreserve.js +1 -0
  34. package/dist/cjs/src/indodax.js +17 -6
  35. package/dist/cjs/src/kraken.js +31 -8
  36. package/dist/cjs/src/krakenfutures.js +1 -0
  37. package/dist/cjs/src/kucoin.js +1 -2
  38. package/dist/cjs/src/luno.js +4 -1
  39. package/dist/cjs/src/mercado.js +1 -0
  40. package/dist/cjs/src/mexc.js +84 -37
  41. package/dist/cjs/src/novadax.js +1 -0
  42. package/dist/cjs/src/oceanex.js +1 -0
  43. package/dist/cjs/src/okcoin.js +4 -1
  44. package/dist/cjs/src/okx.js +52 -8
  45. package/dist/cjs/src/phemex.js +1 -1
  46. package/dist/cjs/src/pro/apex.js +8 -4
  47. package/dist/cjs/src/pro/backpack.js +7 -5
  48. package/dist/cjs/src/pro/binance.js +150 -19
  49. package/dist/cjs/src/pro/bingx.js +206 -220
  50. package/dist/cjs/src/pro/bitget.js +332 -76
  51. package/dist/cjs/src/pro/cex.js +1 -0
  52. package/dist/cjs/src/pro/htx.js +1 -1
  53. package/dist/cjs/src/pro/independentreserve.js +1 -0
  54. package/dist/cjs/src/pro/mexc.js +23 -23
  55. package/dist/cjs/src/pro/okx.js +46 -10
  56. package/dist/cjs/src/pro/toobit.js +1163 -0
  57. package/dist/cjs/src/pro/tradeogre.js +1 -1
  58. package/dist/cjs/src/toobit.js +2999 -0
  59. package/dist/cjs/src/tradeogre.js +1 -1
  60. package/dist/cjs/src/upbit.js +1 -0
  61. package/dist/cjs/src/wavesexchange.js +1 -0
  62. package/dist/cjs/src/yobit.js +1 -0
  63. package/dist/cjs/src/zaif.js +1 -0
  64. package/dist/cjs/src/zonda.js +1 -0
  65. package/js/ccxt.d.ts +8 -8
  66. package/js/ccxt.js +6 -6
  67. package/js/src/abstract/mexc.d.ts +1 -0
  68. package/js/src/abstract/myokx.d.ts +1 -0
  69. package/js/src/abstract/okx.d.ts +1 -0
  70. package/js/src/abstract/okxus.d.ts +1 -0
  71. package/js/src/abstract/toobit.d.ts +66 -0
  72. package/js/src/apex.js +2 -2
  73. package/js/src/backpack.js +1 -1
  74. package/js/src/base/Exchange.d.ts +9 -0
  75. package/js/src/base/Exchange.js +129 -2
  76. package/js/src/bigone.js +4 -4
  77. package/js/src/binance.d.ts +9 -0
  78. package/js/src/binance.js +82 -20
  79. package/js/src/bingx.js +5 -2
  80. package/js/src/bitbank.js +1 -0
  81. package/js/src/bitbns.js +1 -0
  82. package/js/src/bitflyer.js +1 -0
  83. package/js/src/bitget.js +16 -9
  84. package/js/src/bithumb.js +1 -0
  85. package/js/src/bitso.js +1 -0
  86. package/js/src/bitvavo.d.ts +0 -2
  87. package/js/src/bitvavo.js +27 -41
  88. package/js/src/blockchaincom.js +1 -0
  89. package/js/src/btcalpha.js +1 -0
  90. package/js/src/btcbox.js +1 -0
  91. package/js/src/btcmarkets.js +1 -0
  92. package/js/src/btcturk.js +1 -0
  93. package/js/src/bybit.d.ts +8 -0
  94. package/js/src/bybit.js +186 -127
  95. package/js/src/coinsph.js +4 -1
  96. package/js/src/cryptocom.js +6 -3
  97. package/js/src/deribit.js +3 -2
  98. package/js/src/digifinex.js +1 -1
  99. package/js/src/gate.d.ts +2 -2
  100. package/js/src/gate.js +9 -13
  101. package/js/src/gemini.js +5 -5
  102. package/js/src/htx.js +11 -1
  103. package/js/src/hyperliquid.js +3 -0
  104. package/js/src/independentreserve.js +1 -0
  105. package/js/src/indodax.js +17 -6
  106. package/js/src/kraken.d.ts +2 -2
  107. package/js/src/kraken.js +31 -8
  108. package/js/src/krakenfutures.js +1 -0
  109. package/js/src/kucoin.js +1 -2
  110. package/js/src/luno.js +4 -1
  111. package/js/src/mercado.js +1 -0
  112. package/js/src/mexc.d.ts +4 -1
  113. package/js/src/mexc.js +84 -37
  114. package/js/src/novadax.js +1 -0
  115. package/js/src/oceanex.js +1 -0
  116. package/js/src/okcoin.js +4 -1
  117. package/js/src/okx.js +52 -8
  118. package/js/src/phemex.js +1 -1
  119. package/js/src/pro/apex.js +8 -4
  120. package/js/src/pro/backpack.d.ts +1 -1
  121. package/js/src/pro/backpack.js +7 -5
  122. package/js/src/pro/binance.d.ts +24 -0
  123. package/js/src/pro/binance.js +150 -19
  124. package/js/src/pro/bingx.d.ts +53 -33
  125. package/js/src/pro/bingx.js +207 -221
  126. package/js/src/pro/bitget.d.ts +6 -0
  127. package/js/src/pro/bitget.js +332 -76
  128. package/js/src/pro/cex.js +1 -0
  129. package/js/src/pro/htx.js +1 -1
  130. package/js/src/pro/independentreserve.js +1 -0
  131. package/js/src/pro/mexc.js +23 -23
  132. package/js/src/pro/okx.d.ts +7 -1
  133. package/js/src/pro/okx.js +46 -10
  134. package/js/src/pro/toobit.d.ts +174 -0
  135. package/js/src/pro/toobit.js +1162 -0
  136. package/js/src/toobit.d.ts +456 -0
  137. package/js/src/toobit.js +2992 -0
  138. package/js/src/upbit.js +1 -0
  139. package/js/src/wavesexchange.js +1 -0
  140. package/js/src/yobit.js +1 -0
  141. package/js/src/zaif.js +1 -0
  142. package/js/src/zonda.js +1 -0
  143. package/package.json +1 -1
  144. package/dist/373.ccxt.browser.js +0 -7630
  145. package/dist/373.ccxt.browser.min.js +0 -1
  146. package/js/src/abstract/tradeogre.d.ts +0 -21
  147. package/js/src/pro/tradeogre.d.ts +0 -49
  148. package/js/src/pro/tradeogre.js +0 -278
  149. package/js/src/tradeogre.d.ts +0 -149
  150. package/js/src/tradeogre.js +0 -872
  151. /package/js/src/abstract/{tradeogre.js → toobit.js} +0 -0
@@ -0,0 +1,2992 @@
1
+ // ---------------------------------------------------------------------------
2
+ import Exchange from './abstract/toobit.js';
3
+ import { OperationFailed, ArgumentsRequired, ExchangeError, BadRequest, OrderNotFound, BadSymbol, NotSupported, PermissionDenied, RateLimitExceeded, OperationRejected, InvalidOrder, InsufficientFunds } from './base/errors.js';
4
+ import { Precise } from './base/Precise.js';
5
+ import { TICK_SIZE } from './base/functions/number.js';
6
+ import { sha256 } from './static_dependencies/noble-hashes/sha256.js';
7
+ // ---------------------------------------------------------------------------
8
+ /**
9
+ * @class toobit
10
+ * @augments Exchange
11
+ */
12
+ export default class toobit extends Exchange {
13
+ describe() {
14
+ return this.deepExtend(super.describe(), {
15
+ 'id': 'toobit',
16
+ 'name': 'Toobit',
17
+ 'countries': ['KY'],
18
+ 'version': 'v1',
19
+ 'rateLimit': 20,
20
+ 'certified': false,
21
+ 'pro': false,
22
+ 'has': {
23
+ 'CORS': undefined,
24
+ 'spot': true,
25
+ 'margin': false,
26
+ 'swap': true,
27
+ 'future': false,
28
+ 'option': false,
29
+ 'cancelAllOrders': true,
30
+ 'cancelOrder': true,
31
+ 'cancelOrders': true,
32
+ 'createOrder': true,
33
+ 'fetchBalance': true,
34
+ 'fetchBidsAsks': true,
35
+ 'fetchCurrencies': true,
36
+ 'fetchDepositAddress': true,
37
+ 'fetchDeposits': true,
38
+ 'fetchFundingRateHistory': true,
39
+ 'fetchFundingRates': true,
40
+ 'fetchIndexOHLCV': true,
41
+ 'fetchLastPrices': true,
42
+ 'fetchLedger': true,
43
+ 'fetchMarkets': true,
44
+ 'fetchMarkOHLCV': true,
45
+ 'fetchMyTrades': true,
46
+ 'fetchOHLCV': true,
47
+ 'fetchOpenOrders': true,
48
+ 'fetchOrder': true,
49
+ 'fetchOrderBook': true,
50
+ 'fetchOrders': true,
51
+ 'fetchStatus': true,
52
+ 'fetchTickers': true,
53
+ 'fetchTime': true,
54
+ 'fetchTrades': true,
55
+ 'fetchWithdrawals': true,
56
+ 'setMarginMode': true,
57
+ 'transfer': true,
58
+ 'withdraw': true,
59
+ },
60
+ 'urls': {
61
+ 'logo': 'https://github.com/user-attachments/assets/3fc13870-5406-431b-8be0-2aab69c4f225',
62
+ 'api': {
63
+ 'common': 'https://api.toobit.com',
64
+ 'private': 'https://api.toobit.com',
65
+ },
66
+ 'www': 'https://www.toobit.com/',
67
+ 'doc': [
68
+ 'https://toobit-docs.github.io/apidocs/spot/v1/en/',
69
+ 'https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/',
70
+ ],
71
+ 'referral': {
72
+ 'url': 'https://www.toobit.com/en-US/r?i=IFFPy0',
73
+ 'discount': 0.1,
74
+ },
75
+ 'fees': 'https://www.toobit.com/fee',
76
+ },
77
+ 'api': {
78
+ 'common': {
79
+ 'get': {
80
+ 'api/v1/time': 1,
81
+ 'api/v1/ping': 1,
82
+ 'api/v1/exchangeInfo': 1,
83
+ 'quote/v1/depth': 1,
84
+ 'quote/v1/depth/merged': 1,
85
+ 'quote/v1/trades': 1,
86
+ 'quote/v1/klines': 1,
87
+ 'quote/v1/index/klines': 1,
88
+ 'quote/v1/markPrice/klines': 1,
89
+ 'quote/v1/markPrice': 1,
90
+ 'quote/v1/index': 1,
91
+ 'quote/v1/ticker/24hr': 40,
92
+ 'quote/v1/contract/ticker/24hr': 40,
93
+ 'quote/v1/ticker/price': 1,
94
+ 'quote/v1/ticker/bookTicker': 1,
95
+ 'api/v1/futures/fundingRate': 1,
96
+ 'api/v1/futures/historyFundingRate': 1,
97
+ },
98
+ },
99
+ 'private': {
100
+ 'get': {
101
+ 'api/v1/account': 5,
102
+ 'api/v1/account/checkApiKey': 1,
103
+ 'api/v1/spot/order': 1 * 1.67,
104
+ 'api/v1/spot/openOrders': 1 * 1.67,
105
+ 'api/v1/futures/openOrders': 1 * 1.67,
106
+ 'api/v1/spot/tradeOrders': 5 * 1.67,
107
+ 'api/v1/futures/historyOrders': 5 * 1.67,
108
+ 'api/v1/account/trades': 5 * 1.67,
109
+ 'api/v1/account/balanceFlow': 5,
110
+ 'api/v1/account/depositOrders': 5,
111
+ 'api/v1/account/withdrawOrders': 5,
112
+ 'api/v1/account/deposit/address': 1,
113
+ // contracts
114
+ 'api/v1/subAccount': 5,
115
+ 'api/v1/futures/accountLeverage': 1,
116
+ 'api/v1/futures/order': 1 * 1.67,
117
+ 'api/v1/futures/positions': 5 * 1.67,
118
+ 'api/v1/futures/balance': 5,
119
+ 'api/v1/futures/userTrades': 5 * 1.67,
120
+ 'api/v1/futures/balanceFlow': 5,
121
+ 'api/v1/futures/commissionRate': 5,
122
+ 'api/v1/futures/todayPnl': 5,
123
+ },
124
+ 'post': {
125
+ 'api/v1/spot/orderTest': 1 * 1.67,
126
+ 'api/v1/spot/order': 1 * 1.67,
127
+ 'api/v1/futures/order': 1 * 1.67,
128
+ 'api/v1/spot/batchOrders': 2 * 1.67,
129
+ 'api/v1/subAccount/transfer': 1,
130
+ 'api/v1/account/withdraw': 1,
131
+ // contracts
132
+ 'api/v1/futures/marginType': 1,
133
+ 'api/v1/futures/leverage': 1,
134
+ 'api/v1/futures/batchOrders': 2 * 1.67,
135
+ 'api/v1/futures/position/trading-stop': 3 * 1.67,
136
+ 'api/v1/futures/positionMargin': 1,
137
+ 'api/v1/userDataStream': 1,
138
+ 'api/v1/listenKey': 1,
139
+ },
140
+ 'delete': {
141
+ 'api/v1/spot/order': 1 * 1.67,
142
+ 'api/v1/futures/order': 1 * 1.67,
143
+ 'api/v1/spot/openOrders': 5 * 1.67,
144
+ 'api/v1/futures/batchOrders': 5 * 1.67,
145
+ 'api/v1/spot/cancelOrderByIds': 5 * 1.67,
146
+ 'api/v1/futures/cancelOrderByIds': 5 * 1.67,
147
+ 'api/v1/listenKey': 1,
148
+ },
149
+ 'put': {
150
+ 'api/v1/listenKey': 1,
151
+ },
152
+ },
153
+ },
154
+ 'timeframes': {
155
+ '1m': '1m',
156
+ '3m': '3m',
157
+ '5m': '5m',
158
+ '15m': '15m',
159
+ '30m': '30m',
160
+ '1h': '1h',
161
+ '2h': '2h',
162
+ '4h': '4h',
163
+ '6h': '6h',
164
+ '8h': '8h',
165
+ '12h': '12h',
166
+ '1d': '1d',
167
+ '1w': '1w',
168
+ '1M': '1M',
169
+ },
170
+ 'precisionMode': TICK_SIZE,
171
+ 'exceptions': {
172
+ 'exact': {
173
+ '-1000': OperationFailed,
174
+ '-1001': OperationFailed,
175
+ '-1002': PermissionDenied,
176
+ '-1003': RateLimitExceeded,
177
+ '-1004': BadRequest,
178
+ '-1006': OperationFailed,
179
+ '-1007': OperationFailed,
180
+ '-1014': OperationFailed,
181
+ '-1015': RateLimitExceeded,
182
+ '-1016': OperationRejected,
183
+ '-1020': OperationRejected,
184
+ '-1021': OperationRejected,
185
+ '-1022': OperationRejected,
186
+ '-1100': BadRequest,
187
+ '-1101': BadRequest,
188
+ '-1102': BadRequest,
189
+ '-1103': BadRequest,
190
+ '-1104': BadRequest,
191
+ '-1105': BadRequest,
192
+ '-1106': BadRequest,
193
+ '-1111': BadRequest,
194
+ '-1112': OperationRejected,
195
+ '-1114': BadRequest,
196
+ '-1115': BadRequest,
197
+ '-1116': BadRequest,
198
+ '-1117': BadRequest,
199
+ '-1118': InvalidOrder,
200
+ '-1119': InvalidOrder,
201
+ '-1120': BadRequest,
202
+ '-1121': BadRequest,
203
+ '-1125': OperationRejected,
204
+ '-1127': OperationRejected,
205
+ '-1128': BadRequest,
206
+ '-1130': BadRequest,
207
+ '-1132': OperationRejected,
208
+ '-1133': OperationRejected,
209
+ '-1134': OperationRejected,
210
+ '-1135': OperationRejected,
211
+ '-1136': OperationRejected,
212
+ '-1137': OperationRejected,
213
+ '-1138': OperationRejected,
214
+ '-1139': OperationRejected,
215
+ '-1140': OperationRejected,
216
+ '-1141': InvalidOrder,
217
+ '-1142': InvalidOrder,
218
+ '-1143': InvalidOrder,
219
+ '-1144': OperationRejected,
220
+ '-1145': OperationRejected,
221
+ '-1146': OperationFailed,
222
+ '-1147': OperationFailed,
223
+ '-1193': OperationRejected,
224
+ '-1194': OperationRejected,
225
+ '-1195': OperationRejected,
226
+ '-1196': OperationRejected,
227
+ '-1197': OperationRejected,
228
+ '-1198': OperationRejected,
229
+ '-1199': OperationRejected,
230
+ '-1200': OperationRejected,
231
+ '-1201': OperationRejected,
232
+ '-1202': OperationRejected,
233
+ '-1203': OperationRejected,
234
+ '-1206': OperationRejected,
235
+ '-2010': OperationFailed,
236
+ '-2011': OperationFailed,
237
+ '-2013': InvalidOrder,
238
+ '-2014': PermissionDenied,
239
+ '-2015': PermissionDenied,
240
+ '-2016': BadRequest,
241
+ // errors above 3xxx are from swap API
242
+ '-3050': ExchangeError,
243
+ '-3101': OperationRejected,
244
+ '-3102': OperationRejected,
245
+ '-3103': BadRequest,
246
+ '-3105': OperationRejected,
247
+ '-3107': OperationRejected,
248
+ '-3108': OperationRejected,
249
+ '-3109': OperationRejected,
250
+ '-3110': InsufficientFunds,
251
+ '-3116': OperationRejected,
252
+ '-3117': OperationRejected,
253
+ '-3120': OperationRejected,
254
+ '-3124': OperationRejected,
255
+ '-3125': OperationRejected,
256
+ '-3126': OperationRejected,
257
+ '-3127': OperationFailed,
258
+ '-3128': OperationRejected,
259
+ '-3129': BadRequest,
260
+ '-3130': OperationRejected,
261
+ '-3131': NotSupported, // Leverage reduction is not supported in Isolated Margin Mode with open positions.
262
+ },
263
+ 'broad': {
264
+ 'Unknown order sent': OrderNotFound,
265
+ 'Duplicate order sent': InvalidOrder,
266
+ 'Market is closed': OperationRejected,
267
+ 'Account has insufficient balance for requested action': InsufficientFunds,
268
+ 'Market orders are not supported for this symbol': OperationRejected,
269
+ 'Iceberg orders are not supported for this symbol': OperationRejected,
270
+ 'Stop loss orders are not supported for this symbol': OperationRejected,
271
+ 'Stop loss limit orders are not supported for this symbol': OperationRejected,
272
+ 'Take profit orders are not supported for this symbol': OperationRejected,
273
+ 'Take profit limit orders are not supported for this symbol': OperationRejected,
274
+ 'QTY is zero or less': BadRequest,
275
+ 'IcebergQty exceeds QTY': OperationRejected,
276
+ 'This action disabled is on this account': PermissionDenied,
277
+ 'Unsupported order combination': BadRequest,
278
+ 'Order would trigger immediately': OperationRejected,
279
+ 'Cancel order is invalid. Check origClOrdId and orderId': OperationRejected,
280
+ 'Order would immediately match and take': OperationRejected,
281
+ },
282
+ },
283
+ 'commonCurrencies': {},
284
+ 'options': {
285
+ 'defaultType': 'spot',
286
+ 'accountsByType': {
287
+ 'spot': 'MAIN',
288
+ 'swap': 'FUTURES',
289
+ },
290
+ 'networks': {
291
+ 'BTC': 'BTC',
292
+ 'ERC20': 'ETH',
293
+ 'ETH': 'ETH',
294
+ 'BEP20': 'BSC',
295
+ 'TRC20': 'TRX',
296
+ 'SOL': 'SOL',
297
+ 'MATIC': 'MATIC',
298
+ 'ARBONE': 'ARBITRUM',
299
+ 'BASE': 'BASE',
300
+ 'TON': 'TON',
301
+ 'AVAXC': 'AVAXC',
302
+ 'DOGE': 'DOGE',
303
+ 'XRP': 'XRP',
304
+ 'DOT': 'DOT',
305
+ 'ADA': 'ADA',
306
+ 'LTC': 'LTC',
307
+ 'APT': 'APT',
308
+ 'ATOM': 'ATOM',
309
+ 'ALGO': 'ALGO',
310
+ 'NEAR': 'NEAR',
311
+ 'XLM': 'XLM',
312
+ 'SUI': 'SUI',
313
+ 'ETC': 'ETC',
314
+ 'EOS': 'EOS',
315
+ 'WAVES': 'WAVES',
316
+ 'ICP': 'ICP',
317
+ 'ONE': 'ONE',
318
+ // 'CHZ2': 'CHZ2',
319
+ },
320
+ 'networksById': {
321
+ 'ETH': 'ERC20',
322
+ 'ERC20': 'ERC20',
323
+ },
324
+ },
325
+ 'features': {
326
+ 'spot': {
327
+ 'sandbox': false,
328
+ 'createOrder': {
329
+ 'marginMode': false,
330
+ 'triggerPrice': true,
331
+ 'triggerPriceType': undefined,
332
+ 'triggerDirection': false,
333
+ 'stopLossPrice': false,
334
+ 'takeProfitPrice': false,
335
+ 'attachedStopLossTakeProfit': undefined,
336
+ 'timeInForce': {
337
+ 'IOC': true,
338
+ 'FOK': true,
339
+ 'PO': true,
340
+ 'GTD': false,
341
+ },
342
+ 'hedged': false,
343
+ 'trailing': false,
344
+ 'leverage': false,
345
+ 'marketBuyRequiresPrice': false,
346
+ 'marketBuyByCost': false,
347
+ 'selfTradePrevention': false,
348
+ 'iceberg': false,
349
+ },
350
+ 'createOrders': undefined,
351
+ 'fetchOHLCV': {
352
+ 'limit': 1000,
353
+ },
354
+ 'fetchMyTrades': {
355
+ 'marginMode': false,
356
+ 'limit': 1000,
357
+ 'daysBack': 100000,
358
+ 'untilDays': 100000,
359
+ 'symbolRequired': true,
360
+ },
361
+ 'fetchOrder': {
362
+ 'marginMode': false,
363
+ 'trigger': false,
364
+ 'trailing': false,
365
+ 'symbolRequired': false,
366
+ },
367
+ 'fetchOpenOrders': {
368
+ 'marginMode': false,
369
+ 'limit': 1000,
370
+ 'trigger': false,
371
+ 'trailing': false,
372
+ 'symbolRequired': false,
373
+ },
374
+ 'fetchOrders': {
375
+ 'marginMode': false,
376
+ 'limit': 500,
377
+ 'daysBack': 100000,
378
+ 'untilDays': 100000,
379
+ 'trigger': false,
380
+ 'trailing': false,
381
+ 'symbolRequired': false,
382
+ },
383
+ 'fetchClosedOrders': undefined,
384
+ },
385
+ 'forDerivatives': {
386
+ 'createOrders': undefined,
387
+ },
388
+ 'swap': {
389
+ 'linear': undefined,
390
+ 'inverse': undefined,
391
+ },
392
+ 'future': {
393
+ 'linear': undefined,
394
+ 'inverse': undefined,
395
+ },
396
+ },
397
+ });
398
+ }
399
+ /**
400
+ * @method
401
+ * @name toobit#fetchStatus
402
+ * @description the latest known information on the availability of the exchange API
403
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#test-connectivity
404
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
405
+ * @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure}
406
+ */
407
+ async fetchStatus(params = {}) {
408
+ const response = await this.commonGetApiV1Ping(params);
409
+ return {
410
+ 'status': 'ok',
411
+ 'updated': undefined,
412
+ 'eta': undefined,
413
+ 'url': undefined,
414
+ 'info': response,
415
+ };
416
+ }
417
+ /**
418
+ * @method
419
+ * @name toobit#fetchTime
420
+ * @description fetches the current integer timestamp in milliseconds from the exchange server
421
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#check-server-time
422
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
423
+ * @returns {int} the current integer timestamp in milliseconds from the exchange server
424
+ */
425
+ async fetchTime(params = {}) {
426
+ const response = await this.commonGetApiV1Time(params);
427
+ //
428
+ // {
429
+ // "serverTime": 1699827319559
430
+ // }
431
+ //
432
+ return this.safeInteger(response, 'serverTime');
433
+ }
434
+ /**
435
+ * @method
436
+ * @name toobit#fetchCurrencies
437
+ * @description fetches all available currencies on an exchange
438
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
439
+ * @returns {object} an associative dictionary of currencies
440
+ */
441
+ async fetchCurrencies(params = {}) {
442
+ const response = await this.commonGetApiV1ExchangeInfo(params);
443
+ this.options['exchangeInfo'] = response; // we store it in options for later use in fetchMarkets
444
+ //
445
+ // {
446
+ // "timezone": "UTC",
447
+ // "serverTime": "1755583099926",
448
+ // "brokerFilters": [],
449
+ // "symbols": [
450
+ // {
451
+ // "filters": [
452
+ // {
453
+ // "minPrice": "0.01",
454
+ // "maxPrice": "10000000.00000000",
455
+ // "tickSize": "0.01",
456
+ // "filterType": "PRICE_FILTER"
457
+ // },
458
+ // {
459
+ // "minQty": "0.0001",
460
+ // "maxQty": "4000",
461
+ // "stepSize": "0.0001",
462
+ // "filterType": "LOT_SIZE"
463
+ // },
464
+ // {
465
+ // "minNotional": "5",
466
+ // "filterType": "MIN_NOTIONAL"
467
+ // },
468
+ // {
469
+ // "minAmount": "5",
470
+ // "maxAmount": "6600000",
471
+ // "minBuyPrice": "0.01",
472
+ // "filterType": "TRADE_AMOUNT"
473
+ // },
474
+ // {
475
+ // "maxSellPrice": "99999999",
476
+ // "buyPriceUpRate": "0.1",
477
+ // "sellPriceDownRate": "0.1",
478
+ // "filterType": "LIMIT_TRADING"
479
+ // },
480
+ // {
481
+ // "buyPriceUpRate": "0.1",
482
+ // "sellPriceDownRate": "0.1",
483
+ // "filterType": "MARKET_TRADING"
484
+ // },
485
+ // {
486
+ // "noAllowMarketStartTime": "0",
487
+ // "noAllowMarketEndTime": "0",
488
+ // "limitOrderStartTime": "0",
489
+ // "limitOrderEndTime": "0",
490
+ // "limitMinPrice": "0",
491
+ // "limitMaxPrice": "0",
492
+ // "filterType": "OPEN_QUOTE"
493
+ // }
494
+ // ],
495
+ // "exchangeId": "301",
496
+ // "symbol": "ETHUSDT",
497
+ // "symbolName": "ETHUSDT",
498
+ // "status": "TRADING",
499
+ // "baseAsset": "ETH",
500
+ // "baseAssetName": "ETH",
501
+ // "baseAssetPrecision": "0.0001",
502
+ // "quoteAsset": "USDT",
503
+ // "quoteAssetName": "USDT",
504
+ // "quotePrecision": "0.01",
505
+ // "icebergAllowed": false,
506
+ // "isAggregate": false,
507
+ // "allowMargin": true,
508
+ // }
509
+ // ],
510
+ // "options": [],
511
+ // "contracts": [
512
+ // {
513
+ // "filters": [ ... ],
514
+ // "exchangeId": "301",
515
+ // "symbol": "BTC-SWAP-USDT",
516
+ // "symbolName": "BTC-SWAP-USDTUSDT",
517
+ // "status": "TRADING",
518
+ // "baseAsset": "BTC-SWAP-USDT",
519
+ // "baseAssetPrecision": "0.001",
520
+ // "quoteAsset": "USDT",
521
+ // "quoteAssetPrecision": "0.1",
522
+ // "icebergAllowed": false,
523
+ // "inverse": false,
524
+ // "index": "BTC",
525
+ // "indexToken": "BTCUSDT",
526
+ // "marginToken": "USDT",
527
+ // "marginPrecision": "0.0001",
528
+ // "contractMultiplier": "0.001",
529
+ // "underlying": "BTC",
530
+ // "riskLimits": [
531
+ // {
532
+ // "riskLimitId": "200020911",
533
+ // "quantity": "42000.0",
534
+ // "initialMargin": "0.02",
535
+ // "maintMargin": "0.01",
536
+ // "isWhite": false
537
+ // },
538
+ // {
539
+ // "riskLimitId": "200020912",
540
+ // "quantity": "84000.0",
541
+ // "initialMargin": "0.04",
542
+ // "maintMargin": "0.02",
543
+ // "isWhite": false
544
+ // },
545
+ // ...
546
+ // ]
547
+ // },
548
+ // ],
549
+ // "coins": [
550
+ // {
551
+ // "orgId": "9001",
552
+ // "coinId": "TCOM",
553
+ // "coinName": "TCOM",
554
+ // "coinFullName": "TCOM",
555
+ // "allowWithdraw": true,
556
+ // "allowDeposit": true,
557
+ // "chainTypes": [
558
+ // {
559
+ // "chainType": "BSC",
560
+ // "withdrawFee": "49.55478",
561
+ // "minWithdrawQuantity": "77",
562
+ // "maxWithdrawQuantity": "0",
563
+ // "minDepositQuantity": "48",
564
+ // "allowDeposit": true,
565
+ // "allowWithdraw": false
566
+ // }
567
+ // ],
568
+ // "isVirtual": false
569
+ // },
570
+ // ...
571
+ //
572
+ const coins = this.safeList(response, 'coins', []);
573
+ const result = {};
574
+ for (let i = 0; i < coins.length; i++) {
575
+ const coin = coins[i];
576
+ const parsed = this.parseCurrency(coin);
577
+ const code = parsed['code'];
578
+ result[code] = parsed;
579
+ }
580
+ return result;
581
+ }
582
+ parseCurrency(rawCurrency) {
583
+ const id = this.safeString(rawCurrency, 'coinId');
584
+ const code = this.safeCurrencyCode(id);
585
+ const networks = {};
586
+ const rawNetworks = this.safeList(rawCurrency, 'chainTypes');
587
+ for (let j = 0; j < rawNetworks.length; j++) {
588
+ const rawNetwork = rawNetworks[j];
589
+ const networkId = this.safeString(rawNetwork, 'chainType');
590
+ const networkCode = this.networkIdToCode(networkId);
591
+ networks[networkCode] = {
592
+ 'id': networkId,
593
+ 'network': networkCode,
594
+ 'margin': undefined,
595
+ 'deposit': this.safeBool(rawNetwork, 'allowDeposit'),
596
+ 'withdraw': this.safeBool(rawNetwork, 'allowWithdraw'),
597
+ 'active': undefined,
598
+ 'fee': this.safeNumber(rawNetwork, 'withdrawFee'),
599
+ 'precision': undefined,
600
+ 'limits': {
601
+ 'deposit': {
602
+ 'min': this.safeNumber(rawNetwork, 'minDepositQuantity'),
603
+ 'max': undefined,
604
+ },
605
+ 'withdraw': {
606
+ 'min': this.safeNumber(rawNetwork, 'minWithdrawQuantity'),
607
+ 'max': this.safeNumber(rawNetwork, 'maxWithdrawQuantity'),
608
+ },
609
+ },
610
+ 'info': rawNetwork,
611
+ };
612
+ }
613
+ return this.safeCurrencyStructure({
614
+ 'id': id,
615
+ 'code': code,
616
+ 'name': this.safeString(rawCurrency, 'coinFullName'),
617
+ 'type': undefined,
618
+ 'active': undefined,
619
+ 'deposit': this.safeBool(rawCurrency, 'allowDeposit'),
620
+ 'withdraw': this.safeBool(rawCurrency, 'allowWithdraw'),
621
+ 'fee': undefined,
622
+ 'precision': undefined,
623
+ 'limits': {
624
+ 'amount': {
625
+ 'min': undefined,
626
+ 'max': undefined,
627
+ },
628
+ 'withdraw': {
629
+ 'min': undefined,
630
+ 'max': undefined,
631
+ },
632
+ },
633
+ 'networks': networks,
634
+ 'info': rawCurrency,
635
+ });
636
+ }
637
+ /**
638
+ * @method
639
+ * @name toobit#fetchMarkets
640
+ * @description retrieves data on all markets for toobit
641
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#exchange-information
642
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#exchange-information
643
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
644
+ * @returns {object[]} an array of objects representing market data
645
+ */
646
+ async fetchMarkets(params = {}) {
647
+ let response = this.safeDict(this.options, 'exchangeInfo');
648
+ if (response !== undefined) {
649
+ this.options['exchangeInfo'] = undefined; // reset it to avoid using old cached data
650
+ }
651
+ else {
652
+ response = await this.commonGetApiV1ExchangeInfo(params);
653
+ }
654
+ //
655
+ // {
656
+ // "timezone": "UTC",
657
+ // "serverTime": "1755583099926",
658
+ // "brokerFilters": [],
659
+ // "symbols": [
660
+ // {
661
+ // "filters": [
662
+ // {
663
+ // "minPrice": "0.01",
664
+ // "maxPrice": "10000000.00000000",
665
+ // "tickSize": "0.01",
666
+ // "filterType": "PRICE_FILTER"
667
+ // },
668
+ // {
669
+ // "minQty": "0.0001",
670
+ // "maxQty": "4000",
671
+ // "stepSize": "0.0001",
672
+ // "filterType": "LOT_SIZE"
673
+ // },
674
+ // {
675
+ // "minNotional": "5",
676
+ // "filterType": "MIN_NOTIONAL"
677
+ // },
678
+ // {
679
+ // "minAmount": "5",
680
+ // "maxAmount": "6600000",
681
+ // "minBuyPrice": "0.01",
682
+ // "filterType": "TRADE_AMOUNT"
683
+ // },
684
+ // {
685
+ // "maxSellPrice": "99999999",
686
+ // "buyPriceUpRate": "0.1",
687
+ // "sellPriceDownRate": "0.1",
688
+ // "filterType": "LIMIT_TRADING"
689
+ // },
690
+ // {
691
+ // "buyPriceUpRate": "0.1",
692
+ // "sellPriceDownRate": "0.1",
693
+ // "filterType": "MARKET_TRADING"
694
+ // },
695
+ // {
696
+ // "noAllowMarketStartTime": "0",
697
+ // "noAllowMarketEndTime": "0",
698
+ // "limitOrderStartTime": "0",
699
+ // "limitOrderEndTime": "0",
700
+ // "limitMinPrice": "0",
701
+ // "limitMaxPrice": "0",
702
+ // "filterType": "OPEN_QUOTE"
703
+ // }
704
+ // ],
705
+ // "exchangeId": "301",
706
+ // "symbol": "ETHUSDT",
707
+ // "symbolName": "ETHUSDT",
708
+ // "status": "TRADING",
709
+ // "baseAsset": "ETH",
710
+ // "baseAssetName": "ETH",
711
+ // "baseAssetPrecision": "0.0001",
712
+ // "quoteAsset": "USDT",
713
+ // "quoteAssetName": "USDT",
714
+ // "quotePrecision": "0.01",
715
+ // "icebergAllowed": false,
716
+ // "isAggregate": false,
717
+ // "allowMargin": true,
718
+ // }
719
+ // ],
720
+ // "options": [],
721
+ // "contracts": [
722
+ // {
723
+ // "filters": [ ... ],
724
+ // "exchangeId": "301",
725
+ // "symbol": "BTC-SWAP-USDT",
726
+ // "symbolName": "BTC-SWAP-USDTUSDT",
727
+ // "status": "TRADING",
728
+ // "baseAsset": "BTC-SWAP-USDT",
729
+ // "baseAssetPrecision": "0.001",
730
+ // "quoteAsset": "USDT",
731
+ // "quoteAssetPrecision": "0.1",
732
+ // "icebergAllowed": false,
733
+ // "inverse": false,
734
+ // "index": "BTC",
735
+ // "indexToken": "BTCUSDT",
736
+ // "marginToken": "USDT",
737
+ // "marginPrecision": "0.0001",
738
+ // "contractMultiplier": "0.001",
739
+ // "underlying": "BTC",
740
+ // "riskLimits": [
741
+ // {
742
+ // "riskLimitId": "200020911",
743
+ // "quantity": "42000.0",
744
+ // "initialMargin": "0.02",
745
+ // "maintMargin": "0.01",
746
+ // "isWhite": false
747
+ // },
748
+ // {
749
+ // "riskLimitId": "200020912",
750
+ // "quantity": "84000.0",
751
+ // "initialMargin": "0.04",
752
+ // "maintMargin": "0.02",
753
+ // "isWhite": false
754
+ // },
755
+ // ...
756
+ // ]
757
+ // },
758
+ // ],
759
+ // "coins": [
760
+ // {
761
+ // "orgId": "9001",
762
+ // "coinId": "TCOM",
763
+ // "coinName": "TCOM",
764
+ // "coinFullName": "TCOM",
765
+ // "allowWithdraw": true,
766
+ // "allowDeposit": true,
767
+ // "chainTypes": [
768
+ // {
769
+ // "chainType": "BSC",
770
+ // "withdrawFee": "49.55478",
771
+ // "minWithdrawQuantity": "77",
772
+ // "maxWithdrawQuantity": "0",
773
+ // "minDepositQuantity": "48",
774
+ // "allowDeposit": true,
775
+ // "allowWithdraw": false
776
+ // }
777
+ // ],
778
+ // "isVirtual": false
779
+ // },
780
+ // ...
781
+ //
782
+ const symbols = this.safeList(response, 'symbols', []);
783
+ const contracts = this.safeList(response, 'contracts', []);
784
+ const all = this.arrayConcat(symbols, contracts);
785
+ const result = [];
786
+ for (let i = 0; i < all.length; i++) {
787
+ const market = all[i];
788
+ const parsed = this.parseMarket(market);
789
+ result.push(parsed);
790
+ }
791
+ return result;
792
+ }
793
+ parseMarket(market) {
794
+ const id = this.safeString(market, 'symbol');
795
+ const baseId = this.safeString(market, 'baseAsset');
796
+ const quoteId = this.safeString(market, 'quoteAsset');
797
+ const baseParts = baseId.split('-');
798
+ const baseIdClean = baseParts[0];
799
+ const base = this.safeCurrencyCode(baseIdClean);
800
+ const quote = this.safeCurrencyCode(quoteId);
801
+ const settleId = this.safeString(market, 'marginToken');
802
+ const settle = this.safeCurrencyCode(settleId);
803
+ const status = this.safeString(market, 'status');
804
+ const active = (status === 'TRADING');
805
+ const filters = this.safeList(market, 'filters', []);
806
+ const filtersByType = this.indexBy(filters, 'filterType');
807
+ const priceFilter = this.safeDict(filtersByType, 'PRICE_FILTER', {});
808
+ const lotSizeFilter = this.safeDict(filtersByType, 'LOT_SIZE', {});
809
+ const minNotionalFilter = this.safeDict(filtersByType, 'MIN_NOTIONAL', {});
810
+ let symbol = base + '/' + quote;
811
+ const isContract = ('contractMultiplier' in market);
812
+ const inverse = this.safeBool2(market, 'isInverse', 'inverse');
813
+ if (isContract) {
814
+ symbol += ':' + settle;
815
+ }
816
+ return this.safeMarketStructure({
817
+ 'id': id,
818
+ 'symbol': symbol,
819
+ 'base': base,
820
+ 'quote': quote,
821
+ 'settle': settle,
822
+ 'baseId': baseId,
823
+ 'quoteId': quoteId,
824
+ 'settleId': settleId,
825
+ 'type': isContract ? 'swap' : 'spot',
826
+ 'spot': !isContract,
827
+ 'margin': false,
828
+ 'swap': isContract,
829
+ 'future': false,
830
+ 'option': false,
831
+ 'active': active,
832
+ 'contract': isContract,
833
+ 'linear': isContract ? !inverse : undefined,
834
+ 'inverse': isContract ? inverse : undefined,
835
+ 'contractSize': this.safeNumber(market, 'contractMultiplier'),
836
+ 'expiry': undefined,
837
+ 'expiryDatetime': undefined,
838
+ 'strike': undefined,
839
+ 'optionType': undefined,
840
+ 'precision': {
841
+ 'amount': this.safeNumber(lotSizeFilter, 'stepSize'),
842
+ 'price': this.safeNumber(priceFilter, 'tickSize'),
843
+ },
844
+ 'limits': {
845
+ 'leverage': {
846
+ 'min': undefined,
847
+ 'max': undefined,
848
+ },
849
+ 'amount': {
850
+ 'min': this.safeNumber(lotSizeFilter, 'minQty'),
851
+ 'max': this.safeNumber(lotSizeFilter, 'maxQty'),
852
+ },
853
+ 'price': {
854
+ 'min': this.safeNumber(priceFilter, 'minPrice'),
855
+ 'max': this.safeNumber(priceFilter, 'maxPrice'),
856
+ },
857
+ 'cost': {
858
+ 'min': this.safeNumber(minNotionalFilter, 'minNotional'),
859
+ 'max': undefined,
860
+ },
861
+ },
862
+ 'created': undefined,
863
+ 'info': market,
864
+ });
865
+ }
866
+ /**
867
+ * @method
868
+ * @name toobit#fetchOrderBook
869
+ * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
870
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#order-book
871
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#order-book
872
+ * @param {string} symbol unified symbol of the market to fetch the order book for
873
+ * @param {int} [limit] the maximum amount of order book entries to return
874
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
875
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
876
+ */
877
+ async fetchOrderBook(symbol, limit = undefined, params = {}) {
878
+ await this.loadMarkets();
879
+ const market = this.market(symbol);
880
+ const request = {
881
+ 'symbol': market['id'],
882
+ };
883
+ if (limit !== undefined) {
884
+ request['limit'] = limit;
885
+ }
886
+ const response = await this.commonGetQuoteV1Depth(this.extend(request, params));
887
+ //
888
+ // {
889
+ // "t": "1755593995237",
890
+ // "b": [
891
+ // [
892
+ // "115186.47",
893
+ // "4.184864"
894
+ // ],
895
+ // [
896
+ // "115186.46",
897
+ // "0.002756"
898
+ // ],
899
+ // ...
900
+ // ],
901
+ // "a": [
902
+ // [
903
+ // "115186.48",
904
+ // "6.137369"
905
+ // ],
906
+ // [
907
+ // "115186.49",
908
+ // "0.002914"
909
+ // ],
910
+ // ...
911
+ // ]
912
+ // }
913
+ //
914
+ const timestamp = this.safeInteger(response, 't');
915
+ return this.parseOrderBook(response, market['symbol'], timestamp, 'b', 'a');
916
+ }
917
+ /**
918
+ * @method
919
+ * @name toobit#fetchTrades
920
+ * @description get a list of the most recent trades for a particular symbol
921
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#recent-trades-list
922
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#recent-trades-list
923
+ * @param {string} symbol unified symbol of the market to fetch trades for
924
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
925
+ * @param {int} [limit] the maximum number of trades to fetch
926
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
927
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
928
+ */
929
+ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
930
+ await this.loadMarkets();
931
+ const market = this.market(symbol);
932
+ const request = {
933
+ 'symbol': market['id'],
934
+ };
935
+ if (limit !== undefined) {
936
+ request['limit'] = limit;
937
+ }
938
+ const response = await this.commonGetQuoteV1Trades(this.extend(request, params));
939
+ //
940
+ // [
941
+ // {
942
+ // "t": "1755594277287",
943
+ // "p": "115276.99",
944
+ // "q": "0.001508",
945
+ // "ibm": true
946
+ // },
947
+ // ]
948
+ //
949
+ return this.parseTrades(response, market, since, limit);
950
+ }
951
+ parseTrade(trade, market = undefined) {
952
+ //
953
+ // fetchTrades
954
+ //
955
+ // {
956
+ // "t": "1755594277287",
957
+ // "p": "115276.99",
958
+ // "q": "0.001508",
959
+ // "ibm": true
960
+ // },
961
+ // // watchTrades have also an additional fields:
962
+ // "v": "4864732022868004630", // trade id
963
+ // "m": true, // is the buyer taker
964
+ //
965
+ // fetchMyTrades
966
+ //
967
+ // {
968
+ // "id": "2024934575206059008",
969
+ // "symbol": "ETHUSDT",
970
+ // "orderId": "2024934575097029888",
971
+ // "ticketId": "4864450547563401875",
972
+ // "price": "4641.21",
973
+ // "qty": "0.001",
974
+ // "time": "1756127012094",
975
+ // "isMaker": false,
976
+ // "commission": "0.00464121",
977
+ // "commissionAsset": "USDT",
978
+ // "makerRebate": "0",
979
+ // "symbolName": "ETHUSDT", // only in SPOT
980
+ // "isBuyer": false, // only in SPOT
981
+ // "feeAmount": "0.00464121", // only in SPOT
982
+ // "feeCoinId": "USDT", // only in SPOT
983
+ // "fee": { // only in SPOT
984
+ // "feeCoinId": "USDT",
985
+ // "feeCoinName": "USDT",
986
+ // "fee": "0.00464121"
987
+ // },
988
+ // "type": "LIMIT", // only in CONTRACT
989
+ // "side": "BUY_OPEN", // only in CONTRACT
990
+ // "realizedPnl": "0", // only in CONTRACT
991
+ // },
992
+ //
993
+ const timestamp = this.safeInteger2(trade, 't', 'time');
994
+ const priceString = this.safeString2(trade, 'p', 'price');
995
+ const amountString = this.safeString2(trade, 'q', 'qty');
996
+ const isBuyer = this.safeBool(trade, 'isBuyer');
997
+ let side = undefined;
998
+ let isBuyerMaker = this.safeBool(trade, 'ibm');
999
+ if (isBuyerMaker === undefined) {
1000
+ const isBuyerTaker = this.safeBool(trade, 'm');
1001
+ if (isBuyerTaker !== undefined) {
1002
+ isBuyerMaker = !isBuyerTaker;
1003
+ }
1004
+ }
1005
+ if (isBuyerMaker !== undefined) {
1006
+ if (isBuyerMaker) {
1007
+ side = 'sell';
1008
+ }
1009
+ else {
1010
+ side = 'buy';
1011
+ }
1012
+ }
1013
+ else {
1014
+ if (isBuyer) {
1015
+ side = 'buy';
1016
+ }
1017
+ else {
1018
+ side = 'sell';
1019
+ }
1020
+ }
1021
+ const feeCurrencyId = this.safeString(trade, 'feeCoinId');
1022
+ const feeAmount = this.safeString(trade, 'feeAmount');
1023
+ let fee = undefined;
1024
+ if (feeAmount !== undefined) {
1025
+ fee = {
1026
+ 'currency': this.safeCurrencyCode(feeCurrencyId),
1027
+ 'cost': feeAmount,
1028
+ };
1029
+ }
1030
+ const isMaker = this.safeBool(trade, 'isMaker');
1031
+ let takerOrMaker = undefined;
1032
+ if (isMaker !== undefined) {
1033
+ takerOrMaker = isMaker ? 'maker' : 'taker';
1034
+ }
1035
+ market = this.safeMarket(undefined, market);
1036
+ const symbol = market['symbol'];
1037
+ return this.safeTrade({
1038
+ 'info': trade,
1039
+ 'timestamp': timestamp,
1040
+ 'datetime': this.iso8601(timestamp),
1041
+ 'symbol': symbol,
1042
+ 'id': this.safeString2(trade, 'id', 'v'),
1043
+ 'order': this.safeString(trade, 'orderId'),
1044
+ 'type': undefined,
1045
+ 'side': side,
1046
+ 'amount': amountString,
1047
+ 'price': priceString,
1048
+ 'cost': undefined,
1049
+ 'takerOrMaker': takerOrMaker,
1050
+ 'fee': fee,
1051
+ }, market);
1052
+ }
1053
+ /**
1054
+ * @method
1055
+ * @name toobit#fetchOHLCV
1056
+ * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1057
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#kline-candlestick-data
1058
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#kline-candlestick-data
1059
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
1060
+ * @param {string} timeframe the length of time each candle represents
1061
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
1062
+ * @param {int} [limit] the maximum amount of candles to fetch
1063
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1064
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
1065
+ */
1066
+ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
1067
+ await this.loadMarkets();
1068
+ const market = this.market(symbol);
1069
+ const request = {
1070
+ 'symbol': market['id'],
1071
+ 'interval': this.safeString(this.timeframes, timeframe, timeframe),
1072
+ };
1073
+ if (since !== undefined) {
1074
+ request['startTime'] = since;
1075
+ }
1076
+ const until = this.safeInteger(params, 'until');
1077
+ if (until !== undefined) {
1078
+ params = this.omit(params, 'until');
1079
+ request['endTime'] = until;
1080
+ }
1081
+ if (limit !== undefined) {
1082
+ request['limit'] = limit;
1083
+ }
1084
+ let response = undefined;
1085
+ let endpoint = undefined;
1086
+ [endpoint, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'price');
1087
+ if (endpoint === 'index') {
1088
+ response = await this.commonGetQuoteV1IndexKlines(this.extend(request, params));
1089
+ //
1090
+ // {
1091
+ // "code": 200,
1092
+ // "data": [
1093
+ // {
1094
+ // "t": 1669155300000,//time
1095
+ // "s": "ETHUSDT",// symbol
1096
+ // "sn": "ETHUSDT",//symbol name
1097
+ // "c": "1127.1",//Close price
1098
+ // "h": "1130.81",//High price
1099
+ // "l": "1126.17",//Low price
1100
+ // "o": "1130.8",//Open price
1101
+ // "v": "0"//Volume
1102
+ // },
1103
+ // {
1104
+ // "t": 1669156200000,
1105
+ // "s": "ETHUSDT",
1106
+ // "sn": "ETHUSDT",
1107
+ // "c": "1129.44",
1108
+ // "h": "1129.54",
1109
+ // "l": "1127.1",
1110
+ // "o": "1127.1",
1111
+ // "v": "0"
1112
+ // }
1113
+ // ]
1114
+ // }
1115
+ //
1116
+ }
1117
+ else if (endpoint === 'mark') {
1118
+ response = await this.commonGetQuoteV1MarkPriceKlines(this.extend(request, params));
1119
+ //
1120
+ // {
1121
+ // "code": 200,
1122
+ // "data": [
1123
+ // {
1124
+ // "symbol": "BTCUSDT",// Symbol
1125
+ // "time": 1670157900000,// time
1126
+ // "low": "16991.14096",//Low price
1127
+ // "open": "16991.78288",//Open price
1128
+ // "high": "16996.30641",// High prce
1129
+ // "close": "16996.30641",// Close price
1130
+ // "volume": "0",// Volume
1131
+ // "curId": 1670157900000
1132
+ // }
1133
+ // ]
1134
+ // }
1135
+ //
1136
+ }
1137
+ else {
1138
+ response = await this.commonGetQuoteV1Klines(this.extend(request, params));
1139
+ //
1140
+ // [
1141
+ // [
1142
+ // 1755540660000,
1143
+ // "116399.99",
1144
+ // "116399.99",
1145
+ // "116360.09",
1146
+ // "116360.1",
1147
+ // "2.236869",
1148
+ // 0,
1149
+ // "260303.79722607",
1150
+ // 22,
1151
+ // "2.221061",
1152
+ // "258464.10338267"
1153
+ // ],
1154
+ // ...
1155
+ //
1156
+ }
1157
+ return this.parseOHLCVs(response, market, timeframe, since, limit);
1158
+ }
1159
+ parseOHLCV(ohlcv, market = undefined) {
1160
+ return [
1161
+ this.safeIntegerN(ohlcv, [0, 'time', 't']),
1162
+ this.safeNumberN(ohlcv, [1, 'open', 'o']),
1163
+ this.safeNumberN(ohlcv, [2, 'high', 'h']),
1164
+ this.safeNumberN(ohlcv, [3, 'low', 'l']),
1165
+ this.safeNumberN(ohlcv, [4, 'close', 'c']),
1166
+ this.safeNumberN(ohlcv, [5, 'volume', 'v']),
1167
+ ];
1168
+ }
1169
+ /**
1170
+ * @method
1171
+ * @name toobit#fetchTickers
1172
+ * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1173
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#24hr-ticker-price-change-statistics
1174
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#24hr-ticker-price-change-statistics
1175
+ * @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1176
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1177
+ * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1178
+ */
1179
+ async fetchTickers(symbols = undefined, params = {}) {
1180
+ await this.loadMarkets();
1181
+ symbols = this.marketSymbols(symbols);
1182
+ let type = undefined;
1183
+ let market = undefined;
1184
+ const request = {};
1185
+ if (symbols !== undefined) {
1186
+ const symbol = this.safeString(symbols, 0);
1187
+ market = this.market(symbol);
1188
+ const length = symbols.length;
1189
+ if (length === 1) {
1190
+ request['symbol'] = market['id'];
1191
+ }
1192
+ }
1193
+ [type, params] = this.handleMarketTypeAndParams('fetchTickers', market, params);
1194
+ let response = undefined;
1195
+ if (type === 'spot') {
1196
+ response = await this.commonGetQuoteV1Ticker24hr(this.extend(request, params));
1197
+ }
1198
+ else {
1199
+ response = await this.commonGetQuoteV1ContractTicker24hr(this.extend(request, params));
1200
+ }
1201
+ //
1202
+ // [
1203
+ // {
1204
+ // "t": "1755601440162",
1205
+ // "s": "GRDRUSDT",
1206
+ // "o": "0.38",
1207
+ // "h": "0.38",
1208
+ // "l": "0.38",
1209
+ // "c": "0.38",
1210
+ // "v": "0",
1211
+ // "qv": "0",
1212
+ // "pc": "0",
1213
+ // "pcp": "0"
1214
+ // },
1215
+ // ...
1216
+ //
1217
+ return this.parseTickers(response, symbols, params);
1218
+ }
1219
+ parseTicker(ticker, market = undefined) {
1220
+ const marketId = this.safeString(ticker, 's');
1221
+ market = this.safeMarket(marketId, market);
1222
+ const timestamp = this.safeInteger(ticker, 't');
1223
+ const last = this.safeString(ticker, 'c');
1224
+ return this.safeTicker({
1225
+ 'symbol': market['symbol'],
1226
+ 'timestamp': timestamp,
1227
+ 'datetime': this.iso8601(timestamp),
1228
+ 'high': this.safeString(ticker, 'h'),
1229
+ 'low': this.safeString(ticker, 'l'),
1230
+ 'bid': undefined,
1231
+ 'bidVolume': undefined,
1232
+ 'ask': undefined,
1233
+ 'askVolume': undefined,
1234
+ 'vwap': undefined,
1235
+ 'open': this.safeString(ticker, 'o'),
1236
+ 'close': last,
1237
+ 'last': last,
1238
+ 'previousClose': undefined,
1239
+ 'change': this.safeString(ticker, 'pc'),
1240
+ 'percentage': this.safeString(ticker, 'pcp'),
1241
+ 'average': undefined,
1242
+ 'baseVolume': this.safeString(ticker, 'v'),
1243
+ 'quoteVolume': this.safeString(ticker, 'qv'),
1244
+ 'info': ticker,
1245
+ }, market);
1246
+ }
1247
+ /**
1248
+ * @method
1249
+ * @name toobit#fetchLastPrices
1250
+ * @description fetches the last price for multiple markets
1251
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#symbol-price-ticker
1252
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#symbol-price-ticker
1253
+ * @param {string[]|undefined} symbols unified symbols of the markets to fetch the last prices
1254
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1255
+ * @returns {object} a dictionary of lastprices structures
1256
+ */
1257
+ async fetchLastPrices(symbols = undefined, params = {}) {
1258
+ await this.loadMarkets();
1259
+ symbols = this.marketSymbols(symbols);
1260
+ const request = {};
1261
+ if (symbols !== undefined) {
1262
+ const length = symbols.length;
1263
+ if (length === 1) {
1264
+ const market = this.market(symbols[0]);
1265
+ request['symbol'] = market['id'];
1266
+ }
1267
+ }
1268
+ const response = await this.commonGetQuoteV1TickerPrice(this.extend(request, params));
1269
+ //
1270
+ // [
1271
+ // {
1272
+ // "s": "BNTUSDT",
1273
+ // "si": "BNTUSDT",
1274
+ // "p": "0.823"
1275
+ // },
1276
+ //
1277
+ return this.parseLastPrices(response, symbols);
1278
+ }
1279
+ parseLastPrice(entry, market = undefined) {
1280
+ const marketId = this.safeString(entry, 's');
1281
+ market = this.safeMarket(marketId, market);
1282
+ return {
1283
+ 'symbol': market['symbol'],
1284
+ 'timestamp': undefined,
1285
+ 'datetime': undefined,
1286
+ 'price': this.safeNumberOmitZero(entry, 'price'),
1287
+ 'side': undefined,
1288
+ 'info': entry,
1289
+ };
1290
+ }
1291
+ /**
1292
+ * @method
1293
+ * @name toobit#fetchBidsAsks
1294
+ * @description fetches the bid and ask price and volume for multiple markets
1295
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#symbol-order-book-ticker
1296
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#symbol-order-book-ticker
1297
+ * @param {string[]} [symbols] unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
1298
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1299
+ * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1300
+ */
1301
+ async fetchBidsAsks(symbols = undefined, params = {}) {
1302
+ await this.loadMarkets();
1303
+ symbols = this.marketSymbols(symbols);
1304
+ const request = {};
1305
+ if (symbols !== undefined) {
1306
+ const length = symbols.length;
1307
+ if (length === 1) {
1308
+ const market = this.market(symbols[0]);
1309
+ request['symbol'] = market['id'];
1310
+ }
1311
+ }
1312
+ const response = await this.commonGetQuoteV1TickerBookTicker(this.extend(request, params));
1313
+ //
1314
+ // [
1315
+ // {
1316
+ // "s": "GRDRUSDT",
1317
+ // "b": "0",
1318
+ // "bq": "0",
1319
+ // "a": "0",
1320
+ // "aq": "0",
1321
+ // "t": "1755936610506"
1322
+ // }, ...
1323
+ //
1324
+ return this.parseBidsAsksCustom(response, symbols);
1325
+ }
1326
+ parseBidsAsksCustom(tickers, symbols = undefined, params = {}) {
1327
+ const results = [];
1328
+ for (let i = 0; i < tickers.length; i++) {
1329
+ const parsedTicker = this.parseBidAskCustom(tickers[i]);
1330
+ const ticker = this.extend(parsedTicker, params);
1331
+ results.push(ticker);
1332
+ }
1333
+ symbols = this.marketSymbols(symbols);
1334
+ return this.filterByArray(results, 'symbol', symbols);
1335
+ }
1336
+ parseBidAskCustom(ticker) {
1337
+ return {
1338
+ 'timestamp': this.safeString(ticker, 't'),
1339
+ 'symbol': this.safeString(ticker, 's'),
1340
+ 'bid': this.safeNumber(ticker, 'b'),
1341
+ 'bidVolume': this.safeNumber(ticker, 'bq'),
1342
+ 'ask': this.safeNumber(ticker, 'a'),
1343
+ 'askVolume': this.safeNumber(ticker, 'aq'),
1344
+ 'info': ticker,
1345
+ };
1346
+ }
1347
+ /**
1348
+ * @method
1349
+ * @name toobit#fetchFundingRates
1350
+ * @description fetch the funding rate for multiple markets
1351
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#funding-rate
1352
+ * @param {string[]|undefined} symbols list of unified market symbols
1353
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1354
+ * @returns {object[]} a list of [funding rates structures]{@link https://docs.ccxt.com/#/?id=funding-rates-structure}, indexe by market symbols
1355
+ */
1356
+ async fetchFundingRates(symbols = undefined, params = {}) {
1357
+ await this.loadMarkets();
1358
+ symbols = this.marketSymbols(symbols);
1359
+ const request = {};
1360
+ if (symbols !== undefined) {
1361
+ const length = symbols.length;
1362
+ if (length === 1) {
1363
+ const market = this.market(symbols[0]);
1364
+ request['symbol'] = market['id'];
1365
+ }
1366
+ }
1367
+ const response = await this.commonGetApiV1FuturesFundingRate(this.extend(request, params));
1368
+ //
1369
+ // [
1370
+ // {
1371
+ // "symbol": "BTC-SWAP-USDT",
1372
+ // "rate": "0.0001071148112848",
1373
+ // "nextFundingTime": "1755964800000"
1374
+ // },...
1375
+ //
1376
+ return this.parseFundingRates(response, symbols);
1377
+ }
1378
+ parseFundingRate(contract, market = undefined) {
1379
+ const marketId = this.safeString(contract, 'symbol');
1380
+ const symbol = this.safeSymbol(marketId, market);
1381
+ const nextFundingRate = this.safeNumber(contract, 'rate');
1382
+ const nextFundingRateTimestamp = this.safeInteger(contract, 'nextFundingTime');
1383
+ return {
1384
+ 'info': contract,
1385
+ 'symbol': symbol,
1386
+ 'markPrice': undefined,
1387
+ 'indexPrice': undefined,
1388
+ 'interestRate': undefined,
1389
+ 'estimatedSettlePrice': undefined,
1390
+ 'timestamp': undefined,
1391
+ 'datetime': undefined,
1392
+ 'previousFundingRate': undefined,
1393
+ 'nextFundingRate': undefined,
1394
+ 'previousFundingTimestamp': undefined,
1395
+ 'nextFundingTimestamp': undefined,
1396
+ 'previousFundingDatetime': undefined,
1397
+ 'nextFundingDatetime': undefined,
1398
+ 'fundingRate': nextFundingRate,
1399
+ 'fundingTimestamp': nextFundingRateTimestamp,
1400
+ 'fundingDatetime': this.iso8601(nextFundingRateTimestamp),
1401
+ 'interval': undefined,
1402
+ };
1403
+ }
1404
+ /**
1405
+ * @method
1406
+ * @name toobit#fetchFundingRateHistory
1407
+ * @description fetches historical funding rate prices
1408
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#get-funding-rate-history
1409
+ * @param {string} symbol unified symbol of the market to fetch the funding rate history for
1410
+ * @param {int} [since] timestamp in ms of the earliest funding rate to fetch
1411
+ * @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} to fetch
1412
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1413
+ * @param {int} [params.until] timestamp in ms of the latest funding rate to fetch
1414
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1415
+ * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure}
1416
+ */
1417
+ async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1418
+ await this.loadMarkets();
1419
+ let paginate = false;
1420
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchFundingRateHistory', 'paginate');
1421
+ if (paginate) {
1422
+ return await this.fetchPaginatedCallDeterministic('fetchFundingRateHistory', symbol, since, limit, '8h', params);
1423
+ }
1424
+ const market = this.market(symbol);
1425
+ const request = {
1426
+ 'symbol': market['id'],
1427
+ };
1428
+ if (limit !== undefined) {
1429
+ request['limit'] = limit;
1430
+ }
1431
+ const response = await this.commonGetApiV1FuturesHistoryFundingRate(this.extend(request, params));
1432
+ //
1433
+ // [
1434
+ // {
1435
+ // "id": "869931",
1436
+ // "symbol": "BTC-SWAP-USDT",
1437
+ // "settleTime": "1755936000000",
1438
+ // "settleRate": "0.0001"
1439
+ // }, ...
1440
+ //
1441
+ return this.parseFundingRateHistories(response, market, since, limit);
1442
+ }
1443
+ parseFundingRateHistory(contract, market = undefined) {
1444
+ const timestamp = this.safeInteger(contract, 'settleTime');
1445
+ const marketId = this.safeString(contract, 'symbol');
1446
+ return {
1447
+ 'info': contract,
1448
+ 'symbol': this.safeSymbol(marketId, market),
1449
+ 'fundingRate': this.safeNumber(contract, 'settleRate'),
1450
+ 'timestamp': timestamp,
1451
+ 'datetime': this.iso8601(timestamp),
1452
+ };
1453
+ }
1454
+ /**
1455
+ * @method
1456
+ * @name toobit#fetchBalance
1457
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
1458
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#account-information-user_data
1459
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#futures-account-balance-user_data
1460
+ * @param {object} [params] extra parameters specific to the exchange API endpointinvalid
1461
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
1462
+ */
1463
+ async fetchBalance(params = {}) {
1464
+ await this.loadMarkets();
1465
+ let response = undefined;
1466
+ let marketType = undefined;
1467
+ [marketType, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params);
1468
+ if (this.inArray(marketType, ['swap', 'future'])) {
1469
+ response = await this.privateGetApiV1FuturesBalance();
1470
+ //
1471
+ // [
1472
+ // {
1473
+ // "asset": "USDT", // asset
1474
+ // "balance": "999999999999.982", // total
1475
+ // "availableBalance": "1899999999978.4995", // available balance Include unrealized pnl
1476
+ // "positionMargin": "11.9825", //position Margin
1477
+ // "orderMargin": "9.5", //order Margin
1478
+ // "crossUnRealizedPnl": "10.01" //The unrealized profit and loss of cross position
1479
+ // }
1480
+ // ]
1481
+ //
1482
+ }
1483
+ else {
1484
+ response = await this.privateGetApiV1Account();
1485
+ //
1486
+ // {
1487
+ // "userId": "912902020",
1488
+ // "balances": [
1489
+ // {
1490
+ // "asset": "ETH",
1491
+ // "assetId": "ETH",
1492
+ // "assetName": "ETH",
1493
+ // "total": "0.025",
1494
+ // "free": "0.025",
1495
+ // "locked": "0"
1496
+ // }
1497
+ // ]
1498
+ // }
1499
+ //
1500
+ }
1501
+ return this.parseBalance(response);
1502
+ }
1503
+ parseBalance(response) {
1504
+ const result = {
1505
+ 'info': response,
1506
+ 'timestamp': undefined,
1507
+ 'datetime': undefined,
1508
+ };
1509
+ const balances = this.safeList(response, 'balances', response);
1510
+ for (let i = 0; i < balances.length; i++) {
1511
+ const balance = balances[i];
1512
+ const code = this.safeCurrencyCode(this.safeString(balance, 'asset'));
1513
+ const account = this.account();
1514
+ account['free'] = this.safeString2(balance, 'free', 'availableBalance');
1515
+ account['total'] = this.safeString2(balance, 'total', 'balance');
1516
+ account['used'] = this.safeString(balance, 'locked');
1517
+ result[code] = account;
1518
+ }
1519
+ return this.safeBalance(result);
1520
+ }
1521
+ /**
1522
+ * @method
1523
+ * @name toobit#createOrder
1524
+ * @description create a trade order
1525
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#new-order-trade
1526
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#new-order-trade
1527
+ * @param {string} symbol unified symbol of the market to create an order in
1528
+ * @param {string} type 'market', 'limit'
1529
+ * @param {string} side 'buy' or 'sell'
1530
+ * @param {float} amount how much of currency you want to trade in units of base currency
1531
+ * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1532
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1533
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1534
+ */
1535
+ async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
1536
+ await this.loadMarkets();
1537
+ const market = this.market(symbol);
1538
+ let request = {};
1539
+ let response = undefined;
1540
+ if (market['spot']) {
1541
+ [request, params] = this.createOrderRequest(symbol, type, side, amount, price, params);
1542
+ response = await this.privatePostApiV1SpotOrder(this.extend(request, params));
1543
+ }
1544
+ else {
1545
+ [request, params] = this.createContractOrderRequest(symbol, type, side, amount, price, params);
1546
+ response = await this.privatePostApiV1FuturesOrder(this.extend(request, params));
1547
+ }
1548
+ //
1549
+ // {
1550
+ // "symbol": "ETHUSDT",
1551
+ // "price": "0",
1552
+ // "origQty": "0.001",
1553
+ // "orderId": "2024837825254460160",
1554
+ // "clientOrderId": "1756115478113679",
1555
+ // "executedQty": "0",
1556
+ // "status": "PENDING_NEW",
1557
+ // "timeInForce": "GTC",
1558
+ // "type": "MARKET",
1559
+ // "side": "SELL"
1560
+ // "accountId": "1783404067076253952", // only in spot
1561
+ // "symbolName": "ETHUSDT", // only in spot
1562
+ // "transactTime": "1756115478604", // only in spot
1563
+ // "time": "1668418485058", // only in contract
1564
+ // "updateTime": "1668418485058", // only in contract
1565
+ // "leverage": "2", // only in contract
1566
+ // "avgPrice": "0", // only in contract
1567
+ // "marginLocked": "9.5", // only in contract
1568
+ // "priceType": "INPUT" // only in contract
1569
+ // }
1570
+ //
1571
+ return this.parseOrder(response, market);
1572
+ }
1573
+ createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
1574
+ const market = this.market(symbol);
1575
+ const id = market['id'];
1576
+ const request = {
1577
+ 'symbol': id,
1578
+ 'side': side.toUpperCase(),
1579
+ };
1580
+ if (price !== undefined) {
1581
+ request['price'] = this.priceToPrecision(symbol, price);
1582
+ }
1583
+ let cost = undefined;
1584
+ [cost, params] = this.handleParamString(params, 'cost');
1585
+ if (type === 'market') {
1586
+ if (cost === undefined && side === 'buy') {
1587
+ throw new ArgumentsRequired(this.id + ' createOrder() requires params["cost"] for market buy order');
1588
+ }
1589
+ else {
1590
+ request['quantity'] = this.costToPrecision(symbol, cost);
1591
+ }
1592
+ }
1593
+ else {
1594
+ request['quantity'] = this.amountToPrecision(symbol, amount);
1595
+ }
1596
+ let isPostOnly = undefined;
1597
+ [isPostOnly, params] = this.handlePostOnly(type === 'market', false, params);
1598
+ if (isPostOnly) {
1599
+ request['type'] = 'LIMIT_MAKER';
1600
+ }
1601
+ else {
1602
+ request['type'] = type.toUpperCase();
1603
+ }
1604
+ return [request, params];
1605
+ }
1606
+ createContractOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
1607
+ const market = this.market(symbol);
1608
+ const request = {
1609
+ 'symbol': market['id'],
1610
+ 'quantity': this.amountToPrecision(symbol, amount),
1611
+ };
1612
+ let reduceOnly = undefined;
1613
+ [reduceOnly, params] = this.handleParamBool(params, 'reduceOnly');
1614
+ if (side === 'buy') {
1615
+ side = reduceOnly ? 'SELL_CLOSE' : 'BUY_OPEN';
1616
+ }
1617
+ else if (side === 'sell') {
1618
+ side = reduceOnly ? 'BUY_CLOSE' : 'SELL_OPEN';
1619
+ }
1620
+ request['side'] = side;
1621
+ if (price !== undefined) {
1622
+ request['price'] = this.priceToPrecision(symbol, price);
1623
+ }
1624
+ if (this.inArray(type, ['limit', 'LIMIT'])) {
1625
+ request['type'] = type.toUpperCase();
1626
+ request['price'] = this.priceToPrecision(symbol, price);
1627
+ }
1628
+ else if (type === 'market') {
1629
+ request['type'] = 'LIMIT'; // weird, but exchange works this way
1630
+ request['priceType'] = 'MARKET';
1631
+ }
1632
+ let isPostOnly = undefined;
1633
+ [isPostOnly, params] = this.handlePostOnly(type === 'market', false, params);
1634
+ if (isPostOnly) {
1635
+ request['timeInForce'] = 'LIMIT_MAKER';
1636
+ }
1637
+ const values = this.handleTriggerPricesAndParams(symbol, params);
1638
+ const triggerPrice = values[0];
1639
+ params = values[3];
1640
+ if (triggerPrice !== undefined) {
1641
+ request['stopPrice'] = triggerPrice;
1642
+ }
1643
+ const stopLoss = this.safeDict(params, 'stopLoss');
1644
+ const takeProfit = this.safeDict(params, 'takeProfit');
1645
+ const triggerPriceTypes = {
1646
+ 'mark': 'MARK_PRICE',
1647
+ 'last': 'CONTRACT_PRICE',
1648
+ };
1649
+ if (stopLoss !== undefined) {
1650
+ request['stopLoss'] = this.safeValue(stopLoss, 'triggerPrice');
1651
+ const limitPrice = this.safeValue(stopLoss, 'price');
1652
+ if (limitPrice !== undefined) {
1653
+ request['slOrderType'] = 'LIMIT';
1654
+ request['slLimitPrice'] = this.priceToPrecision(symbol, limitPrice);
1655
+ }
1656
+ const triggerPriceType = this.safeString(stopLoss, 'triggerPriceType');
1657
+ if (triggerPriceType !== undefined) {
1658
+ request['slTriggerBy'] = this.safeString(triggerPriceTypes, triggerPriceType, triggerPriceType);
1659
+ }
1660
+ params = this.omit(params, 'stopLoss');
1661
+ }
1662
+ if (takeProfit !== undefined) {
1663
+ request['takeProfit'] = this.safeValue(takeProfit, 'triggerPrice');
1664
+ const limitPrice = this.safeValue(takeProfit, 'price');
1665
+ if (limitPrice !== undefined) {
1666
+ request['tpOrderType'] = 'LIMIT';
1667
+ request['tpLimitPrice'] = this.priceToPrecision(symbol, limitPrice);
1668
+ }
1669
+ const triggerPriceType = this.safeString(takeProfit, 'triggerPriceType');
1670
+ if (triggerPriceType !== undefined) {
1671
+ request['tpTriggerBy'] = this.safeString(triggerPriceTypes, triggerPriceType, triggerPriceType);
1672
+ }
1673
+ params = this.omit(params, 'takeProfit');
1674
+ }
1675
+ if (!('newClientOrderId' in params)) {
1676
+ request['newClientOrderId'] = this.uuid();
1677
+ }
1678
+ return [request, params];
1679
+ }
1680
+ parseOrder(order, market = undefined) {
1681
+ //
1682
+ // createOrder, cancelOrder
1683
+ //
1684
+ // {
1685
+ // "symbol": "ETHUSDT",
1686
+ // "price": "0",
1687
+ // "origQty": "0.001",
1688
+ // "orderId": "2024837825254460160",
1689
+ // "clientOrderId": "1756115478113679",
1690
+ // "executedQty": "0",
1691
+ // "status": "PENDING_NEW",
1692
+ // "timeInForce": "GTC",
1693
+ // "type": "MARKET",
1694
+ // "side": "SELL"
1695
+ // "accountId": "1783404067076253952", // only in spot
1696
+ // "symbolName": "ETHUSDT", // only in spot
1697
+ // "transactTime": "1756115478604", // only in spot
1698
+ // "time": "1668418485058", // only in contract
1699
+ // "updateTime": "1668418485058", // only in contract
1700
+ // "leverage": "2", // only in contract
1701
+ // "avgPrice": "0", // only in contract
1702
+ // "marginLocked": "9.5", // only in contract
1703
+ // "priceType": "INPUT" // only in contract
1704
+ // }
1705
+ //
1706
+ //
1707
+ // fetchOrder, fetchOrders, fetchOpenOrders
1708
+ //
1709
+ // {
1710
+ // "time": "1756140208069",
1711
+ // "updateTime": "1756140208078",
1712
+ // "orderId": "2025045271033977089",
1713
+ // "clientOrderId": "17561402075722006",
1714
+ // "symbol": "ETHUSDT",
1715
+ // "price": "3000",
1716
+ // "origQty": "0.002",
1717
+ // "executedQty": "0",
1718
+ // "avgPrice": "0",
1719
+ // "type": "LIMIT",
1720
+ // "side": "BUY",
1721
+ // "timeInForce": "GTC",
1722
+ // "status": "NEW",
1723
+ // "accountId": "1783404067076253952", // only in SPOT
1724
+ // "exchangeId": "301", // only in SPOT
1725
+ // "symbolName": "ETHUSDT", // only in SPOT
1726
+ // "cummulativeQuoteQty": "0", // only in SPOT
1727
+ // "cumulativeQuoteQty": "0", // only in SPOT
1728
+ // "stopPrice": "0.0", // only in SPOT
1729
+ // "icebergQty": "0.0", // only in SPOT
1730
+ // "isWorking": true // only in SPOT
1731
+ // "leverage": "2", // only in CONTRACT
1732
+ // "marginLocked": "9.5", // only in CONTRACT
1733
+ // "priceType": "INPUT" // only in CONTRACT
1734
+ // "triggerType": "0", // only in CONTRACT fetchClosedOrders
1735
+ // "fallType": "0", // only in CONTRACT fetchClosedOrders
1736
+ // "activeStatus": "0" // only in CONTRACT fetchClosedOrders
1737
+ // }
1738
+ //
1739
+ const timestamp = this.safeInteger2(order, 'transactTime', 'time');
1740
+ const marketId = this.safeString(order, 'symbol');
1741
+ market = this.safeMarket(marketId, market);
1742
+ const rawType = this.safeString(order, 'type');
1743
+ const rawSideLower = this.safeStringLower(order, 'side');
1744
+ let triggerPrice = this.omitZero(this.safeString(order, 'stopPrice'));
1745
+ if (triggerPrice === '0.0') {
1746
+ triggerPrice = undefined;
1747
+ }
1748
+ return this.safeOrder({
1749
+ 'info': order,
1750
+ 'id': this.safeString(order, 'orderId'),
1751
+ 'clientOrderId': this.safeString(order, 'clientOrderId'),
1752
+ 'timestamp': timestamp,
1753
+ 'datetime': this.iso8601(timestamp),
1754
+ 'lastTradeTimestamp': undefined,
1755
+ 'lastUpdateTimestamp': this.safeInteger(order, 'updateTime'),
1756
+ 'status': this.parseOrderStatus(this.safeString(order, 'status')),
1757
+ 'symbol': market['symbol'],
1758
+ 'type': this.parseOrderType(rawType),
1759
+ 'timeInForce': this.safeString(order, 'timeInForce'),
1760
+ 'postOnly': (rawType === 'LIMIT_MAKER'),
1761
+ 'side': rawSideLower,
1762
+ 'price': this.omitZero(this.safeString(order, 'price')),
1763
+ 'triggerPrice': triggerPrice,
1764
+ 'cost': this.omitZero(this.safeString(order, 'cumulativeQuoteQty')),
1765
+ 'average': this.safeString(order, 'avgPrice'),
1766
+ 'amount': this.safeString(order, 'origQty'),
1767
+ 'filled': this.safeString(order, 'executedQty'),
1768
+ 'remaining': undefined,
1769
+ 'trades': undefined,
1770
+ 'fee': undefined,
1771
+ 'marginMode': undefined,
1772
+ 'reduceOnly': undefined,
1773
+ 'leverage': undefined,
1774
+ 'hedged': undefined,
1775
+ }, market);
1776
+ }
1777
+ parseOrderStatus(status) {
1778
+ const statuses = {
1779
+ 'PENDING_NEW': 'open',
1780
+ 'NEW': 'open',
1781
+ 'PARTIALLY_FILLED': 'open',
1782
+ 'FILLED': 'closed',
1783
+ 'PENDING_CANCEL': 'canceled',
1784
+ 'CANCELED': 'canceled',
1785
+ 'REJECTED': 'canceled',
1786
+ };
1787
+ return this.safeString(statuses, status, status);
1788
+ }
1789
+ parseOrderType(status) {
1790
+ const statuses = {
1791
+ 'MARKET': 'market',
1792
+ 'LIMIT': 'limit',
1793
+ 'LIMIT_MAKER': 'limit',
1794
+ };
1795
+ return this.safeString(statuses, status, status);
1796
+ }
1797
+ /**
1798
+ * @method
1799
+ * @name toobit#cancelOrder
1800
+ * @description cancels an open order
1801
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#cancel-order-trade
1802
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#cancel-order-trade
1803
+ * @param {string} id order id
1804
+ * @param {string} symbol unified symbol of the market the order was made in
1805
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1806
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1807
+ */
1808
+ async cancelOrder(id, symbol = undefined, params = {}) {
1809
+ const request = {};
1810
+ if (this.safeString(params, 'clientOrderId') === undefined) {
1811
+ request['orderId'] = id;
1812
+ }
1813
+ let market = undefined;
1814
+ if (symbol !== undefined) {
1815
+ market = this.market(symbol);
1816
+ request['symbol'] = market['id'];
1817
+ }
1818
+ let marketType = undefined;
1819
+ [marketType, params] = this.handleMarketTypeAndParams('cancelOrder', market, params, 'none');
1820
+ if (marketType === 'none') {
1821
+ throw new ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument or the "defaultType" parameter to be set to "spot" or "swap"');
1822
+ }
1823
+ let response = undefined;
1824
+ if (marketType === 'spot') {
1825
+ response = await this.privateDeleteApiV1SpotOrder(this.extend(request, params));
1826
+ }
1827
+ else {
1828
+ response = await this.privateDeleteApiV1FuturesOrder(this.extend(request, params));
1829
+ }
1830
+ // response same as in `createOrder`
1831
+ const status = this.parseOrderStatus(this.safeString(response, 'status'));
1832
+ if (status !== 'open') {
1833
+ throw new OrderNotFound(this.id + ' order ' + id + ' can not be canceled, ' + this.json(response));
1834
+ }
1835
+ return this.parseOrder(response, market);
1836
+ }
1837
+ /**
1838
+ * @method
1839
+ * @name toobit#cancelAllOrders
1840
+ * @description cancel all open orders in a market
1841
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#cancel-all-open-orders-trade
1842
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#cancel-orders-trade
1843
+ * @param {string} symbol unified symbol
1844
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1845
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
1846
+ */
1847
+ async cancelAllOrders(symbol = undefined, params = {}) {
1848
+ await this.loadMarkets();
1849
+ const request = {};
1850
+ let market = undefined;
1851
+ if (symbol !== undefined) {
1852
+ market = this.market(symbol);
1853
+ request['symbol'] = market['id'];
1854
+ }
1855
+ let marketType = undefined;
1856
+ [marketType, params] = this.handleMarketTypeAndParams('cancelAllOrders', market, params, 'none');
1857
+ if (marketType === 'none') {
1858
+ throw new ArgumentsRequired(this.id + ' cancelAllOrders() requires a symbol argument or the "defaultType" parameter to be set to "spot" or "swap"');
1859
+ }
1860
+ let response = undefined;
1861
+ if (marketType === 'spot') {
1862
+ response = await this.privateDeleteApiV1SpotOpenOrders(this.extend(request, params));
1863
+ //
1864
+ // {"success":true} // always same response
1865
+ //
1866
+ }
1867
+ else {
1868
+ response = await this.privateDeleteApiV1FuturesBatchOrders(this.extend(request, params));
1869
+ //
1870
+ // { "code": 200, "message":"success", "timestamp":1541161088303 }
1871
+ //
1872
+ }
1873
+ return [
1874
+ this.safeOrder({
1875
+ 'info': response,
1876
+ }),
1877
+ ];
1878
+ }
1879
+ /**
1880
+ * @method
1881
+ * @name toobit#cancelOrders
1882
+ * @description cancel multiple orders
1883
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#cancel-multiple-orders-trade
1884
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#cancel-multiple-orders-trade
1885
+ * @param {string[]} ids order ids
1886
+ * @param {string} [symbol] unified market symbol
1887
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1888
+ * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
1889
+ */
1890
+ async cancelOrders(ids, symbol = undefined, params = {}) {
1891
+ await this.loadMarkets();
1892
+ const idsString = ids.join(',');
1893
+ const request = {
1894
+ 'ids': idsString,
1895
+ };
1896
+ let market = undefined;
1897
+ if (symbol !== undefined) {
1898
+ market = this.market(symbol);
1899
+ }
1900
+ let marketType = undefined;
1901
+ [marketType, params] = this.handleMarketTypeAndParams('cancelOrders', market, params, 'none');
1902
+ if (marketType === 'none') {
1903
+ throw new ArgumentsRequired(this.id + ' cancelOrders() requires a symbol argument or the "defaultType" parameter to be set to "spot" or "swap"');
1904
+ }
1905
+ let response = undefined;
1906
+ if (marketType === 'spot') {
1907
+ response = await this.privateDeleteApiV1SpotCancelOrderByIds(this.extend(request, params));
1908
+ //
1909
+ // {"success":true} // always same response
1910
+ //
1911
+ }
1912
+ else {
1913
+ response = await this.privateDeleteApiV1FuturesCancelOrderByIds(this.extend(request, params));
1914
+ //
1915
+ // {
1916
+ // "code":200,
1917
+ // "result":[
1918
+ // {
1919
+ // "orderId":"1327047813809448704",
1920
+ // "code":-2013
1921
+ // },
1922
+ // {
1923
+ // "orderId":"1327047814212101888",
1924
+ // "code":-2013
1925
+ // }
1926
+ // ]
1927
+ // }
1928
+ //
1929
+ // or empty array if no orders were canceled
1930
+ }
1931
+ const result = this.safeList(response, 'result', []);
1932
+ return this.parseOrders(result, market);
1933
+ }
1934
+ /**
1935
+ * @method
1936
+ * @name toobit#fetchOrder
1937
+ * @description fetches information on an order made by the user
1938
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#query-order-user_data
1939
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#query-order-user_data
1940
+ * @param {string} id the order id
1941
+ * @param {string} symbol unified symbol of the market the order was made in
1942
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1943
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1944
+ */
1945
+ async fetchOrder(id, symbol = undefined, params = {}) {
1946
+ if (symbol === undefined) {
1947
+ throw new ArgumentsRequired(this.id + ' fetchOrder() requires a symbol argument');
1948
+ }
1949
+ await this.loadMarkets();
1950
+ const request = {
1951
+ 'orderId': id,
1952
+ };
1953
+ const market = this.market(symbol);
1954
+ let response = undefined;
1955
+ if (market['spot']) {
1956
+ response = await this.privateGetApiV1SpotOrder(this.extend(request, params));
1957
+ }
1958
+ else {
1959
+ response = await this.privateGetApiV1FuturesOrder(this.extend(request, params));
1960
+ }
1961
+ //
1962
+ // {
1963
+ // "time": "1756140208069",
1964
+ // "updateTime": "1756140208078",
1965
+ // "orderId": "2025045271033977089",
1966
+ // "clientOrderId": "17561402075722006",
1967
+ // "symbol": "ETHUSDT",
1968
+ // "price": "3000",
1969
+ // "origQty": "0.002",
1970
+ // "executedQty": "0",
1971
+ // "avgPrice": "0",
1972
+ // "type": "LIMIT",
1973
+ // "side": "BUY",
1974
+ // "timeInForce": "GTC",
1975
+ // "status": "NEW",
1976
+ // "accountId": "1783404067076253952", // only in SPOT
1977
+ // "exchangeId": "301", // only in SPOT
1978
+ // "symbolName": "ETHUSDT", // only in SPOT
1979
+ // "cummulativeQuoteQty": "0", // only in SPOT
1980
+ // "cumulativeQuoteQty": "0", // only in SPOT
1981
+ // "stopPrice": "0.0", // only in SPOT
1982
+ // "icebergQty": "0.0", // only in SPOT
1983
+ // "isWorking": true // only in SPOT
1984
+ // "leverage": "2", // only in CONTRACT
1985
+ // "marginLocked": "9.5", // only in CONTRACT
1986
+ // "priceType": "INPUT" // only in CONTRACT
1987
+ // }
1988
+ //
1989
+ return this.parseOrder(response, market);
1990
+ }
1991
+ /**
1992
+ * @method
1993
+ * @name toobit#fetchOpenOrders
1994
+ * @description fetches information on multiple orders made by the user
1995
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#current-open-orders-user_data
1996
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#query-current-open-order-user_data
1997
+ * @param {string} symbol unified market symbol of the market orders were made in
1998
+ * @param {int} [since] the earliest time in ms to fetch orders for
1999
+ * @param {int} [limit] the maximum number of order structures to retrieve
2000
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2001
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2002
+ */
2003
+ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2004
+ await this.loadMarkets();
2005
+ const request = {};
2006
+ let market = undefined;
2007
+ if (symbol !== undefined) {
2008
+ market = this.market(symbol);
2009
+ request['symbol'] = market['id'];
2010
+ }
2011
+ if (limit !== undefined) {
2012
+ request['limit'] = limit;
2013
+ }
2014
+ let marketType = undefined;
2015
+ [marketType, params] = this.handleMarketTypeAndParams('fetchOrders', market, params);
2016
+ let response = undefined;
2017
+ if (marketType === 'spot') {
2018
+ response = await this.privateGetApiV1SpotOpenOrders(this.extend(request, params));
2019
+ //
2020
+ // [
2021
+ // {
2022
+ // "accountId": "1783404067076253952",
2023
+ // "exchangeId": "301",
2024
+ // "symbol": "ETHUSDT",
2025
+ // "symbolName": "ETHUSDT",
2026
+ // "clientOrderId": "17561415157172008",
2027
+ // "orderId": "2025056244339984384",
2028
+ // "price": "3000",
2029
+ // "origQty": "0.002",
2030
+ // "executedQty": "0",
2031
+ // "cummulativeQuoteQty": "0",
2032
+ // "cumulativeQuoteQty": "0",
2033
+ // "avgPrice": "0",
2034
+ // "status": "NEW",
2035
+ // "timeInForce": "GTC",
2036
+ // "type": "LIMIT",
2037
+ // "side": "BUY",
2038
+ // "stopPrice": "0.0",
2039
+ // "icebergQty": "0.0",
2040
+ // "time": "1756141516189",
2041
+ // "updateTime": "1756141516198",
2042
+ // "isWorking": true
2043
+ // }, ...
2044
+ // ]
2045
+ //
2046
+ }
2047
+ else {
2048
+ response = await this.privateGetApiV1FuturesOpenOrders(this.extend(request, params));
2049
+ }
2050
+ return this.parseOrders(response, market, since, limit);
2051
+ }
2052
+ /**
2053
+ * @method
2054
+ * @name toobit#fetchOrders
2055
+ * @description fetches information on multiple orders made by the user
2056
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#all-orders-user_data
2057
+ * @param {string} symbol unified market symbol of the market orders were made in
2058
+ * @param {int} [since] the earliest time in ms to fetch orders for
2059
+ * @param {int} [limit] the maximum number of order structures to retrieve
2060
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2061
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2062
+ */
2063
+ async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2064
+ await this.loadMarkets();
2065
+ let request = {};
2066
+ if (limit !== undefined) {
2067
+ request['limit'] = limit;
2068
+ }
2069
+ if (since !== undefined) {
2070
+ request['startTime'] = since;
2071
+ }
2072
+ [request, params] = this.handleUntilOption('endTime', request, params);
2073
+ let market = undefined;
2074
+ if (symbol !== undefined) {
2075
+ market = this.market(symbol);
2076
+ request['symbol'] = market['id'];
2077
+ }
2078
+ let marketType = undefined;
2079
+ [marketType, params] = this.handleMarketTypeAndParams('fetchOrders', market, params);
2080
+ let response = undefined;
2081
+ if (marketType === 'spot') {
2082
+ response = await this.privateGetApiV1SpotTradeOrders(request);
2083
+ //
2084
+ // [
2085
+ // {
2086
+ // "accountId": "1783404067076253952",
2087
+ // "exchangeId": "301",
2088
+ // "symbol": "ETHUSDT",
2089
+ // "symbolName": "ETHUSDT",
2090
+ // "clientOrderId": "17561415157172008",
2091
+ // "orderId": "2025056244339984384",
2092
+ // "price": "3000",
2093
+ // "origQty": "0.002",
2094
+ // "executedQty": "0",
2095
+ // "cummulativeQuoteQty": "0",
2096
+ // "cumulativeQuoteQty": "0",
2097
+ // "avgPrice": "0",
2098
+ // "status": "NEW",
2099
+ // "timeInForce": "GTC",
2100
+ // "type": "LIMIT",
2101
+ // "side": "BUY",
2102
+ // "stopPrice": "0.0",
2103
+ // "icebergQty": "0.0",
2104
+ // "time": "1756141516189",
2105
+ // "updateTime": "1756141516198",
2106
+ // "isWorking": true
2107
+ // }, ...
2108
+ // ]
2109
+ //
2110
+ }
2111
+ else {
2112
+ throw new NotSupported(this.id + ' fetchOrders() is not supported for ' + marketType + ' markets');
2113
+ }
2114
+ return this.parseOrders(response, market, since, limit);
2115
+ }
2116
+ /**
2117
+ * @method
2118
+ * @name toobit#fetchClosedOrders
2119
+ * @description fetches information on multiple closed orders made by the user
2120
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#query-history-orders-user_data
2121
+ * @param {string} symbol unified market symbol of the market orders were made in
2122
+ * @param {int} [since] the earliest time in ms to fetch orders for
2123
+ * @param {int} [limit] the maximum number of order structures to retrieve
2124
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2125
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2126
+ */
2127
+ async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2128
+ // returns the most recent closed or canceled orders up to circa two weeks ago
2129
+ await this.loadMarkets();
2130
+ let request = {};
2131
+ let market = undefined;
2132
+ if (symbol !== undefined) {
2133
+ market = this.market(symbol);
2134
+ request['symbol'] = market['id'];
2135
+ }
2136
+ if (since !== undefined) {
2137
+ request['startTime'] = since;
2138
+ }
2139
+ [request, params] = this.handleUntilOption('endTime', request, params);
2140
+ let marketType = undefined;
2141
+ [marketType, params] = this.handleMarketTypeAndParams('fetchClosedOrders', market, params);
2142
+ let response = undefined;
2143
+ if (marketType === 'spot') {
2144
+ throw new NotSupported(this.id + ' fetchOrders() is not supported for ' + marketType + ' markets');
2145
+ }
2146
+ else {
2147
+ response = await this.privateGetApiV1FuturesHistoryOrders(request);
2148
+ //
2149
+ // [
2150
+ // {
2151
+ // "time": "1756756879360",
2152
+ // "updateTime": "1756757165956",
2153
+ // "orderId": "2030218284767504128",
2154
+ // "clientOrderId": "1756756876002",
2155
+ // "symbol": "SOL-SWAP-USDT",
2156
+ // "price": "144",
2157
+ // "leverage": "50",
2158
+ // "origQty": "1",
2159
+ // "executedQty": "0",
2160
+ // "executeQty": "0",
2161
+ // "avgPrice": "0",
2162
+ // "marginLocked": "0",
2163
+ // "type": "LIMIT",
2164
+ // "side": "BUY_OPEN",
2165
+ // "timeInForce": "GTC",
2166
+ // "status": "CANCELED",
2167
+ // "priceType": "INPUT",
2168
+ // "triggerType": "0",
2169
+ // "fallType": "0",
2170
+ // "activeStatus": "0"
2171
+ // }
2172
+ // ]
2173
+ //
2174
+ }
2175
+ const ordersList = [];
2176
+ for (let i = 0; i < response.length; i++) {
2177
+ ordersList.push({ 'result': response[i] });
2178
+ }
2179
+ return this.parseOrders(ordersList, market, since, limit);
2180
+ }
2181
+ /**
2182
+ * @method
2183
+ * @name toobit#fetchMyTrades
2184
+ * @description fetch all trades made by the user
2185
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#account-trade-list-user_data
2186
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#account-trade-list-user_data
2187
+ * @param {string} [symbol] unified market symbol
2188
+ * @param {int} [since] the earliest time in ms to fetch trades for
2189
+ * @param {int} [limit] the maximum number of trade structures to retrieve
2190
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2191
+ * @param {int} [params.until] the latest time in ms to fetch trades for
2192
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
2193
+ */
2194
+ async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2195
+ if (symbol === undefined) {
2196
+ throw new ArgumentsRequired(this.id + ' fetchMyTrades() requires a symbol argument');
2197
+ }
2198
+ await this.loadMarkets();
2199
+ let request = {};
2200
+ if (since !== undefined) {
2201
+ request['startTime'] = since;
2202
+ }
2203
+ if (limit !== undefined) {
2204
+ request['limit'] = limit;
2205
+ }
2206
+ const market = this.market(symbol);
2207
+ request['symbol'] = market['id'];
2208
+ let marketType = undefined;
2209
+ [marketType, params] = this.handleMarketTypeAndParams('fetchMyTrades', market, params);
2210
+ [request, params] = this.handleUntilOption('endTime', request, params);
2211
+ let response = undefined;
2212
+ if (marketType === 'spot') {
2213
+ response = await this.privateGetApiV1AccountTrades(this.extend(request, params));
2214
+ //
2215
+ // [
2216
+ // {
2217
+ // "id": "2024934575206059008",
2218
+ // "symbol": "ETHUSDT",
2219
+ // "symbolName": "ETHUSDT",
2220
+ // "orderId": "2024934575097029888",
2221
+ // "price": "4641.21",
2222
+ // "qty": "0.001",
2223
+ // "commission": "0.00464121",
2224
+ // "commissionAsset": "USDT",
2225
+ // "time": "1756127012094",
2226
+ // "isBuyer": false,
2227
+ // "isMaker": false,
2228
+ // "fee": {
2229
+ // "feeCoinId": "USDT",
2230
+ // "feeCoinName": "USDT",
2231
+ // "fee": "0.00464121"
2232
+ // },
2233
+ // "feeCoinId": "USDT",
2234
+ // "feeAmount": "0.00464121",
2235
+ // "makerRebate": "0",
2236
+ // "ticketId": "4864450547563401875"
2237
+ // }, ...
2238
+ //
2239
+ }
2240
+ else {
2241
+ response = await this.privateGetApiV1FuturesUserTrades(request);
2242
+ //
2243
+ // [
2244
+ // {
2245
+ // "time": "1756758426899",
2246
+ // "id": "2030231266499116032",
2247
+ // "orderId": "2030231266373265152",
2248
+ // "symbol": "DOGE-SWAP-USDT",
2249
+ // "price": "0.21191",
2250
+ // "qty": "63",
2251
+ // "commissionAsset": "USDT",
2252
+ // "commission": "0.00801019",
2253
+ // "makerRebate": "0",
2254
+ // "type": "LIMIT",
2255
+ // "side": "BUY_OPEN",
2256
+ // "realizedPnl": "0",
2257
+ // "ticketId": "4900760819871364854",
2258
+ // "isMaker": false
2259
+ // }
2260
+ // ]
2261
+ //
2262
+ }
2263
+ return this.parseTrades(response, market, since, limit);
2264
+ }
2265
+ /**
2266
+ * @method
2267
+ * @name toobit#transfer
2268
+ * @description transfer currency internally between wallets on the same account
2269
+ * @see https://open.big.one/docs/spot_transfer.html#transfer-of-user
2270
+ * @param {string} code unified currency code
2271
+ * @param {float} amount amount to transfer
2272
+ * @param {string} fromAccount 'spot', 'swap'
2273
+ * @param {string} toAccount 'spot', 'swap'
2274
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2275
+ * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure}
2276
+ */
2277
+ async transfer(code, amount, fromAccount, toAccount, params = {}) {
2278
+ await this.loadMarkets();
2279
+ const currency = this.currency(code);
2280
+ const accountsByType = this.safeDict(this.options, 'accountsByType', {});
2281
+ const fromId = this.safeString(accountsByType, fromAccount, fromAccount);
2282
+ const toId = this.safeString(accountsByType, toAccount, toAccount);
2283
+ const request = {
2284
+ 'asset': currency['id'],
2285
+ 'quantity': this.currencyToPrecision(code, amount),
2286
+ 'fromAccountType': fromId,
2287
+ 'toAccountType': toId,
2288
+ };
2289
+ const response = await this.privatePostApiV1SubAccountTransfer(this.extend(request, params));
2290
+ //
2291
+ // {
2292
+ // "code": 200, // 200 = success
2293
+ // "msg": "success" // response message
2294
+ // }
2295
+ //
2296
+ return this.parseTransfer(response, currency);
2297
+ }
2298
+ parseTransfer(transfer, currency = undefined) {
2299
+ //
2300
+ // {
2301
+ // "code": 200, // 200 = success
2302
+ // "msg": "success" // response message
2303
+ // }
2304
+ //
2305
+ return {
2306
+ 'info': transfer,
2307
+ 'id': undefined,
2308
+ 'timestamp': undefined,
2309
+ 'datetime': undefined,
2310
+ 'currency': undefined,
2311
+ 'amount': undefined,
2312
+ 'fromAccount': undefined,
2313
+ 'toAccount': undefined,
2314
+ 'status': undefined,
2315
+ };
2316
+ }
2317
+ /**
2318
+ * @method
2319
+ * @name toobit#fetchLedger
2320
+ * @description fetch the history of changes, actions done by the user or operations that altered the balance of the user
2321
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#get-account-transaction-history-list-user_data
2322
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#get-future-account-transaction-history-list-user_data
2323
+ * @param {string} [code] unified currency code, default is undefined
2324
+ * @param {int} [since] timestamp in ms of the earliest ledger entry, default is undefined
2325
+ * @param {int} [limit] max number of ledger entries to return, default is undefined
2326
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2327
+ * @param {int} [params.until] end time in ms
2328
+ * @returns {object} a [ledger structure]{@link https://docs.ccxt.com/#/?id=ledger}
2329
+ */
2330
+ async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
2331
+ await this.loadMarkets();
2332
+ let currency = undefined;
2333
+ let request = {};
2334
+ if (code !== undefined) {
2335
+ currency = this.currency(code);
2336
+ request['coin'] = currency['id'];
2337
+ }
2338
+ if (since !== undefined) {
2339
+ request['startTime'] = since;
2340
+ }
2341
+ [request, params] = this.handleUntilOption('endTime', request, params);
2342
+ if (limit !== undefined) {
2343
+ request['limit'] = limit;
2344
+ }
2345
+ let marketType = undefined;
2346
+ [marketType, params] = this.handleMarketTypeAndParams('cancelAllOrders', undefined, params);
2347
+ let response = undefined;
2348
+ if (marketType === 'spot') {
2349
+ response = await this.privateGetApiV1AccountBalanceFlow(this.extend(request, params));
2350
+ }
2351
+ else {
2352
+ response = await this.privateGetApiV1FuturesBalanceFlow(this.extend(request, params));
2353
+ }
2354
+ //
2355
+ // both answers are same format
2356
+ //
2357
+ // [
2358
+ // {
2359
+ // "id": "539870570957903104",
2360
+ // "accountId": "122216245228131",
2361
+ // "coin": "BTC",
2362
+ // "coinId": "BTC",
2363
+ // "coinName": "BTC",
2364
+ // "flowTypeValue": 51,
2365
+ // "flowType": "USER_ACCOUNT_TRANSFER",
2366
+ // "flowName": "Transfer",
2367
+ // "change": "-12.5",
2368
+ // "total": "379.624059937852365",
2369
+ // "created": "1579093587214"
2370
+ // },
2371
+ //
2372
+ return this.parseLedger(response, currency, since, limit);
2373
+ }
2374
+ parseLedgerEntry(item, currency = undefined) {
2375
+ const currencyId = this.safeString(item, 'coinId');
2376
+ currency = this.safeCurrency(currencyId, currency);
2377
+ const timestamp = this.safeInteger(item, 'created');
2378
+ const after = this.safeNumber(item, 'total');
2379
+ const amountRaw = this.safeString(item, 'change');
2380
+ const amount = this.parseNumber(Precise.stringAbs(amountRaw));
2381
+ let direction = 'in';
2382
+ if (amountRaw.startsWith('-')) {
2383
+ direction = 'out';
2384
+ }
2385
+ return this.safeLedgerEntry({
2386
+ 'info': item,
2387
+ 'id': this.safeString(item, 'id'),
2388
+ 'timestamp': timestamp,
2389
+ 'datetime': this.iso8601(timestamp),
2390
+ 'direction': direction,
2391
+ 'account': undefined,
2392
+ 'referenceId': undefined,
2393
+ 'referenceAccount': undefined,
2394
+ 'type': this.parseLedgerType(this.safeString(item, 'flowType')),
2395
+ 'currency': currency['code'],
2396
+ 'amount': amount,
2397
+ 'before': undefined,
2398
+ 'after': after,
2399
+ 'status': undefined,
2400
+ 'fee': undefined,
2401
+ }, currency);
2402
+ }
2403
+ parseLedgerType(type) {
2404
+ const types = {
2405
+ 'USER_ACCOUNT_TRANSFER': 'transfer',
2406
+ 'AIRDROP': 'rebate',
2407
+ };
2408
+ return this.safeString(types, type, type);
2409
+ }
2410
+ /**
2411
+ * @method
2412
+ * @name toobit#fetchTradingFees
2413
+ * @description fetch the trading fees for multiple markets
2414
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#user-trade-fee-rate-user_data
2415
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2416
+ * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols
2417
+ */
2418
+ async fetchTradingFees(params = {}) {
2419
+ await this.loadMarkets();
2420
+ let response = undefined;
2421
+ let marketType = undefined;
2422
+ let market = undefined;
2423
+ [marketType, params] = this.handleMarketTypeAndParams('fetchTradingFees', undefined, params);
2424
+ if (marketType === 'spot') {
2425
+ throw new NotSupported(this.id + ' fetchTradingFees(): does not support ' + marketType + ' markets');
2426
+ }
2427
+ else if (this.inArray(marketType, ['swap', 'future'])) {
2428
+ let symbol = undefined;
2429
+ [symbol, params] = this.handleParamString(params, 'symbol');
2430
+ if (symbol === undefined) {
2431
+ throw new BadRequest(this.id + ' fetchTradingFees requires a params["symbol"]');
2432
+ }
2433
+ market = this.market(symbol);
2434
+ const request = {
2435
+ 'symbol': market['id'],
2436
+ };
2437
+ response = await this.privateGetApiV1FuturesCommissionRate(this.extend(request, params));
2438
+ }
2439
+ //
2440
+ // {
2441
+ // "openMakerFee": "0.000006", // The trade fee rate for opening pending orders
2442
+ // "openTakerFee": "0.0001", // The trade fee rate for open position taker
2443
+ // "closeMakerFee": "0.0002", // The trade fee rate for closing pending orders
2444
+ // "closeTakerFee": "0.0004" // The trade fee rate for closing a taker order
2445
+ // }
2446
+ //
2447
+ const result = {};
2448
+ const entry = response;
2449
+ const marketId = this.safeString(entry, 'symbol');
2450
+ market = this.safeMarket(marketId, market);
2451
+ const fee = this.parseTradingFee(entry, market);
2452
+ result[market['symbol']] = fee;
2453
+ return result;
2454
+ }
2455
+ parseTradingFee(data, market = undefined) {
2456
+ const marketId = this.safeString(data, 'symbol');
2457
+ return {
2458
+ 'info': data,
2459
+ 'symbol': this.safeSymbol(marketId, market),
2460
+ 'maker': this.safeNumber(data, 'closeMakerFee'),
2461
+ 'taker': this.safeNumber(data, 'closeTakerFee'),
2462
+ 'percentage': undefined,
2463
+ 'tierBased': undefined,
2464
+ };
2465
+ }
2466
+ /**
2467
+ * @method
2468
+ * @name toobit#fetchDeposits
2469
+ * @description fetch all deposits made to an account
2470
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#deposit-history-user_data
2471
+ * @param {string} [code] unified currency code
2472
+ * @param {int} [since] the earliest time in ms to fetch deposits for
2473
+ * @param {int} [limit] the maximum number of deposit structures to retrieve
2474
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2475
+ * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
2476
+ */
2477
+ async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
2478
+ return await this.fetchDepositsOrWithdrawalsHelper('deposits', code, since, limit, params);
2479
+ }
2480
+ /**
2481
+ * @method
2482
+ * @name toobit#fetchWithdrawals
2483
+ * @description fetch all withdrawals made from an account
2484
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#withdrawal-records-user_data
2485
+ * @param {string} [code] unified currency code
2486
+ * @param {int} [since] the earliest time in ms to fetch withdrawals for
2487
+ * @param {int} [limit] the maximum number of withdrawal structures to retrieve
2488
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2489
+ * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
2490
+ */
2491
+ async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
2492
+ return await this.fetchDepositsOrWithdrawalsHelper('withdrawals', code, since, limit, params);
2493
+ }
2494
+ async fetchDepositsOrWithdrawalsHelper(type, code, since, limit, params) {
2495
+ await this.loadMarkets();
2496
+ let currency = undefined;
2497
+ let request = {};
2498
+ if (code !== undefined) {
2499
+ currency = this.currency(code);
2500
+ request['coin'] = currency['id'];
2501
+ }
2502
+ if (since !== undefined) {
2503
+ request['startTime'] = since;
2504
+ }
2505
+ [request, params] = this.handleUntilOption('endTime', request, params);
2506
+ if (limit !== undefined) {
2507
+ request['limit'] = limit;
2508
+ }
2509
+ let response = undefined;
2510
+ if (type === 'deposits') {
2511
+ response = await this.privateGetApiV1AccountDepositOrders(this.extend(request, params));
2512
+ //
2513
+ // [
2514
+ // {
2515
+ // "time": 1499865549590,
2516
+ // "id": 100234,
2517
+ // "coinName": "EOS",
2518
+ // "statusCode": "DEPOSIT_CAN_WITHDRAW",
2519
+ // "status": "2", // 2=SUCCESS, 11=REJECT, 12=AUDIT
2520
+ // "address": "deposit2bb",
2521
+ // "txId": "98A3EA560C6B3336D348B6C83F0F95ECE4F1F5919E94BD006E5BF3BF264FACFC",
2522
+ // "txIdUrl": "",
2523
+ // "requiredConfirmTimes": "5",
2524
+ // "confirmTimes": "5",
2525
+ // "quantity": "1.01",
2526
+ // "coin": "EOS",
2527
+ // "fromAddress": "clarkkent",
2528
+ // "fromAddressTag": "19029901"
2529
+ // "addressTag": "19012584",
2530
+ // }
2531
+ // ]
2532
+ //
2533
+ }
2534
+ else if (type === 'withdrawals') {
2535
+ response = await this.privateGetApiV1AccountWithdrawOrders(this.extend(request, params));
2536
+ //
2537
+ // [
2538
+ // {
2539
+ // "time":"1536232111669",
2540
+ // "id ":"90161227158286336",
2541
+ // "accountId":"517256161325920",
2542
+ // "coinName":"BHC",
2543
+ // "statusCode":"PROCESSING_STATUS",
2544
+ // "status":3,
2545
+ // "address":"0x815bF1c3cc0f49b8FC66B21A7e48fCb476051209",
2546
+ // "txId ":"",
2547
+ // "txIdUrl ":"",
2548
+ // "requiredConfirmTimes ":0, // Number of confirmation requests
2549
+ // "confirmTimes ":0, // number of confirmations
2550
+ // "quantity":"14", // Withdrawal amount
2551
+ // "coinId ":"BHC",
2552
+ // "addressExt":"address tag",
2553
+ // "arriveQuantity":"14",
2554
+ // "walletHandleTime":"1536232111669",
2555
+ // "feeCoinId ":"BHC",
2556
+ // "feeCoinName ":"BHC",
2557
+ // "fee":"0.1",
2558
+ // "kernelId":"", // Exclusive to BEAM and GRIN
2559
+ // "isInternalTransfer": false // Whether internal transfer
2560
+ // }
2561
+ // ]
2562
+ //
2563
+ }
2564
+ return this.parseTransactions(response, currency, since, limit, params);
2565
+ }
2566
+ parseTransaction(transaction, currency = undefined) {
2567
+ //
2568
+ // fetchDeposits & fetchWithdrawals
2569
+ //
2570
+ // {
2571
+ // "time": 1499865549590,
2572
+ // "id": 100234,
2573
+ // "coinName": "EOS",
2574
+ // "statusCode": "DEPOSIT_CAN_WITHDRAW",
2575
+ // "status": "2", // 2=SUCCESS, 11=REJECT, 12=AUDIT
2576
+ // "address": "deposit2bb",
2577
+ // "txId": "98A3EA560C6B3336D348B6C83F0F95ECE4F1F5919E94BD006E5BF3BF264FACFC",
2578
+ // "txIdUrl": "",
2579
+ // "requiredConfirmTimes": "5",
2580
+ // "confirmTimes": "5",
2581
+ // "quantity": "1.01",
2582
+ // "coin": "EOS", // present in "fetchDeposits"
2583
+ // "coinId ":"BHC", // present in "fetchWithdrawals"
2584
+ // "addressTag": "19012584", // present in "fetchDeposits"
2585
+ // "addressExt":"address tag", // present in "fetchWithdrawals"
2586
+ // "fromAddress": "clarkkent", // present in "fetchDeposits"
2587
+ // "fromAddressTag": "19029901" // present in "fetchDeposits"
2588
+ // "arriveQuantity":"14", // present in "fetchWithdrawals"
2589
+ // "walletHandleTime":"1536232111669",// present in "fetchWithdrawals"
2590
+ // "feeCoinId ":"BHC", // present in "fetchWithdrawals"
2591
+ // "feeCoinName ":"BHC", // present in "fetchWithdrawals"
2592
+ // "fee":"0.1", // present in "fetchWithdrawals"
2593
+ // "kernelId":"", // present in "fetchWithdrawals"
2594
+ // "isInternalTransfer": false // present in "fetchWithdrawals"
2595
+ // }
2596
+ //
2597
+ // withdraw
2598
+ //
2599
+ // {
2600
+ // "status": 0,
2601
+ // "success": true,
2602
+ // "needBrokerAudit": false, // Do you need a brokerage review?
2603
+ // "id": "423885103582776064",
2604
+ // "refuseReason":"" // failure rejection reason
2605
+ // }
2606
+ //
2607
+ const timestamp = this.safeInteger(transaction, 'time');
2608
+ const currencyId = this.safeString2(transaction, 'coin', 'coinId');
2609
+ const code = this.safeCurrencyCode(currencyId, currency);
2610
+ const feeString = this.safeString(transaction, 'fee');
2611
+ const feeCoin = this.safeString(transaction, 'feeCoinName');
2612
+ let fee = undefined;
2613
+ if (feeString !== undefined) {
2614
+ fee = {
2615
+ 'cost': this.parseNumber(feeString),
2616
+ 'currency': this.safeCurrencyCode(feeCoin),
2617
+ };
2618
+ }
2619
+ const tagTo = this.safeString2(transaction, 'addressTag', 'addressExt');
2620
+ const tagFrom = this.safeString(transaction, 'fromAddressTag');
2621
+ const addressTo = this.safeString(transaction, 'address');
2622
+ const addressFrom = this.safeString(transaction, 'fromAddress');
2623
+ const isWithdraw = ('arriveQuantity' in transaction);
2624
+ const type = isWithdraw ? 'withdrawal' : 'deposit';
2625
+ return {
2626
+ 'info': transaction,
2627
+ 'id': this.safeString(transaction, 'id'),
2628
+ 'txid': this.safeString(transaction, 'txId'),
2629
+ 'timestamp': timestamp,
2630
+ 'datetime': this.iso8601(timestamp),
2631
+ 'network': undefined,
2632
+ 'address': undefined,
2633
+ 'addressTo': addressTo,
2634
+ 'addressFrom': addressFrom,
2635
+ 'tag': undefined,
2636
+ 'tagTo': tagTo,
2637
+ 'tagFrom': tagFrom,
2638
+ 'type': type,
2639
+ 'amount': this.safeNumber(transaction, 'quantity'),
2640
+ 'currency': code,
2641
+ 'status': this.parseTransactionStatus(this.safeString(transaction, 'status')),
2642
+ 'updated': undefined,
2643
+ 'fee': fee,
2644
+ 'comment': undefined,
2645
+ 'internal': undefined,
2646
+ };
2647
+ }
2648
+ parseTransactionStatus(status) {
2649
+ const statuses = {
2650
+ '2': 'pending',
2651
+ '12': 'pending',
2652
+ '11': 'failed',
2653
+ '3': 'ok',
2654
+ };
2655
+ return this.safeString(statuses, status, status);
2656
+ }
2657
+ /**
2658
+ * @method
2659
+ * @name toobit#fetchDepositAddress
2660
+ * @description fetch the deposit address for a currency associated with this account
2661
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#deposit-address-user_data
2662
+ * @param {string} code unified currency code
2663
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2664
+ * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure}
2665
+ */
2666
+ async fetchDepositAddress(code, params = {}) {
2667
+ await this.loadMarkets();
2668
+ const currency = this.currency(code);
2669
+ const request = {
2670
+ 'coin': currency['id'],
2671
+ };
2672
+ const [networkCode, paramsOmitted] = this.handleNetworkCodeAndParams(this.extend(request, params));
2673
+ if (networkCode === undefined) {
2674
+ throw new ArgumentsRequired(this.id + ' fetchDepositAddress() : param["network"] is required');
2675
+ }
2676
+ request['chainType'] = this.networkCodeToId(networkCode);
2677
+ const response = await this.privateGetApiV1AccountDepositAddress(this.extend(request, paramsOmitted));
2678
+ //
2679
+ // {
2680
+ // "canDeposit":false,//Is it possible to recharge
2681
+ // "address":"0x815bF1c3cc0f49b8FC66B21A7e48fCb476051209",
2682
+ // "addressExt":"address tag",
2683
+ // "minQuantity":"100",//minimum amount
2684
+ // "requiredConfirmTimes ":1,//Arrival confirmation number
2685
+ // "canWithdrawConfirmNum ":12,//Withdrawal confirmation number
2686
+ // "coinType":"ERC20_TOKEN"
2687
+ // }
2688
+ //
2689
+ return this.parseDepositAddress(response, currency);
2690
+ }
2691
+ parseDepositAddress(depositAddress, currency = undefined) {
2692
+ const address = this.safeString(depositAddress, 'address');
2693
+ this.checkAddress(address);
2694
+ return {
2695
+ 'info': depositAddress,
2696
+ 'currency': this.safeString(currency, 'code'),
2697
+ 'network': undefined,
2698
+ 'address': address,
2699
+ 'tag': this.safeString(depositAddress, 'addressExt'),
2700
+ };
2701
+ }
2702
+ /**
2703
+ * @method
2704
+ * @name toobit#withdraw
2705
+ * @description make a withdrawal
2706
+ * @see https://toobit-docs.github.io/apidocs/spot/v1/en/#withdraw-user_data
2707
+ * @param {string} code unified currency code
2708
+ * @param {float} amount the amount to withdraw
2709
+ * @param {string} address the address to withdraw to
2710
+ * @param {string} tag a memo for the transaction
2711
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2712
+ * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
2713
+ */
2714
+ async withdraw(code, amount, address, tag = undefined, params = {}) {
2715
+ this.checkAddress(address);
2716
+ let networkCode = undefined;
2717
+ [networkCode, params] = this.handleNetworkCodeAndParams(params);
2718
+ if (networkCode === undefined) {
2719
+ throw new ArgumentsRequired(this.id + ' withdraw() : param["network"] is required');
2720
+ }
2721
+ await this.loadMarkets();
2722
+ const currency = this.currency(code);
2723
+ const request = {
2724
+ 'coin': currency['id'],
2725
+ 'address': address,
2726
+ 'quantity': this.currencyToPrecision(currency['code'], amount),
2727
+ 'network': networkCode,
2728
+ };
2729
+ if (tag !== undefined) {
2730
+ request['addressExt'] = tag;
2731
+ }
2732
+ const response = await this.privatePostApiV1AccountWithdraw(this.extend(request, params));
2733
+ //
2734
+ // {
2735
+ // "status": 0,
2736
+ // "success": true,
2737
+ // "needBrokerAudit": false, // Do you need a brokerage review?
2738
+ // "id": "423885103582776064", // Withdrawal successful order id
2739
+ // "refuseReason":"" // failure rejection reason
2740
+ // }
2741
+ //
2742
+ return this.parseTransaction(response, currency);
2743
+ }
2744
+ /**
2745
+ * @method
2746
+ * @name toobit#setMarginMode
2747
+ * @description set margin mode to 'cross' or 'isolated'
2748
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#change-margin-type-trade
2749
+ * @param {string} marginMode 'cross' or 'isolated'
2750
+ * @param {string} symbol unified market symbol
2751
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2752
+ * @returns {object} response from the exchange
2753
+ */
2754
+ async setMarginMode(marginMode, symbol = undefined, params = {}) {
2755
+ if (symbol === undefined) {
2756
+ throw new ArgumentsRequired(this.id + ' setMarginMode() requires a symbol argument');
2757
+ }
2758
+ await this.loadMarkets();
2759
+ const market = this.market(symbol);
2760
+ if (market['type'] !== 'swap') {
2761
+ throw new BadSymbol(this.id + ' setMarginMode() supports swap contracts only');
2762
+ }
2763
+ marginMode = marginMode.toUpperCase();
2764
+ const request = {
2765
+ 'symbol': market['id'],
2766
+ 'marginType': marginMode,
2767
+ };
2768
+ const response = await this.privatePostApiV1FuturesMarginType(this.extend(request, params));
2769
+ //
2770
+ // {"code":200,"symbolId":"BTC-SWAP-USDT","marginType":"ISOLATED"}
2771
+ //
2772
+ return response;
2773
+ }
2774
+ /**
2775
+ * @method
2776
+ * @name toobit#setLeverage
2777
+ * @description set the level of leverage for a market
2778
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#change-initial-leverage-trade
2779
+ * @param {float} leverage the rate of leverage
2780
+ * @param {string} symbol unified market symbol
2781
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2782
+ * @returns {object} response from the exchange
2783
+ */
2784
+ async setLeverage(leverage, symbol = undefined, params = {}) {
2785
+ if (symbol === undefined) {
2786
+ throw new ArgumentsRequired(this.id + ' setLeverage() requires a symbol argument');
2787
+ }
2788
+ await this.loadMarkets();
2789
+ const market = this.market(symbol);
2790
+ const request = {
2791
+ 'symbol': market['id'],
2792
+ 'leverage': leverage,
2793
+ };
2794
+ const response = await this.privatePostApiV1FuturesLeverage(this.extend(request, params));
2795
+ //
2796
+ // {"code":200,"symbolId":"BTC-SWAP-USDT","leverage":"19"}
2797
+ //
2798
+ return response;
2799
+ }
2800
+ /**
2801
+ * @method
2802
+ * @name toobit#fetchLeverage
2803
+ * @description fetch the set leverage for a market
2804
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#get-the-leverage-multiple-and-position-mode-user_data
2805
+ * @param {string} symbol unified market symbol
2806
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2807
+ * @returns {object} a [leverage structure]{@link https://docs.ccxt.com/#/?id=leverage-structure}
2808
+ */
2809
+ async fetchLeverage(symbol, params = {}) {
2810
+ await this.loadMarkets();
2811
+ const market = this.market(symbol);
2812
+ const request = {
2813
+ 'symbol': market['id'],
2814
+ };
2815
+ const response = await this.privateGetApiV1FuturesAccountLeverage(this.extend(request, params));
2816
+ //
2817
+ // [
2818
+ // {
2819
+ // "symbol":"BTC-SWAP-USDT", //symbol
2820
+ // "leverage":"20", // leverage
2821
+ // "marginType":"CROSS" // CROSS;ISOLATED
2822
+ // }
2823
+ // ]
2824
+ //
2825
+ const data = this.safeDict(response, 'data', {});
2826
+ return this.parseLeverage(data, market);
2827
+ }
2828
+ parseLeverage(leverage, market = undefined) {
2829
+ const marketId = this.safeString(leverage, 'symbol');
2830
+ const leverageValue = this.safeInteger(leverage, 'leverage');
2831
+ const marginType = this.safeString(leverage, 'marginType');
2832
+ const marginMode = (marginType === 'crossed') ? 'cross' : 'isolated';
2833
+ return {
2834
+ 'info': leverage,
2835
+ 'symbol': this.safeSymbol(marketId, market),
2836
+ 'marginMode': marginMode,
2837
+ 'longLeverage': leverageValue,
2838
+ 'shortLeverage': leverageValue,
2839
+ };
2840
+ }
2841
+ /**
2842
+ * @method
2843
+ * @name toobit#fetchPositions
2844
+ * @description fetch all open positions
2845
+ * @see https://toobit-docs.github.io/apidocs/usdt_swap/v1/en/#query-position-user_data
2846
+ * @param {string[]|undefined} symbols list of unified market symbols
2847
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2848
+ * @returns {object[]} a list of [position structures]{@link https://docs.ccxt.com/#/?id=position-structure}
2849
+ */
2850
+ async fetchPositions(symbols = undefined, params = {}) {
2851
+ await this.loadMarkets();
2852
+ const request = {};
2853
+ let market = undefined;
2854
+ if (symbols !== undefined) {
2855
+ const length = symbols.length;
2856
+ if (length > 1) {
2857
+ throw new BadRequest(this.id + ' fetchPositions() only accepts an array with a single symbol or without symbols argument');
2858
+ }
2859
+ const firstSymbol = this.safeString(symbols, 0);
2860
+ if (firstSymbol !== undefined) {
2861
+ market = this.market(firstSymbol);
2862
+ request['symbol'] = market['id'];
2863
+ }
2864
+ }
2865
+ const response = await this.privateGetApiV1FuturesPositions(this.extend(request, params));
2866
+ //
2867
+ // [
2868
+ // {
2869
+ // "symbol": "DOGE-SWAP-USDT",
2870
+ // "side": "LONG",
2871
+ // "avgPrice": "0.21191",
2872
+ // "position": "63",
2873
+ // "available": "63",
2874
+ // "leverage": "25",
2875
+ // "lastPrice": "0.20932",
2876
+ // "positionValue": "13.3503",
2877
+ // "flp": "0.05471",
2878
+ // "margin": "0.5262",
2879
+ // "marginRate": "",
2880
+ // "unrealizedPnL": "-0.1701",
2881
+ // "profitRate": "-0.3185",
2882
+ // "realizedPnL": "-0.008",
2883
+ // "minMargin": "0",
2884
+ // "maxNotionalValue": "10000000",
2885
+ // "markPrice": "0.20921"
2886
+ // }
2887
+ // ]
2888
+ //
2889
+ return this.parsePositions(response, symbols);
2890
+ }
2891
+ parsePosition(position, market = undefined) {
2892
+ const marketId = this.safeString(position, 'symbol');
2893
+ market = this.safeMarket(marketId, market);
2894
+ const side = this.safeStringLower(position, 'side');
2895
+ const quantity = this.safeString(position, 'position');
2896
+ const leverage = this.safeInteger(position, 'leverage');
2897
+ return this.safePosition({
2898
+ 'info': position,
2899
+ 'id': this.safeString(position, 'id'),
2900
+ 'symbol': market['symbol'],
2901
+ 'entryPrice': this.safeString(position, 'avgPrice'),
2902
+ 'markPrice': this.safeString(position, 'markPrice'),
2903
+ 'lastPrice': this.safeString(position, 'lastPrice'),
2904
+ 'notional': this.safeString(position, 'positionValue'),
2905
+ 'collateral': undefined,
2906
+ 'unrealizedPnl': this.safeString(position, 'unrealizedPnL'),
2907
+ 'side': side,
2908
+ 'contracts': this.parseNumber(quantity),
2909
+ 'contractSize': undefined,
2910
+ 'timestamp': undefined,
2911
+ 'datetime': undefined,
2912
+ 'hedged': undefined,
2913
+ 'maintenanceMargin': undefined,
2914
+ 'maintenanceMarginPercentage': undefined,
2915
+ 'initialMargin': this.safeString(position, 'margin'),
2916
+ 'initialMarginPercentage': undefined,
2917
+ 'leverage': leverage,
2918
+ 'liquidationPrice': undefined,
2919
+ 'marginRatio': undefined,
2920
+ 'marginMode': undefined,
2921
+ 'percentage': undefined,
2922
+ });
2923
+ }
2924
+ sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
2925
+ let url = this.urls['api'][api] + '/' + this.implodeParams(path, params);
2926
+ const isPost = method === 'POST';
2927
+ const isDelete = method === 'DELETE';
2928
+ const extraQuery = {};
2929
+ const query = this.omit(params, this.extractParams(path));
2930
+ if (api !== 'private') {
2931
+ // Public endpoints
2932
+ if (!isPost) {
2933
+ if (Object.keys(query).length) {
2934
+ url += '?' + this.urlencode(query);
2935
+ }
2936
+ }
2937
+ }
2938
+ else {
2939
+ this.checkRequiredCredentials();
2940
+ const timestamp = this.milliseconds();
2941
+ // Add timestamp to parameters for signed endpoints
2942
+ extraQuery['recvWindow'] = this.safeString(this.options, 'recvWindow', '5000');
2943
+ extraQuery['timestamp'] = timestamp.toString();
2944
+ const queryExtended = this.extend(query, extraQuery);
2945
+ let queryString = '';
2946
+ if (isPost || isDelete) {
2947
+ // everything else except Batch-Orders
2948
+ if (!Array.isArray(params)) {
2949
+ body = this.urlencode(queryExtended);
2950
+ }
2951
+ else {
2952
+ queryString = this.urlencode(extraQuery);
2953
+ body = this.json(query);
2954
+ }
2955
+ }
2956
+ else {
2957
+ queryString = this.urlencode(queryExtended);
2958
+ }
2959
+ let payload = queryString;
2960
+ if (body !== undefined) {
2961
+ payload = body + payload;
2962
+ }
2963
+ const signature = this.hmac(this.encode(payload), this.encode(this.secret), sha256, 'hex');
2964
+ if (queryString !== '') {
2965
+ queryString += '&signature=' + signature;
2966
+ url += '?' + queryString;
2967
+ }
2968
+ else {
2969
+ body += '&signature=' + signature;
2970
+ }
2971
+ headers = {
2972
+ 'X-BB-APIKEY': this.apiKey,
2973
+ 'Content-Type': 'application/x-www-form-urlencoded',
2974
+ };
2975
+ }
2976
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
2977
+ }
2978
+ handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
2979
+ if (response === undefined) {
2980
+ return undefined;
2981
+ }
2982
+ const errorCode = this.safeString(response, 'code');
2983
+ const message = this.safeString(response, 'msg');
2984
+ if (errorCode && errorCode !== '200' && errorCode !== '0') {
2985
+ const feedback = this.id + ' ' + body;
2986
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
2987
+ this.throwBroadlyMatchedException(this.exceptions['broad'], message, feedback);
2988
+ throw new ExchangeError(feedback);
2989
+ }
2990
+ return undefined;
2991
+ }
2992
+ }