ccxt 4.4.98__py2.py3-none-any.whl → 4.4.100__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. ccxt/__init__.py +3 -1
  2. ccxt/abstract/bingx.py +1 -0
  3. ccxt/abstract/bitget.py +6 -0
  4. ccxt/abstract/hibachi.py +26 -0
  5. ccxt/alpaca.py +1 -1
  6. ccxt/apex.py +1 -1
  7. ccxt/ascendex.py +1 -1
  8. ccxt/async_support/__init__.py +3 -1
  9. ccxt/async_support/alpaca.py +1 -1
  10. ccxt/async_support/apex.py +1 -1
  11. ccxt/async_support/ascendex.py +1 -1
  12. ccxt/async_support/base/exchange.py +44 -9
  13. ccxt/async_support/base/ws/client.py +3 -1
  14. ccxt/async_support/bigone.py +1 -1
  15. ccxt/async_support/binance.py +10 -8
  16. ccxt/async_support/bingx.py +33 -4
  17. ccxt/async_support/bitbank.py +1 -1
  18. ccxt/async_support/bitfinex.py +4 -1
  19. ccxt/async_support/bitflyer.py +1 -1
  20. ccxt/async_support/bitget.py +2040 -561
  21. ccxt/async_support/bithumb.py +1 -1
  22. ccxt/async_support/bitmart.py +2 -2
  23. ccxt/async_support/bitmex.py +3 -2
  24. ccxt/async_support/bitopro.py +1 -1
  25. ccxt/async_support/bitrue.py +2 -2
  26. ccxt/async_support/bitso.py +1 -1
  27. ccxt/async_support/bitstamp.py +1 -1
  28. ccxt/async_support/bittrade.py +1 -1
  29. ccxt/async_support/bitvavo.py +1 -1
  30. ccxt/async_support/blockchaincom.py +1 -1
  31. ccxt/async_support/blofin.py +1 -1
  32. ccxt/async_support/btcmarkets.py +1 -1
  33. ccxt/async_support/bybit.py +7 -3
  34. ccxt/async_support/coinbase.py +1 -1
  35. ccxt/async_support/coinbaseexchange.py +1 -1
  36. ccxt/async_support/coinbaseinternational.py +1 -1
  37. ccxt/async_support/coincatch.py +2 -2
  38. ccxt/async_support/coinex.py +67 -6
  39. ccxt/async_support/coinmate.py +1 -1
  40. ccxt/async_support/coinsph.py +1 -1
  41. ccxt/async_support/cryptocom.py +2 -2
  42. ccxt/async_support/defx.py +2 -2
  43. ccxt/async_support/delta.py +1 -1
  44. ccxt/async_support/deribit.py +1 -1
  45. ccxt/async_support/digifinex.py +2 -2
  46. ccxt/async_support/ellipx.py +1 -1
  47. ccxt/async_support/exmo.py +1 -1
  48. ccxt/async_support/foxbit.py +3 -3
  49. ccxt/async_support/gate.py +18 -4
  50. ccxt/async_support/gemini.py +1 -1
  51. ccxt/async_support/hashkey.py +2 -2
  52. ccxt/async_support/hibachi.py +2080 -0
  53. ccxt/async_support/hitbtc.py +2 -2
  54. ccxt/async_support/hollaex.py +1 -1
  55. ccxt/async_support/htx.py +4 -3
  56. ccxt/async_support/hyperliquid.py +71 -29
  57. ccxt/async_support/independentreserve.py +1 -1
  58. ccxt/async_support/indodax.py +1 -1
  59. ccxt/async_support/kraken.py +1 -1
  60. ccxt/async_support/krakenfutures.py +2 -1
  61. ccxt/async_support/kucoin.py +2 -2
  62. ccxt/async_support/kucoinfutures.py +2 -1
  63. ccxt/async_support/lbank.py +2 -2
  64. ccxt/async_support/mercado.py +1 -1
  65. ccxt/async_support/mexc.py +9 -2
  66. ccxt/async_support/modetrade.py +93 -2
  67. ccxt/async_support/ndax.py +1 -1
  68. ccxt/async_support/novadax.py +35 -1
  69. ccxt/async_support/okcoin.py +1 -1
  70. ccxt/async_support/okx.py +2 -2
  71. ccxt/async_support/onetrading.py +33 -0
  72. ccxt/async_support/oxfun.py +1 -1
  73. ccxt/async_support/p2b.py +32 -0
  74. ccxt/async_support/paradex.py +2 -1
  75. ccxt/async_support/phemex.py +2 -2
  76. ccxt/async_support/poloniex.py +2 -2
  77. ccxt/async_support/probit.py +36 -1
  78. ccxt/async_support/tokocrypto.py +1 -1
  79. ccxt/async_support/upbit.py +1 -1
  80. ccxt/async_support/vertex.py +1 -1
  81. ccxt/async_support/wavesexchange.py +1 -1
  82. ccxt/async_support/whitebit.py +2 -2
  83. ccxt/async_support/woo.py +4 -4
  84. ccxt/async_support/woofipro.py +93 -2
  85. ccxt/async_support/xt.py +2 -2
  86. ccxt/async_support/yobit.py +1 -1
  87. ccxt/async_support/zaif.py +1 -1
  88. ccxt/async_support/zonda.py +1 -1
  89. ccxt/base/errors.py +0 -6
  90. ccxt/base/exchange.py +11 -9
  91. ccxt/base/types.py +1 -0
  92. ccxt/bigone.py +1 -1
  93. ccxt/binance.py +10 -8
  94. ccxt/bingx.py +33 -4
  95. ccxt/bitbank.py +1 -1
  96. ccxt/bitfinex.py +4 -1
  97. ccxt/bitflyer.py +1 -1
  98. ccxt/bitget.py +2040 -561
  99. ccxt/bithumb.py +1 -1
  100. ccxt/bitmart.py +2 -2
  101. ccxt/bitmex.py +3 -2
  102. ccxt/bitopro.py +1 -1
  103. ccxt/bitrue.py +2 -2
  104. ccxt/bitso.py +1 -1
  105. ccxt/bitstamp.py +1 -1
  106. ccxt/bittrade.py +1 -1
  107. ccxt/bitvavo.py +1 -1
  108. ccxt/blockchaincom.py +1 -1
  109. ccxt/blofin.py +1 -1
  110. ccxt/btcmarkets.py +1 -1
  111. ccxt/bybit.py +7 -3
  112. ccxt/coinbase.py +1 -1
  113. ccxt/coinbaseexchange.py +1 -1
  114. ccxt/coinbaseinternational.py +1 -1
  115. ccxt/coincatch.py +2 -2
  116. ccxt/coinex.py +67 -6
  117. ccxt/coinmate.py +1 -1
  118. ccxt/coinsph.py +1 -1
  119. ccxt/cryptocom.py +2 -2
  120. ccxt/defx.py +2 -2
  121. ccxt/delta.py +1 -1
  122. ccxt/deribit.py +1 -1
  123. ccxt/digifinex.py +2 -2
  124. ccxt/ellipx.py +1 -1
  125. ccxt/exmo.py +1 -1
  126. ccxt/foxbit.py +3 -3
  127. ccxt/gate.py +18 -4
  128. ccxt/gemini.py +1 -1
  129. ccxt/hashkey.py +2 -2
  130. ccxt/hibachi.py +2079 -0
  131. ccxt/hitbtc.py +2 -2
  132. ccxt/hollaex.py +1 -1
  133. ccxt/htx.py +4 -3
  134. ccxt/hyperliquid.py +71 -29
  135. ccxt/independentreserve.py +1 -1
  136. ccxt/indodax.py +1 -1
  137. ccxt/kraken.py +1 -1
  138. ccxt/krakenfutures.py +2 -1
  139. ccxt/kucoin.py +2 -2
  140. ccxt/kucoinfutures.py +2 -1
  141. ccxt/lbank.py +2 -2
  142. ccxt/mercado.py +1 -1
  143. ccxt/mexc.py +9 -2
  144. ccxt/modetrade.py +93 -2
  145. ccxt/ndax.py +1 -1
  146. ccxt/novadax.py +35 -1
  147. ccxt/okcoin.py +1 -1
  148. ccxt/okx.py +2 -2
  149. ccxt/onetrading.py +33 -0
  150. ccxt/oxfun.py +1 -1
  151. ccxt/p2b.py +32 -0
  152. ccxt/paradex.py +2 -1
  153. ccxt/phemex.py +2 -2
  154. ccxt/poloniex.py +2 -2
  155. ccxt/pro/__init__.py +1 -1
  156. ccxt/pro/alpaca.py +2 -2
  157. ccxt/pro/apex.py +2 -2
  158. ccxt/pro/ascendex.py +2 -2
  159. ccxt/pro/binance.py +4 -5
  160. ccxt/pro/bitget.py +3 -3
  161. ccxt/pro/bithumb.py +2 -2
  162. ccxt/pro/bitmart.py +2 -2
  163. ccxt/pro/bitmex.py +3 -3
  164. ccxt/pro/bitstamp.py +3 -3
  165. ccxt/pro/bittrade.py +2 -2
  166. ccxt/pro/bitvavo.py +5 -3
  167. ccxt/pro/bybit.py +5 -4
  168. ccxt/pro/cex.py +3 -2
  169. ccxt/pro/coinbaseexchange.py +4 -4
  170. ccxt/pro/coinbaseinternational.py +2 -2
  171. ccxt/pro/coincatch.py +1 -1
  172. ccxt/pro/coinex.py +1 -1
  173. ccxt/pro/coinone.py +2 -2
  174. ccxt/pro/cryptocom.py +2 -2
  175. ccxt/pro/derive.py +2 -2
  176. ccxt/pro/gate.py +3 -3
  177. ccxt/pro/hollaex.py +2 -2
  178. ccxt/pro/htx.py +3 -3
  179. ccxt/pro/hyperliquid.py +101 -14
  180. ccxt/pro/kraken.py +2 -2
  181. ccxt/pro/krakenfutures.py +4 -3
  182. ccxt/pro/kucoin.py +4 -3
  183. ccxt/pro/kucoinfutures.py +4 -3
  184. ccxt/pro/mexc.py +328 -139
  185. ccxt/pro/modetrade.py +2 -2
  186. ccxt/pro/okcoin.py +2 -2
  187. ccxt/pro/okx.py +7 -6
  188. ccxt/pro/onetrading.py +2 -2
  189. ccxt/pro/oxfun.py +1 -1
  190. ccxt/pro/p2b.py +2 -2
  191. ccxt/pro/paradex.py +2 -2
  192. ccxt/pro/poloniex.py +2 -2
  193. ccxt/pro/probit.py +2 -2
  194. ccxt/pro/vertex.py +2 -2
  195. ccxt/pro/whitebit.py +2 -2
  196. ccxt/pro/woo.py +2 -2
  197. ccxt/pro/woofipro.py +2 -2
  198. ccxt/probit.py +36 -1
  199. ccxt/protobuf/__init__.py +0 -0
  200. ccxt/protobuf/mexc/PrivateAccountV3Api_pb2.py +37 -0
  201. ccxt/protobuf/mexc/PrivateDealsV3Api_pb2.py +37 -0
  202. ccxt/protobuf/mexc/PrivateOrdersV3Api_pb2.py +37 -0
  203. ccxt/protobuf/mexc/PublicAggreBookTickerV3Api_pb2.py +37 -0
  204. ccxt/protobuf/mexc/PublicAggreDealsV3Api_pb2.py +39 -0
  205. ccxt/protobuf/mexc/PublicAggreDepthsV3Api_pb2.py +39 -0
  206. ccxt/protobuf/mexc/PublicBookTickerBatchV3Api_pb2.py +38 -0
  207. ccxt/protobuf/mexc/PublicBookTickerV3Api_pb2.py +37 -0
  208. ccxt/protobuf/mexc/PublicDealsV3Api_pb2.py +39 -0
  209. ccxt/protobuf/mexc/PublicIncreaseDepthsBatchV3Api_pb2.py +38 -0
  210. ccxt/protobuf/mexc/PublicIncreaseDepthsV3Api_pb2.py +39 -0
  211. ccxt/protobuf/mexc/PublicLimitDepthsV3Api_pb2.py +39 -0
  212. ccxt/protobuf/mexc/PublicMiniTickerV3Api_pb2.py +37 -0
  213. ccxt/protobuf/mexc/PublicMiniTickersV3Api_pb2.py +38 -0
  214. ccxt/protobuf/mexc/PublicSpotKlineV3Api_pb2.py +37 -0
  215. ccxt/protobuf/mexc/PushDataV3ApiWrapper_pb2.py +52 -0
  216. ccxt/protobuf/mexc/__init__.py +0 -0
  217. ccxt/test/tests_async.py +1 -1
  218. ccxt/test/tests_sync.py +1 -1
  219. ccxt/tokocrypto.py +1 -1
  220. ccxt/upbit.py +1 -1
  221. ccxt/vertex.py +1 -1
  222. ccxt/wavesexchange.py +1 -1
  223. ccxt/whitebit.py +2 -2
  224. ccxt/woo.py +4 -4
  225. ccxt/woofipro.py +93 -2
  226. ccxt/xt.py +2 -2
  227. ccxt/yobit.py +1 -1
  228. ccxt/zaif.py +1 -1
  229. ccxt/zonda.py +1 -1
  230. {ccxt-4.4.98.dist-info → ccxt-4.4.100.dist-info}/METADATA +8 -7
  231. {ccxt-4.4.98.dist-info → ccxt-4.4.100.dist-info}/RECORD +234 -213
  232. {ccxt-4.4.98.dist-info → ccxt-4.4.100.dist-info}/LICENSE.txt +0 -0
  233. {ccxt-4.4.98.dist-info → ccxt-4.4.100.dist-info}/WHEEL +0 -0
  234. {ccxt-4.4.98.dist-info → ccxt-4.4.100.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,2080 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+
6
+ from ccxt.async_support.base.exchange import Exchange
7
+ from ccxt.abstract.hibachi import ImplicitAPI
8
+ import asyncio
9
+ import hashlib
10
+ from ccxt.base.types import Any, Balances, Currencies, Currency, DepositAddress, Int, LedgerEntry, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, FundingRate, Trade, TradingFees, Transaction
11
+ from typing import List
12
+ from ccxt.base.errors import ExchangeError
13
+ from ccxt.base.errors import BadRequest
14
+ from ccxt.base.errors import OrderNotFound
15
+ from ccxt.base.decimal_to_precision import TICK_SIZE
16
+ from ccxt.base.precise import Precise
17
+
18
+
19
+ class hibachi(Exchange, ImplicitAPI):
20
+
21
+ def describe(self) -> Any:
22
+ return self.deep_extend(super(hibachi, self).describe(), {
23
+ 'id': 'hibachi',
24
+ 'name': 'Hibachi',
25
+ 'countries': ['US'],
26
+ 'rateLimit': 100,
27
+ 'userAgent': self.userAgents['chrome'],
28
+ 'certified': False,
29
+ 'pro': False,
30
+ 'dex': True,
31
+ 'has': {
32
+ 'CORS': None,
33
+ 'spot': False,
34
+ 'margin': False,
35
+ 'swap': True,
36
+ 'future': False,
37
+ 'option': False,
38
+ 'addMargin': False,
39
+ 'cancelAllOrders': True,
40
+ 'cancelOrder': True,
41
+ 'cancelOrders': True,
42
+ 'cancelWithdraw': False,
43
+ 'closeAllPositions': False,
44
+ 'closePosition': False,
45
+ 'createConvertTrade': False,
46
+ 'createDepositAddress': False,
47
+ 'createMarketBuyOrderWithCost': False,
48
+ 'createMarketOrder': False,
49
+ 'createMarketOrderWithCost': False,
50
+ 'createMarketSellOrderWithCost': False,
51
+ 'createOrder': True,
52
+ 'createOrders': True,
53
+ 'createOrderWithTakeProfitAndStopLoss': False,
54
+ 'createReduceOnlyOrder': False,
55
+ 'createStopLimitOrder': False,
56
+ 'createStopLossOrder': False,
57
+ 'createStopMarketOrder': False,
58
+ 'createStopOrder': False,
59
+ 'createTakeProfitOrder': False,
60
+ 'createTrailingAmountOrder': False,
61
+ 'createTrailingPercentOrder': False,
62
+ 'createTriggerOrder': False,
63
+ 'editOrder': True,
64
+ 'editOrders': True,
65
+ 'fetchAccounts': False,
66
+ 'fetchBalance': True,
67
+ 'fetchCanceledOrders': False,
68
+ 'fetchClosedOrder': False,
69
+ 'fetchClosedOrders': False,
70
+ 'fetchConvertCurrencies': False,
71
+ 'fetchConvertQuote': False,
72
+ 'fetchCurrencies': True,
73
+ 'fetchDepositAddress': True,
74
+ 'fetchDeposits': True,
75
+ 'fetchDepositsWithdrawals': False,
76
+ 'fetchFundingHistory': False,
77
+ 'fetchFundingInterval': False,
78
+ 'fetchFundingIntervals': False,
79
+ 'fetchFundingRate': True,
80
+ 'fetchFundingRateHistory': True,
81
+ 'fetchFundingRates': False,
82
+ 'fetchIndexOHLCV': False,
83
+ 'fetchLedger': True,
84
+ 'fetchLeverage': False,
85
+ 'fetchMarginAdjustmentHistory': False,
86
+ 'fetchMarginMode': False,
87
+ 'fetchMarkets': True,
88
+ 'fetchMyTrades': True,
89
+ 'fetchOHLCV': True,
90
+ 'fetchOpenInterest': True,
91
+ 'fetchOpenInterestHistory': False,
92
+ 'fetchOpenOrder': False,
93
+ 'fetchOpenOrders': True,
94
+ 'fetchOrder': True,
95
+ 'fetchOrderBook': True,
96
+ 'fetchOrders': False,
97
+ 'fetchOrderTrades': False,
98
+ 'fetchPosition': False,
99
+ 'fetchPositionMode': False,
100
+ 'fetchPositions': True,
101
+ 'fetchPremiumIndexOHLCV': False,
102
+ 'fetchStatus': False,
103
+ 'fetchTicker': True,
104
+ 'fetchTickers': False,
105
+ 'fetchTime': True,
106
+ 'fetchTrades': True,
107
+ 'fetchTradingFee': False,
108
+ 'fetchTradingFees': True,
109
+ 'fetchTradingLimits': False,
110
+ 'fetchTransactions': 'emulated',
111
+ 'fetchTransfers': False,
112
+ 'fetchWithdrawals': True,
113
+ 'reduceMargin': False,
114
+ 'setLeverage': False,
115
+ 'setMargin': False,
116
+ 'setPositionMode': False,
117
+ 'transfer': False,
118
+ 'withdraw': True,
119
+ },
120
+ 'timeframes': {
121
+ '1m': '1min',
122
+ '5m': '5min',
123
+ '15m': '15min',
124
+ '1h': '1h',
125
+ '4h': '4h',
126
+ '1d': '1d',
127
+ '1w': '1w',
128
+ },
129
+ 'urls': {
130
+ 'logo': 'https://github.com/user-attachments/assets/7301bbb1-4f27-4167-8a55-75f74b14e973',
131
+ 'api': {
132
+ 'public': 'https://data-api.hibachi.xyz',
133
+ 'private': 'https://api.hibachi.xyz',
134
+ },
135
+ 'www': 'https://www.hibachi.xyz/',
136
+ 'referral': {
137
+ 'url': 'hibachi.xyz/r/ZBL2YFWIHU',
138
+ },
139
+ },
140
+ 'api': {
141
+ 'public': {
142
+ 'get': {
143
+ 'market/exchange-info': 1,
144
+ 'market/data/trades': 1,
145
+ 'market/data/prices': 1,
146
+ 'market/data/stats': 1,
147
+ 'market/data/klines': 1,
148
+ 'market/data/orderbook': 1,
149
+ 'market/data/open-interest': 1,
150
+ 'market/data/funding-rates': 1,
151
+ 'exchange/utc-timestamp': 1,
152
+ },
153
+ },
154
+ 'private': {
155
+ 'get': {
156
+ 'capital/deposit-info': 1,
157
+ 'capital/history': 1,
158
+ 'trade/account/trading_history': 1,
159
+ 'trade/account/info': 1,
160
+ 'trade/order': 1,
161
+ 'trade/account/trades': 1,
162
+ 'trade/orders': 1,
163
+ },
164
+ 'put': {
165
+ 'trade/order': 1,
166
+ },
167
+ 'delete': {
168
+ 'trade/order': 1,
169
+ 'trade/orders': 1,
170
+ },
171
+ 'post': {
172
+ 'trade/order': 1,
173
+ 'trade/orders': 1,
174
+ 'capital/withdraw': 1,
175
+ },
176
+ },
177
+ },
178
+ 'requiredCredentials': {
179
+ 'apiKey': True,
180
+ 'secret': False,
181
+ 'accountId': True,
182
+ 'privateKey': True,
183
+ },
184
+ 'fees': {
185
+ 'trading': {
186
+ 'tierBased': False,
187
+ 'percentage': True,
188
+ 'maker': self.parse_number('0.00015'),
189
+ 'taker': self.parse_number('0.00045'),
190
+ },
191
+ },
192
+ 'options': {
193
+ },
194
+ 'features': {
195
+ 'default': {
196
+ 'sandbox': False,
197
+ 'createOrder': {
198
+ 'marginMode': False,
199
+ 'triggerPrice': True,
200
+ 'triggerPriceType': None,
201
+ 'triggerDirection': None,
202
+ 'stopLossPrice': False,
203
+ 'takeProfitPrice': False,
204
+ 'attachedStopLossTakeProfit': None,
205
+ 'timeInForce': {
206
+ 'IOC': True,
207
+ 'FOK': False,
208
+ 'PO': True,
209
+ 'GTD': False,
210
+ },
211
+ 'hedged': False,
212
+ 'trailing': False,
213
+ 'leverage': False,
214
+ 'marketBuyByCost': False,
215
+ 'marketBuyRequiresPrice': False,
216
+ 'selfTradePrevention': False,
217
+ 'iceberg': False,
218
+ },
219
+ 'createOrders': None,
220
+ 'fetchMyTrades': {
221
+ 'marginMode': False,
222
+ 'limit': None,
223
+ 'daysBack': None,
224
+ 'untilDays': None,
225
+ 'symbolRequired': False,
226
+ },
227
+ 'fetchOrder': {
228
+ 'marginMode': False,
229
+ 'trigger': False,
230
+ 'trailing': False,
231
+ 'symbolRequired': False,
232
+ },
233
+ 'fetchOpenOrders': {
234
+ 'marginMode': False,
235
+ 'limit': None,
236
+ 'trigger': False,
237
+ 'trailing': False,
238
+ 'symbolRequired': False,
239
+ },
240
+ 'fetchOrders': None,
241
+ 'fetchClosedOrders': None,
242
+ 'fetchOHLCV': {
243
+ 'limit': None,
244
+ },
245
+ },
246
+ 'swap': {
247
+ 'linear': {
248
+ 'extends': 'default',
249
+ },
250
+ 'inverse': None,
251
+ },
252
+ 'future': {
253
+ 'linear': {
254
+ 'extends': 'default',
255
+ },
256
+ 'inverse': None,
257
+ },
258
+ },
259
+ 'commonCurrencies': {},
260
+ 'exceptions': {
261
+ 'exact': {
262
+ '2': BadRequest, # {"errorCode":2,"message":"Invalid signature: Failed to verify signature"}
263
+ '3': OrderNotFound, # {"errorCode":3,"message":"Not found: order ID 33","status":"failed"}
264
+ '4': BadRequest, # {"errorCode":4,"message":"Missing accountId","status":"failed"}
265
+ },
266
+ 'broad': {
267
+ },
268
+ },
269
+ 'precisionMode': TICK_SIZE,
270
+ })
271
+
272
+ def get_account_id(self):
273
+ self.check_required_credentials()
274
+ id = self.parse_to_int(self.accountId)
275
+ return id
276
+
277
+ def parse_market(self, market: dict) -> Market:
278
+ marketId = self.safe_string(market, 'symbol')
279
+ numericId = self.safe_number(market, 'id')
280
+ marketType = 'swap'
281
+ baseId = self.safe_string(market, 'underlyingSymbol')
282
+ quoteId = self.safe_string(market, 'settlementSymbol')
283
+ base = self.safe_currency_code(baseId)
284
+ quote = self.safe_currency_code(quoteId)
285
+ settleId: Str = self.safe_string(market, 'settlementSymbol')
286
+ settle: Str = self.safe_currency_code(settleId)
287
+ symbol = base + '/' + quote + ':' + settle
288
+ created = self.safe_integer_product(market, 'marketCreationTimestamp', 1000)
289
+ return {
290
+ 'id': marketId,
291
+ 'numericId': numericId,
292
+ 'symbol': symbol,
293
+ 'base': base,
294
+ 'quote': quote,
295
+ 'settle': settle,
296
+ 'baseId': baseId,
297
+ 'quoteId': quoteId,
298
+ 'settleId': settleId,
299
+ 'type': marketType,
300
+ 'spot': False,
301
+ 'margin': False,
302
+ 'swap': True,
303
+ 'future': False,
304
+ 'option': False,
305
+ 'active': self.safe_string(market, 'status') == 'LIVE',
306
+ 'contract': True,
307
+ 'linear': True,
308
+ 'inverse': False,
309
+ 'contractSize': self.parse_number('1'),
310
+ 'expiry': None,
311
+ 'expiryDatetime': None,
312
+ 'strike': None,
313
+ 'optionType': None,
314
+ 'precision': {
315
+ 'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'underlyingDecimals'))),
316
+ 'price': self.parse_number(self.safe_list(market, 'orderbookGranularities')[0]) / 10000.0,
317
+ },
318
+ 'limits': {
319
+ 'leverage': {
320
+ 'min': None,
321
+ 'max': None,
322
+ },
323
+ 'amount': {
324
+ 'min': None,
325
+ 'max': None,
326
+ },
327
+ 'price': {
328
+ 'min': None,
329
+ 'max': None,
330
+ },
331
+ 'cost': {
332
+ 'min': self.safe_number(market, 'minNotional'),
333
+ 'max': None,
334
+ },
335
+ },
336
+ 'created': created,
337
+ 'info': market,
338
+ }
339
+
340
+ async def fetch_markets(self, params={}) -> List[Market]:
341
+ """
342
+ retrieves data on all markets for hibachi
343
+
344
+ https://api-doc.hibachi.xyz/#183981da-8df5-40a0-a155-da15015dd536
345
+
346
+ :param dict [params]: extra parameters specific to the exchange API endpoint
347
+ :returns dict[]: an array of objects representing market data
348
+ """
349
+ response = await self.publicGetMarketExchangeInfo(params)
350
+ # {
351
+ # "displayName": "ETH/USDT Perps",
352
+ # "id": 1,
353
+ # "maintenanceFactorForPositions": "0.030000",
354
+ # "marketCloseTimestamp": null,
355
+ # "marketOpenTimestamp": null,
356
+ # "minNotional": "1",
357
+ # "minOrderSize": "0.000000001",
358
+ # "orderbookGranularities": [
359
+ # "0.01",
360
+ # "0.1",
361
+ # "1",
362
+ # "10"
363
+ # ],
364
+ # "riskFactorForOrders": "0.066667",
365
+ # "riskFactorForPositions": "0.030000",
366
+ # "settlementDecimals": 6,
367
+ # "settlementSymbol": "USDT",
368
+ # "status": "LIVE",
369
+ # "stepSize": "0.000000001",
370
+ # "symbol": "ETH/USDT-P",
371
+ # "tickSize": "0.000001",
372
+ # "underlyingDecimals": 9,
373
+ # "underlyingSymbol": "ETH"
374
+ # },
375
+ rows = self.safe_list(response, 'futureContracts')
376
+ return self.parse_markets(rows)
377
+
378
+ async def fetch_currencies(self, params={}) -> Currencies:
379
+ """
380
+ fetches all available currencies on an exchange
381
+
382
+ https://api-doc.hibachi.xyz/#183981da-8df5-40a0-a155-da15015dd536
383
+
384
+ :param dict [params]: extra parameters specific to the exchange API endpoint
385
+ :returns dict: an associative dictionary of currencies
386
+ """
387
+ # Hibachi only supports USDT on Arbitrum at self time
388
+ # We don't have an API endpoint to expose self information yet
389
+ result: dict = {}
390
+ networks: dict = {}
391
+ networkId = 'ARBITRUM'
392
+ networks[networkId] = {
393
+ 'id': networkId,
394
+ 'network': networkId,
395
+ 'limits': {
396
+ 'withdraw': {
397
+ 'min': None,
398
+ 'max': None,
399
+ },
400
+ 'deposit': {
401
+ 'min': None,
402
+ 'max': None,
403
+ },
404
+ },
405
+ 'active': None,
406
+ 'deposit': None,
407
+ 'withdraw': None,
408
+ 'info': {},
409
+ }
410
+ code = self.safe_currency_code('USDT')
411
+ result[code] = self.safe_currency_structure({
412
+ 'id': 'USDT',
413
+ 'name': 'USDT',
414
+ 'type': 'fiat',
415
+ 'code': code,
416
+ 'precision': self.parse_number('0.000001'),
417
+ 'active': True,
418
+ 'fee': None,
419
+ 'networks': networks,
420
+ 'deposit': True,
421
+ 'withdraw': True,
422
+ 'limits': {
423
+ 'deposit': {
424
+ 'min': None,
425
+ 'max': None,
426
+ },
427
+ 'withdraw': {
428
+ 'min': None,
429
+ 'max': None,
430
+ },
431
+ },
432
+ 'info': {},
433
+ })
434
+ return result
435
+
436
+ def parse_balance(self, response) -> Balances:
437
+ result: dict = {
438
+ 'info': response,
439
+ }
440
+ # Hibachi only supports USDT on Arbitrum at self time
441
+ code = self.safe_currency_code('USDT')
442
+ account = self.account()
443
+ account['total'] = self.safe_string(response, 'balance')
444
+ account['free'] = self.safe_string(response, 'maximalWithdraw')
445
+ result[code] = account
446
+ return self.safe_balance(result)
447
+
448
+ async def fetch_balance(self, params={}) -> Balances:
449
+ """
450
+ query for balance and get the amount of funds available for trading or funds locked in orders
451
+
452
+ https://api-doc.hibachi.xyz/#69aafedb-8274-4e21-bbaf-91dace8b8f31
453
+
454
+ :param dict [params]: extra parameters specific to the exchange API endpoint
455
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
456
+ """
457
+ request: dict = {
458
+ 'accountId': self.get_account_id(),
459
+ }
460
+ response = await self.privateGetTradeAccountInfo(self.extend(request, params))
461
+ #
462
+ # {
463
+ # assets: [{quantity: '3.000000', symbol: 'USDT'}],
464
+ # balance: '3.000000',
465
+ # maximalWithdraw: '3.000000',
466
+ # numFreeTransfersRemaining: '100',
467
+ # positions: [],
468
+ # totalOrderNotional: '0.000000',
469
+ # totalPositionNotional: '0.000000',
470
+ # totalUnrealizedFundingPnl: '0.000000',
471
+ # totalUnrealizedPnl: '0.000000',
472
+ # totalUnrealizedTradingPnl: '0.000000',
473
+ # tradeMakerFeeRate: '0.00000000',
474
+ # tradeTakerFeeRate: '0.00020000'
475
+ # }
476
+ #
477
+ return self.parse_balance(response)
478
+
479
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
480
+ prices = self.safe_dict(ticker, 'prices')
481
+ stats = self.safe_dict(ticker, 'stats')
482
+ bid = self.safe_number(prices, 'bidPrice')
483
+ ask = self.safe_number(prices, 'askPrice')
484
+ last = self.safe_number(prices, 'tradePrice')
485
+ high = self.safe_number(stats, 'high24h')
486
+ low = self.safe_number(stats, 'low24h')
487
+ volume = self.safe_number(stats, 'volume24h')
488
+ return self.safe_ticker({
489
+ 'symbol': self.safe_symbol(None, market),
490
+ 'timestamp': None,
491
+ 'datetime': None,
492
+ 'bid': bid,
493
+ 'ask': ask,
494
+ 'last': last,
495
+ 'high': high,
496
+ 'low': low,
497
+ 'bidVolume': None,
498
+ 'askVolume': None,
499
+ 'vwap': None,
500
+ 'open': None,
501
+ 'close': last,
502
+ 'previousClose': None,
503
+ 'change': None,
504
+ 'percentage': None,
505
+ 'average': None,
506
+ 'baseVolume': None,
507
+ 'quoteVolume': volume,
508
+ 'info': ticker,
509
+ }, market)
510
+
511
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
512
+ # public fetchTrades:
513
+ # {
514
+ # "price": "3512.431902",
515
+ # "quantity": "1.414780098",
516
+ # "takerSide": "Buy",
517
+ # "timestamp": 1712692147
518
+ # }
519
+ #
520
+ # private fetchMyTrades:
521
+ # {
522
+ # "askAccountId": 221,
523
+ # "askOrderId": 589168494921909200,
524
+ # "bidAccountId": 132,
525
+ # "bidOrderId": 589168494829895700,
526
+ # "fee": "0.000477",
527
+ # "id": 199511136,
528
+ # "orderType": "MARKET",
529
+ # "price": "119257.90000",
530
+ # "quantity": "0.0000200000",
531
+ # "realizedPnl": "-0.000352",
532
+ # "side": "Sell",
533
+ # "symbol": "BTC/USDT-P",
534
+ # "timestamp": 1752543391
535
+ # }
536
+ marketId = self.safe_string(trade, 'symbol')
537
+ market = self.safe_market(marketId, market)
538
+ symbol = market['symbol']
539
+ id = self.safe_string(trade, 'id')
540
+ price = self.safe_string(trade, 'price')
541
+ amount = self.safe_string(trade, 'quantity')
542
+ timestamp = self.safe_integer_product(trade, 'timestamp', 1000)
543
+ cost = Precise.string_mul(price, amount)
544
+ side = None
545
+ fee = None
546
+ orderType = None
547
+ orderId = None
548
+ takerOrMaker = None
549
+ if id is None:
550
+ # public trades
551
+ side = self.safe_string_lower(trade, 'takerSide')
552
+ takerOrMaker = 'taker'
553
+ else:
554
+ # private trades
555
+ side = self.safe_string_lower(trade, 'side')
556
+ fee = {'cost': self.safe_string(trade, 'fee'), 'currency': 'USDT'}
557
+ orderType = self.safe_string_lower(trade, 'orderType')
558
+ if side == 'buy':
559
+ orderId = self.safe_string(trade, 'bidOrderId')
560
+ else:
561
+ orderId = self.safe_string(trade, 'askOrderId')
562
+ return self.safe_trade({
563
+ 'id': id,
564
+ 'timestamp': timestamp,
565
+ 'datetime': self.iso8601(timestamp),
566
+ 'symbol': symbol,
567
+ 'side': side,
568
+ 'price': price,
569
+ 'amount': amount,
570
+ 'cost': cost,
571
+ 'order': orderId,
572
+ 'takerOrMaker': takerOrMaker,
573
+ 'type': orderType,
574
+ 'fee': fee,
575
+ 'info': trade,
576
+ }, market)
577
+
578
+ async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
579
+ """
580
+ get the list of most recent trades for a particular symbol
581
+
582
+ https://api-doc.hibachi.xyz/#86a53bc1-d3bb-4b93-8a11-7034d4698caa
583
+
584
+ :param str symbol: unified market symbol
585
+ :param int [since]: timestamp in ms of the earliest trade to fetch
586
+ :param int [limit]: the maximum amount of trades to fetch(maximum value is 100)
587
+ :param dict [params]: extra parameters specific to the hibachi api endpoint
588
+ :returns dict[]: a list of recent [trade structures]
589
+ """
590
+ await self.load_markets()
591
+ market = self.market(symbol)
592
+ request = {
593
+ 'symbol': market['id'],
594
+ }
595
+ response = await self.publicGetMarketDataTrades(self.extend(request, params))
596
+ #
597
+ # {
598
+ # "trades": [
599
+ # {
600
+ # "price": "111091.38352",
601
+ # "quantity": "0.0090090093",
602
+ # "takerSide": "Buy",
603
+ # "timestamp": 1752095479
604
+ # },
605
+ # ]
606
+ # }
607
+ #
608
+ trades = self.safe_list(response, 'trades', [])
609
+ return self.parse_trades(trades, market)
610
+
611
+ async def fetch_ticker(self, symbol: Str, params={}) -> Ticker:
612
+ """
613
+
614
+ https://api-doc.hibachi.xyz/#4abb30c4-e5c7-4b0f-9ade-790111dbfa47
615
+
616
+ fetches a price ticker and the related information for the past 24h
617
+ :param str symbol: unified symbol of the market
618
+ :param dict [params]: extra parameters specific to the hibachi api endpoint
619
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
620
+ """
621
+ await self.load_markets()
622
+ market = self.market(symbol)
623
+ request: dict = {
624
+ 'symbol': market['id'],
625
+ }
626
+ rawPromises = [
627
+ self.publicGetMarketDataPrices(self.extend(request, params)),
628
+ self.publicGetMarketDataStats(self.extend(request, params)),
629
+ ]
630
+ promises = await asyncio.gather(*rawPromises)
631
+ pricesResponse = promises[0]
632
+ # {
633
+ # "askPrice": "3514.650296",
634
+ # "bidPrice": "3513.596112",
635
+ # "fundingRateEstimation": {
636
+ # "estimatedFundingRate": "0.000001",
637
+ # "nextFundingTimestamp": 1712707200
638
+ # },
639
+ # "markPrice": "3514.288858",
640
+ # "spotPrice": "3514.715000",
641
+ # "symbol": "ETH/USDT-P",
642
+ # "tradePrice": "2372.746570"
643
+ # }
644
+ statsResponse = promises[1]
645
+ # {
646
+ # "high24h": "3819.507827",
647
+ # "low24h": "3754.474162",
648
+ # "symbol": "ETH/USDT-P",
649
+ # "volume24h": "23554.858590416"
650
+ # }
651
+ ticker = {
652
+ 'prices': pricesResponse,
653
+ 'stats': statsResponse,
654
+ }
655
+ return self.parse_ticker(ticker, market)
656
+
657
+ def parse_order_status(self, status: str) -> str:
658
+ statuses: dict = {
659
+ 'PENDING': 'open',
660
+ 'CHILD_PENDING': 'open',
661
+ 'SCHEDULED_TWAP': 'open',
662
+ 'PLACED': 'open',
663
+ 'PARTIALLY_FILLED': 'open',
664
+ 'FILLED': 'closed',
665
+ 'CANCELLED': 'canceled',
666
+ 'REJECTED': 'rejected',
667
+ }
668
+ return self.safe_string(statuses, status, status)
669
+
670
+ def parse_order(self, order: dict, market: Market = None) -> Order:
671
+ marketId = self.safe_string(order, 'symbol')
672
+ market = self.safe_market(marketId, market)
673
+ status = self.safe_string(order, 'status')
674
+ type = self.safe_string_lower(order, 'orderType')
675
+ price = self.safe_string(order, 'price')
676
+ rawSide = self.safe_string(order, 'side')
677
+ side = None
678
+ if rawSide == 'BID':
679
+ side = 'buy'
680
+ elif rawSide == 'ASK':
681
+ side = 'sell'
682
+ amount = self.safe_string(order, 'totalQuantity')
683
+ remaining = self.safe_string(order, 'availableQuantity')
684
+ totalQuantity = self.safe_string(order, 'totalQuantity')
685
+ availableQuantity = self.safe_string(order, 'availableQuantity')
686
+ filled = None
687
+ if totalQuantity is not None and availableQuantity is not None:
688
+ filled = Precise.string_sub(totalQuantity, availableQuantity)
689
+ timeInForce = 'GTC'
690
+ orderFlags = self.safe_value(order, 'orderFlags')
691
+ postOnly = False
692
+ reduceOnly = False
693
+ if orderFlags == 'POST_ONLY':
694
+ timeInForce = 'PO'
695
+ postOnly = True
696
+ elif orderFlags == 'IOC':
697
+ timeInForce = 'IOC'
698
+ elif orderFlags == 'REDUCE_ONLY':
699
+ reduceOnly = True
700
+ return self.safe_order({
701
+ 'info': order,
702
+ 'id': self.safe_string(order, 'orderId'),
703
+ 'clientOrderId': None,
704
+ 'datetime': None,
705
+ 'timestamp': None,
706
+ 'lastTradeTimestamp': None,
707
+ 'lastUpdateTimestamp': None,
708
+ 'status': self.parse_order_status(status),
709
+ 'symbol': market['symbol'],
710
+ 'type': type,
711
+ 'timeInForce': timeInForce,
712
+ 'side': side,
713
+ 'price': price,
714
+ 'average': None,
715
+ 'amount': amount,
716
+ 'filled': filled,
717
+ 'remaining': remaining,
718
+ 'cost': None,
719
+ 'trades': None,
720
+ 'fee': None,
721
+ 'reduceOnly': reduceOnly,
722
+ 'postOnly': postOnly,
723
+ 'triggerPrice': self.safe_number(order, 'triggerPrice'),
724
+ }, market)
725
+
726
+ async def fetch_order(self, id: str, symbol: Str = None, params={}) -> Order:
727
+ """
728
+ fetches information on an order made by the user
729
+
730
+ https://api-doc.hibachi.xyz/#096a8854-b918-4de8-8731-b2a28d26b96d
731
+
732
+ :param str id: the order id
733
+ :param str symbol: unified symbol of the market the order was made in
734
+ :param dict [params]: extra parameters specific to the exchange API endpoint
735
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
736
+ """
737
+ await self.load_markets()
738
+ market = None
739
+ if symbol is not None:
740
+ market = self.market(symbol)
741
+ request: dict = {
742
+ 'orderId': id,
743
+ 'accountId': self.get_account_id(),
744
+ }
745
+ response = await self.privateGetTradeOrder(self.extend(request, params))
746
+ return self.parse_order(response, market)
747
+
748
+ async def fetch_trading_fees(self, params={}) -> TradingFees:
749
+ """
750
+ fetch the trading fee
751
+ @param params extra parameters
752
+ :returns dict: a map of market symbols to `fee structures <https://docs.ccxt.com/#/?id=fee-structure>`
753
+ """
754
+ await self.load_markets()
755
+ request: dict = {
756
+ 'accountId': self.get_account_id(),
757
+ }
758
+ response = await self.privateGetTradeAccountInfo(self.extend(request, params))
759
+ # {
760
+ # "tradeMakerFeeRate": "0.00000000",
761
+ # "tradeTakerFeeRate": "0.00020000"
762
+ # },
763
+ makerFeeRate = self.safe_number(response, 'tradeMakerFeeRate')
764
+ takerFeeRate = self.safe_number(response, 'tradeTakerFeeRate')
765
+ result: dict = {}
766
+ for i in range(0, len(self.symbols)):
767
+ symbol = self.symbols[i]
768
+ result[symbol] = {
769
+ 'info': response,
770
+ 'symbol': symbol,
771
+ 'maker': makerFeeRate,
772
+ 'taker': takerFeeRate,
773
+ 'percentage': True,
774
+ }
775
+ return result
776
+
777
+ def order_message(self, market, nonce: float, feeRate: float, type: OrderType, side: OrderSide, amount: float, price: Num = None):
778
+ sideInternal = 0
779
+ if side == 'sell':
780
+ sideInternal = 0
781
+ elif side == 'buy':
782
+ sideInternal = 1
783
+ # Converting them to internal representation:
784
+ # - Quantity: Internal = External * (10^underlyingDecimals)
785
+ # - Price: Internal = External * (2^32) * (10^(settlementDecimals-underlyingDecimals))
786
+ # - FeeRate: Internal = External * (10^8)
787
+ amountStr = self.amount_to_precision(self.safe_string(market, 'symbol'), amount)
788
+ feeRateStr = self.number_to_string(feeRate)
789
+ info = self.safe_dict(market, 'info')
790
+ underlying = '1e' + self.safe_string(info, 'underlyingDecimals')
791
+ settlement = '1e' + self.safe_string(info, 'settlementDecimals')
792
+ one = '1'
793
+ feeRateFactor = '100000000' # 10^8
794
+ priceFactor = '4294967296' # 2^32
795
+ quantityInternal = Precise.string_div(Precise.string_mul(amountStr, underlying), one, 0)
796
+ feeRateInternal = Precise.string_div(Precise.string_mul(feeRateStr, feeRateFactor), one, 0)
797
+ # Encoding
798
+ nonce16 = self.int_to_base16(nonce)
799
+ noncePadded = nonce16.rjust(16, '0')
800
+ encodedNonce = self.base16_to_binary(noncePadded)
801
+ numericId = self.int_to_base16(self.safe_integer(market, 'numericId'))
802
+ numericIdPadded = numericId.rjust(8, '0')
803
+ encodedMarketId = self.base16_to_binary(numericIdPadded)
804
+ quantity16 = self.int_to_base16(self.parse_to_int(quantityInternal))
805
+ quantityPadded = quantity16.rjust(16, '0')
806
+ encodedQuantity = self.base16_to_binary(quantityPadded)
807
+ sideInternal16 = self.int_to_base16(sideInternal)
808
+ sidePadded = sideInternal16.rjust(8, '0')
809
+ encodedSide = self.base16_to_binary(sidePadded)
810
+ feeRateInternal16 = self.int_to_base16(self.parse_to_int(feeRateInternal))
811
+ feeRatePadded = feeRateInternal16.rjust(16, '0')
812
+ encodedFeeRate = self.base16_to_binary(feeRatePadded)
813
+ encodedPrice = self.binary_concat()
814
+ if type == 'limit':
815
+ priceStr = self.price_to_precision(self.safe_string(market, 'symbol'), price)
816
+ priceInternal = Precise.string_div(Precise.string_div(Precise.string_mul(Precise.string_mul(priceStr, priceFactor), settlement), underlying), one, 0)
817
+ price16 = self.int_to_base16(self.parse_to_int(priceInternal))
818
+ pricePadded = price16.rjust(16, '0')
819
+ encodedPrice = self.base16_to_binary(pricePadded)
820
+ message = self.binary_concat(encodedNonce, encodedMarketId, encodedQuantity, encodedSide, encodedPrice, encodedFeeRate)
821
+ return message
822
+
823
+ def create_order_request(self, nonce: float, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
824
+ market = self.market(symbol)
825
+ feeRate = max(self.safe_number(market, 'taker'), self.safe_number(market, 'maker'))
826
+ sideInternal = ''
827
+ if side == 'sell':
828
+ sideInternal = 'ASK'
829
+ elif side == 'buy':
830
+ sideInternal = 'BID'
831
+ priceInternal = ''
832
+ if price:
833
+ priceInternal = self.price_to_precision(symbol, price)
834
+ message = self.order_message(market, nonce, feeRate, type, side, amount, price)
835
+ signature = self.sign_message(message, self.privateKey)
836
+ request = {
837
+ 'symbol': self.safe_string(market, 'id'),
838
+ 'nonce': nonce,
839
+ 'side': sideInternal,
840
+ 'orderType': type.upper(),
841
+ 'quantity': self.amount_to_precision(symbol, amount),
842
+ 'price': priceInternal,
843
+ 'signature': signature,
844
+ 'maxFeesPercent': self.number_to_string(feeRate),
845
+ }
846
+ postOnly = self.is_post_only(type.upper() == 'MARKET', None, params)
847
+ reduceOnly = self.safe_bool_2(params, 'reduceOnly', 'reduce_only')
848
+ timeInForce = self.safe_string_lower(params, 'timeInForce')
849
+ triggerPrice = self.safe_string_2(params, 'triggerPrice', 'stopPrice')
850
+ if postOnly:
851
+ request['orderFlags'] = 'POST_ONLY'
852
+ elif timeInForce == 'ioc':
853
+ request['orderFlags'] = 'IOC'
854
+ elif reduceOnly:
855
+ request['orderFlags'] = 'REDUCE_ONLY'
856
+ if triggerPrice is not None:
857
+ request['triggerPrice'] = triggerPrice
858
+ params = self.omit(params, ['reduceOnly', 'reduce_only', 'postOnly', 'timeInForce', 'stopPrice', 'triggerPrice'])
859
+ return self.extend(request, params)
860
+
861
+ async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
862
+ """
863
+ create a trade order
864
+
865
+ https://api-doc.hibachi.xyz/#00f6d5ad-5275-41cb-a1a8-19ed5d142124
866
+
867
+ :param str symbol: unified symbol of the market to create an order in
868
+ :param str type: 'market' or 'limit'
869
+ :param str side: 'buy' or 'sell'
870
+ :param float amount: how much of currency you want to trade in units of base currency
871
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
872
+ :param dict [params]: extra parameters specific to the exchange API endpoint
873
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
874
+ """
875
+ await self.load_markets()
876
+ nonce = self.nonce()
877
+ request = self.create_order_request(nonce, symbol, type, side, amount, price, params)
878
+ request['accountId'] = self.get_account_id()
879
+ response = await self.privatePostTradeOrder(request)
880
+ #
881
+ # {
882
+ # "orderId": "578721673790138368"
883
+ # }
884
+ #
885
+ return self.safe_order({
886
+ 'id': self.safe_string(response, 'orderId'),
887
+ 'status': 'pending',
888
+ })
889
+
890
+ async def create_orders(self, orders: List[OrderRequest], params={}) -> List[Order]:
891
+ """
892
+ *contract only* create a list of trade orders
893
+
894
+ https://api-doc.hibachi.xyz/#c2840b9b-f02c-44ed-937d-dc2819f135b4
895
+
896
+ :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
897
+ :param dict [params]: extra parameters specific to the exchange API endpoint
898
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
899
+ """
900
+ await self.load_markets()
901
+ nonce = self.nonce()
902
+ requestOrders = []
903
+ for i in range(0, len(orders)):
904
+ rawOrder = orders[i]
905
+ symbol = self.safe_string(rawOrder, 'symbol')
906
+ type = self.safe_string(rawOrder, 'type')
907
+ side = self.safe_string(rawOrder, 'side')
908
+ amount = self.safe_value(rawOrder, 'amount')
909
+ price = self.safe_value(rawOrder, 'price')
910
+ orderParams = self.safe_dict(rawOrder, 'params', {})
911
+ orderRequest = self.create_order_request(nonce + i, symbol, type, side, amount, price, orderParams)
912
+ orderRequest['action'] = 'place'
913
+ requestOrders.append(orderRequest)
914
+ request: dict = {
915
+ 'accountId': self.get_account_id(),
916
+ 'orders': requestOrders,
917
+ }
918
+ response = await self.privatePostTradeOrders(self.extend(request, params))
919
+ #
920
+ # {"orders": [{nonce: '1754349993908', orderId: '589642085255349248'}]}
921
+ #
922
+ ret = []
923
+ responseOrders = self.safe_list(response, 'orders')
924
+ for i in range(0, len(responseOrders)):
925
+ responseOrder = responseOrders[i]
926
+ ret.append(self.safe_order({
927
+ 'info': responseOrder,
928
+ 'id': self.safe_string(responseOrder, 'orderId'),
929
+ 'status': 'pending',
930
+ }))
931
+ return ret
932
+
933
+ def edit_order_request(self, nonce: float, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
934
+ market = self.market(symbol)
935
+ feeRate = max(self.safe_number(market, 'taker'), self.safe_number(market, 'maker'))
936
+ message = self.order_message(market, nonce, feeRate, type, side, amount, price)
937
+ signature = self.sign_message(message, self.privateKey)
938
+ request = {
939
+ 'orderId': id,
940
+ 'nonce': nonce,
941
+ 'updatedQuantity': self.amount_to_precision(symbol, amount),
942
+ 'updatedPrice': self.price_to_precision(symbol, price),
943
+ 'maxFeesPercent': self.number_to_string(feeRate),
944
+ 'signature': signature,
945
+ }
946
+ return self.extend(request, params)
947
+
948
+ async def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
949
+ """
950
+ edit a limit order that is not matched
951
+
952
+ https://api-doc.hibachi.xyz/#94d2cdaf-1c71-440f-a981-da1112824810
953
+
954
+ :param str id: order id
955
+ :param str symbol: unified symbol of the market to create an order in
956
+ :param str type: must be 'limit'
957
+ :param str side: 'buy' or 'sell', should stay the same with original side
958
+ :param float amount: how much of currency you want to trade in units of base currency
959
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency
960
+ :param dict [params]: extra parameters specific to the exchange API endpoint
961
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
962
+ """
963
+ await self.load_markets()
964
+ nonce = self.nonce()
965
+ request = self.edit_order_request(nonce, id, symbol, type, side, amount, price, params)
966
+ request['accountId'] = self.get_account_id()
967
+ await self.privatePutTradeOrder(request)
968
+ # At self time the response body is empty. A 200 response means the update request is accepted and sent to process
969
+ #
970
+ # {}
971
+ #
972
+ return self.safe_order({
973
+ 'id': id,
974
+ 'status': 'pending',
975
+ })
976
+
977
+ async def edit_orders(self, orders: List[OrderRequest], params={}) -> List[Order]:
978
+ """
979
+ edit a list of trade orders
980
+
981
+ https://api-doc.hibachi.xyz/#c2840b9b-f02c-44ed-937d-dc2819f135b4
982
+
983
+ :param Array orders: list of orders to edit, each object should contain the parameters required by editOrder, namely id, symbol, type, side, amount, price and params
984
+ :param dict [params]: extra parameters specific to the exchange API endpoint
985
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
986
+ """
987
+ await self.load_markets()
988
+ nonce = self.nonce()
989
+ requestOrders = []
990
+ for i in range(0, len(orders)):
991
+ rawOrder = orders[i]
992
+ id = self.safe_string(rawOrder, 'id')
993
+ symbol = self.safe_string(rawOrder, 'symbol')
994
+ type = self.safe_string(rawOrder, 'type')
995
+ side = self.safe_string(rawOrder, 'side')
996
+ amount = self.safe_value(rawOrder, 'amount')
997
+ price = self.safe_value(rawOrder, 'price')
998
+ orderParams = self.safe_dict(rawOrder, 'params', {})
999
+ orderRequest = self.edit_order_request(nonce + i, id, symbol, type, side, amount, price, orderParams)
1000
+ orderRequest['action'] = 'modify'
1001
+ requestOrders.append(orderRequest)
1002
+ request: dict = {
1003
+ 'accountId': self.get_account_id(),
1004
+ 'orders': requestOrders,
1005
+ }
1006
+ response = await self.privatePostTradeOrders(self.extend(request, params))
1007
+ #
1008
+ # {"orders": [{"orderId": "589636801329628160"}]}
1009
+ #
1010
+ ret = []
1011
+ responseOrders = self.safe_list(response, 'orders')
1012
+ for i in range(0, len(responseOrders)):
1013
+ responseOrder = responseOrders[i]
1014
+ ret.append(self.safe_order({
1015
+ 'info': responseOrder,
1016
+ 'id': self.safe_string(responseOrder, 'orderId'),
1017
+ 'status': 'pending',
1018
+ }))
1019
+ return ret
1020
+
1021
+ def cancel_order_request(self, id: str):
1022
+ bigid = self.convert_to_big_int(id)
1023
+ idbase16 = self.int_to_base16(bigid)
1024
+ idPadded = idbase16.rjust(16, '0')
1025
+ message = self.base16_to_binary(idPadded)
1026
+ signature = self.sign_message(message, self.privateKey)
1027
+ return {
1028
+ 'orderId': id,
1029
+ 'signature': signature,
1030
+ }
1031
+
1032
+ async def cancel_order(self, id: str, symbol: Str = None, params={}):
1033
+ """
1034
+
1035
+ https://api-doc.hibachi.xyz/#e99c4f48-e610-4b7c-b7f6-1b4bb7af0271
1036
+
1037
+ cancels an open order
1038
+ :param str id: order id
1039
+ :param str symbol: is unused
1040
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1041
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1042
+ """
1043
+ request: dict = self.cancel_order_request(id)
1044
+ request['accountId'] = self.get_account_id()
1045
+ response = await self.privateDeleteTradeOrder(self.extend(request, params))
1046
+ # At self time the response body is empty. A 200 response means the cancel request is accepted and sent to cancel
1047
+ #
1048
+ # {}
1049
+ #
1050
+ return self.safe_order({
1051
+ 'info': response,
1052
+ 'id': id,
1053
+ 'status': 'canceled',
1054
+ })
1055
+
1056
+ async def cancel_orders(self, ids: List[str], symbol: Str = None, params={}):
1057
+ """
1058
+ cancel multiple orders
1059
+
1060
+ https://api-doc.hibachi.xyz/#c2840b9b-f02c-44ed-937d-dc2819f135b4
1061
+
1062
+ :param str[] ids: order ids
1063
+ :param str [symbol]: unified market symbol, unused
1064
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1065
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1066
+ """
1067
+ orders = []
1068
+ for i in range(0, len(ids)):
1069
+ orderRequest = self.cancel_order_request(ids[i])
1070
+ orderRequest['action'] = 'cancel'
1071
+ orders.append(orderRequest)
1072
+ request: dict = {
1073
+ 'accountId': self.get_account_id(),
1074
+ 'orders': orders,
1075
+ }
1076
+ response = await self.privatePostTradeOrders(self.extend(request, params))
1077
+ #
1078
+ # {"orders": [{"orderId": "589636801329628160"}]}
1079
+ #
1080
+ ret = []
1081
+ responseOrders = self.safe_list(response, 'orders')
1082
+ for i in range(0, len(responseOrders)):
1083
+ responseOrder = responseOrders[i]
1084
+ ret.append(self.safe_order({
1085
+ 'info': responseOrder,
1086
+ 'id': self.safe_string(responseOrder, 'orderId'),
1087
+ 'status': 'canceled',
1088
+ }))
1089
+ return ret
1090
+
1091
+ async def cancel_all_orders(self, symbol: Str = None, params={}):
1092
+ """
1093
+
1094
+ https://api-doc.hibachi.xyz/#8ed24695-016e-49b2-a72d-7511ca921fee
1095
+
1096
+ cancel all open orders in a market
1097
+ :param str symbol: unified market symbol
1098
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1099
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1100
+ """
1101
+ await self.load_markets()
1102
+ nonce = self.nonce()
1103
+ nonce16 = self.int_to_base16(nonce)
1104
+ noncePadded = nonce16.rjust(16, '0')
1105
+ message = self.base16_to_binary(noncePadded)
1106
+ signature = self.sign_message(message, self.privateKey)
1107
+ request: dict = {
1108
+ 'accountId': self.get_account_id(),
1109
+ 'nonce': nonce,
1110
+ 'signature': signature,
1111
+ }
1112
+ if symbol is not None:
1113
+ market = self.market(symbol)
1114
+ request['contractId'] = self.safe_integer(market, 'numericId')
1115
+ response = await self.privateDeleteTradeOrders(self.extend(request, params))
1116
+ # At self time the response body is empty. A 200 response means the cancel request is accepted and sent to process
1117
+ #
1118
+ # {}
1119
+ #
1120
+ return [
1121
+ self.safe_order({
1122
+ 'info': response,
1123
+ }),
1124
+ ]
1125
+
1126
+ def encode_withdraw_message(self, amount: float, maxFees: float, address: str):
1127
+ # Converting them to internal representation:
1128
+ # - Quantity: Internal = External * (10^6)
1129
+ # - maxFees: Internal = External * (10^6)
1130
+ # We only have USDT currency time
1131
+ USDTAssetId = 1
1132
+ USDTFactor = '1000000'
1133
+ amountStr = self.number_to_string(amount)
1134
+ maxFeesStr = self.number_to_string(maxFees)
1135
+ one = '1'
1136
+ quantityInternal = Precise.string_div(Precise.string_mul(amountStr, USDTFactor), one, 0)
1137
+ maxFeesInternal = Precise.string_div(Precise.string_mul(maxFeesStr, USDTFactor), one, 0)
1138
+ # Encoding
1139
+ usdtAsset16 = self.int_to_base16(USDTAssetId)
1140
+ usdtAssetPadded = usdtAsset16.rjust(8, '0')
1141
+ encodedAssetId = self.base16_to_binary(usdtAssetPadded)
1142
+ quantity16 = self.int_to_base16(self.parse_to_int(quantityInternal))
1143
+ quantityPadded = quantity16.rjust(16, '0')
1144
+ encodedQuantity = self.base16_to_binary(quantityPadded)
1145
+ maxFees16 = self.int_to_base16(self.parse_to_int(maxFeesInternal))
1146
+ maxFeesPadded = maxFees16.rjust(16, '0')
1147
+ encodedMaxFees = self.base16_to_binary(maxFeesPadded)
1148
+ encodedAddress = self.base16_to_binary(address)
1149
+ message = self.binary_concat(encodedAssetId, encodedQuantity, encodedMaxFees, encodedAddress)
1150
+ return message
1151
+
1152
+ async def withdraw(self, code: str, amount: float, address: str, tag: Str = None, params={}) -> Transaction:
1153
+ """
1154
+ make a withdrawal
1155
+
1156
+ https://api-doc.hibachi.xyz/#6421625d-3e45-45fa-be9b-d2a0e780c090
1157
+
1158
+ :param str code: unified currency code, only support USDT
1159
+ :param float amount: the amount to withdraw
1160
+ :param str address: the address to withdraw to
1161
+ :param str tag:
1162
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1163
+ :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
1164
+ """
1165
+ withdrawAddress = address[-40:]
1166
+ # Get the withdraw fees
1167
+ exchangeInfo = await self.publicGetMarketExchangeInfo(params)
1168
+ # {
1169
+ # "feeConfig": {
1170
+ # "depositFees": "0.004518",
1171
+ # "tradeMakerFeeRate": "0.00000000",
1172
+ # "tradeTakerFeeRate": "0.00020000",
1173
+ # "transferFeeRate": "0.00010000",
1174
+ # "withdrawalFees": "0.012050"
1175
+ # },
1176
+ # }
1177
+ feeConfig = self.safe_dict(exchangeInfo, 'feeConfig')
1178
+ maxFees = self.safe_number(feeConfig, 'withdrawalFees')
1179
+ # Generate the signature
1180
+ message = self.encode_withdraw_message(amount, maxFees, withdrawAddress)
1181
+ signature = self.sign_message(message, self.privateKey)
1182
+ request = {
1183
+ 'accountId': self.get_account_id(),
1184
+ 'coin': 'USDT',
1185
+ 'network': 'ARBITRUM',
1186
+ 'withdrawAddress': withdrawAddress,
1187
+ 'selfWithdrawal': False,
1188
+ 'quantity': self.number_to_string(amount),
1189
+ 'maxFees': self.number_to_string(maxFees),
1190
+ 'signature': signature,
1191
+ }
1192
+ await self.privatePostCapitalWithdraw(self.extend(request, params))
1193
+ # At self time the response body is empty. A 200 response means the withdraw request is accepted and sent to process
1194
+ #
1195
+ # {}
1196
+ #
1197
+ return {
1198
+ 'info': None,
1199
+ 'id': None,
1200
+ 'txid': None,
1201
+ 'timestamp': self.milliseconds(),
1202
+ 'datetime': None,
1203
+ 'address': None,
1204
+ 'addressFrom': None,
1205
+ 'addressTo': withdrawAddress,
1206
+ 'tag': None,
1207
+ 'tagFrom': None,
1208
+ 'tagTo': None,
1209
+ 'type': 'withdrawal',
1210
+ 'amount': amount,
1211
+ 'currency': code,
1212
+ 'status': 'pending',
1213
+ 'fee': {'currency': 'USDT', 'cost': maxFees},
1214
+ 'network': 'ARBITRUM',
1215
+ 'updated': None,
1216
+ 'comment': None,
1217
+ 'internal': None,
1218
+ }
1219
+
1220
+ def nonce(self):
1221
+ return self.milliseconds()
1222
+
1223
+ def sign_message(self, message, privateKey):
1224
+ if len(privateKey) == 44:
1225
+ # For Exchange Managed account, the key length is 44 and we use HMAC to sign the message
1226
+ return self.hmac(message, self.encode(privateKey), hashlib.sha256, 'hex')
1227
+ else:
1228
+ # For Trustless account, the key length is 66 including '0x' and we use ECDSA to sign the message
1229
+ hash = self.hash(self.encode(message), 'sha256', 'hex')
1230
+ signature = self.ecdsa(hash[-64:], privateKey[-64:], 'secp256k1', None)
1231
+ r = signature['r']
1232
+ s = signature['s']
1233
+ v = signature['v']
1234
+ return r.rjust(64, '0') + s.rjust(64, '0') + self.int_to_base16(v).rjust(2, '0')
1235
+
1236
+ async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
1237
+ """
1238
+ fetches the state of the open orders on the orderbook
1239
+
1240
+ https://api-doc.hibachi.xyz/#4abb30c4-e5c7-4b0f-9ade-790111dbfa47
1241
+
1242
+ :param str symbol: unified symbol of the market
1243
+ :param int [limit]: currently unused
1244
+ :param dict [params]: extra parameters to be passed -- see documentation link above
1245
+ :returns dict: A dictionary containg `orderbook information <https://docs.ccxt.com/#/?id=order-book-structure>`
1246
+ """
1247
+ await self.load_markets()
1248
+ market: Market = self.market(symbol)
1249
+ request: dict = {
1250
+ 'symbol': market['id'],
1251
+ }
1252
+ response = await self.publicGetMarketDataOrderbook(self.extend(request, params))
1253
+ formattedResponse = {}
1254
+ formattedResponse['ask'] = self.safe_list(self.safe_dict(response, 'ask'), 'levels')
1255
+ formattedResponse['bid'] = self.safe_list(self.safe_dict(response, 'bid'), 'levels')
1256
+ # {
1257
+ # "ask": {
1258
+ # "endPrice": "3512.63",
1259
+ # "levels": [
1260
+ # {
1261
+ # "price": "3511.93",
1262
+ # "quantity": "0.284772482"
1263
+ # },
1264
+ # {
1265
+ # "price": "3512.28",
1266
+ # "quantity": "0.569544964"
1267
+ # },
1268
+ # {
1269
+ # "price": "3512.63",
1270
+ # "quantity": "0.854317446"
1271
+ # }
1272
+ # ],
1273
+ # "startPrice": "3511.93"
1274
+ # },
1275
+ # "bid": {
1276
+ # "endPrice": "3510.87",
1277
+ # "levels": [
1278
+ # {
1279
+ # "price": "3515.39",
1280
+ # "quantity": "2.345153070"
1281
+ # },
1282
+ # {
1283
+ # "price": "3511.22",
1284
+ # "quantity": "0.284772482"
1285
+ # },
1286
+ # {
1287
+ # "price": "3510.87",
1288
+ # "quantity": "0.569544964"
1289
+ # }
1290
+ # ],
1291
+ # "startPrice": "3515.39"
1292
+ # }
1293
+ # }
1294
+ return self.parse_order_book(formattedResponse, symbol, self.milliseconds(), 'bid', 'ask', 'price', 'quantity')
1295
+
1296
+ async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1297
+ """
1298
+
1299
+ https://api-doc.hibachi.xyz/#0adbf143-189f-40e0-afdc-88af4cba3c79
1300
+
1301
+ fetch all trades made by the user
1302
+ :param str symbol: unified market symbol
1303
+ :param int [since]: the earliest time in ms to fetch trades for
1304
+ :param int [limit]: the maximum number of trades structures to retrieve
1305
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1306
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1307
+ """
1308
+ await self.load_markets()
1309
+ market: Market = None
1310
+ if symbol is not None:
1311
+ market = self.market(symbol)
1312
+ request = {'accountId': self.get_account_id()}
1313
+ response = await self.privateGetTradeAccountTrades(self.extend(request, params))
1314
+ #
1315
+ # {
1316
+ # "trades": [
1317
+ # {
1318
+ # "askAccountId": 221,
1319
+ # "askOrderId": 589168494921909200,
1320
+ # "bidAccountId": 132,
1321
+ # "bidOrderId": 589168494829895700,
1322
+ # "fee": "0.000477",
1323
+ # "id": 199511136,
1324
+ # "orderType": "MARKET",
1325
+ # "price": "119257.90000",
1326
+ # "quantity": "0.0000200000",
1327
+ # "realizedPnl": "-0.000352",
1328
+ # "side": "Sell",
1329
+ # "symbol": "BTC/USDT-P",
1330
+ # "timestamp": 1752543391
1331
+ # }
1332
+ # ]
1333
+ # }
1334
+ #
1335
+ trades = self.safe_list(response, 'trades')
1336
+ return self.parse_trades(trades, market, since, limit, params)
1337
+
1338
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
1339
+ #
1340
+ # [
1341
+ # {
1342
+ # "close": "3704.751036",
1343
+ # "high": "3716.530378",
1344
+ # "interval": "1h",
1345
+ # "low": "3699.627883",
1346
+ # "open": "3716.406894",
1347
+ # "timestamp": 1712628000,
1348
+ # "volumeNotional": "1637355.846362"
1349
+ # }
1350
+ # ]
1351
+ #
1352
+ return [
1353
+ self.safe_integer_product(ohlcv, 'timestamp', 1000),
1354
+ self.safe_number(ohlcv, 'open'),
1355
+ self.safe_number(ohlcv, 'high'),
1356
+ self.safe_number(ohlcv, 'low'),
1357
+ self.safe_number(ohlcv, 'close'),
1358
+ self.safe_number(ohlcv, 'volumeNotional'),
1359
+ ]
1360
+
1361
+ async def fetch_open_orders(self, symbol: str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1362
+ """
1363
+ fetches all current open orders
1364
+
1365
+ https://api-doc.hibachi.xyz/#3243f8a0-086c-44c5-ab8a-71bbb7bab403
1366
+
1367
+ :param str [symbol]: unified market symbol to filter by
1368
+ :param int [since]: milisecond timestamp of the earliest order
1369
+ :param int [limit]: the maximum number of open orders to return
1370
+ :param dict [params]: extra parameters
1371
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1372
+ """
1373
+ await self.load_markets()
1374
+ market = None
1375
+ if symbol is not None:
1376
+ market = self.market(symbol)
1377
+ request = {
1378
+ 'accountId': self.get_account_id(),
1379
+ }
1380
+ response = await self.privateGetTradeOrders(self.extend(request, params))
1381
+ # [
1382
+ # {
1383
+ # "accountId": 12452,
1384
+ # "availableQuantity": "0.0000230769",
1385
+ # "contractId": 2,
1386
+ # "creationTime": 1752684501,
1387
+ # "orderId": "589205486123876352",
1388
+ # "orderType": "LIMIT",
1389
+ # "price": "130000.00000",
1390
+ # "side": "ASK",
1391
+ # "status": "PLACED",
1392
+ # "symbol": "BTC/USDT-P",
1393
+ # "totalQuantity": "0.0000230769"
1394
+ # },
1395
+ # {
1396
+ # "accountId": 12452,
1397
+ # "availableQuantity": "1.234000000",
1398
+ # "contractId": 1,
1399
+ # "creationTime": 1752240682,
1400
+ # "orderId": "589089141754429441",
1401
+ # "orderType": "LIMIT",
1402
+ # "price": "1.234000",
1403
+ # "side": "BID",
1404
+ # "status": "PLACED",
1405
+ # "symbol": "ETH/USDT-P",
1406
+ # "totalQuantity": "1.234000000"
1407
+ # }
1408
+ # ]
1409
+ return self.parse_orders(response, market, since, limit)
1410
+
1411
+ async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
1412
+ """
1413
+
1414
+ https://api-doc.hibachi.xyz/#4f0eacec-c61e-4d51-afb3-23c51c2c6bac
1415
+
1416
+ fetches historical candlestick data containing the close, high, low, open prices, interval and the volumeNotional
1417
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
1418
+ :param str timeframe: the length of time each candle represents
1419
+ :param int [since]: timestamp in ms of the earliest candle to fetch
1420
+ :param int [limit]: the maximum amount of candles to fetch
1421
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1422
+ :param int [params.until]: timestamp in ms of the latest candle to fetch
1423
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
1424
+ """
1425
+ await self.load_markets()
1426
+ market = self.market(symbol)
1427
+ timeframe = self.safe_string(self.timeframes, timeframe, timeframe)
1428
+ request: dict = {
1429
+ 'symbol': market['id'],
1430
+ 'interval': timeframe,
1431
+ }
1432
+ if since is not None:
1433
+ request['fromMs'] = since
1434
+ until: Int = None
1435
+ until, params = self.handle_option_and_params(params, 'fetchOHLCV', 'until')
1436
+ if until is not None:
1437
+ request['toMs'] = until
1438
+ response = await self.publicGetMarketDataKlines(self.extend(request, params))
1439
+ #
1440
+ # [
1441
+ # {
1442
+ # "close": "3704.751036",
1443
+ # "high": "3716.530378",
1444
+ # "interval": "1h",
1445
+ # "low": "3699.627883",
1446
+ # "open": "3716.406894",
1447
+ # "timestamp": 1712628000,
1448
+ # "volumeNotional": "1637355.846362"
1449
+ # }
1450
+ # ]
1451
+ #
1452
+ klines = self.safe_list(response, 'klines', [])
1453
+ return self.parse_ohlcvs(klines, market, timeframe, since, limit)
1454
+
1455
+ async def fetch_positions(self, symbols: Strings = None, params={}) -> List[Position]:
1456
+ """
1457
+ fetch all open positions
1458
+
1459
+ https://api-doc.hibachi.xyz/#69aafedb-8274-4e21-bbaf-91dace8b8f31
1460
+
1461
+ :param str[] [symbols]: list of unified market symbols
1462
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1463
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
1464
+ """
1465
+ await self.load_markets()
1466
+ symbols = self.market_symbols(symbols)
1467
+ request: dict = {
1468
+ 'accountId': self.get_account_id(),
1469
+ }
1470
+ response = await self.privateGetTradeAccountInfo(self.extend(request, params))
1471
+ #
1472
+ # {
1473
+ # "assets": [
1474
+ # {
1475
+ # "quantity": "14.130626",
1476
+ # "symbol": "USDT"
1477
+ # }
1478
+ # ],
1479
+ # "balance": "14.186087",
1480
+ # "maximalWithdraw": "4.152340",
1481
+ # "numFreeTransfersRemaining": 96,
1482
+ # "positions": [
1483
+ # {
1484
+ # "direction": "Short",
1485
+ # "entryNotional": "10.302213",
1486
+ # "notionalValue": "10.225008",
1487
+ # "quantity": "0.004310550",
1488
+ # "symbol": "ETH/USDT-P",
1489
+ # "unrealizedFundingPnl": "0.000000",
1490
+ # "unrealizedTradingPnl": "0.077204"
1491
+ # },
1492
+ # {
1493
+ # "direction": "Short",
1494
+ # "entryNotional": "2.000016",
1495
+ # "notionalValue": "1.999390",
1496
+ # "quantity": "0.0000328410",
1497
+ # "symbol": "BTC/USDT-P",
1498
+ # "unrealizedFundingPnl": "0.000000",
1499
+ # "unrealizedTradingPnl": "0.000625"
1500
+ # },
1501
+ # {
1502
+ # "direction": "Short",
1503
+ # "entryNotional": "2.000015",
1504
+ # "notionalValue": "2.022384",
1505
+ # "quantity": "0.01470600",
1506
+ # "symbol": "SOL/USDT-P",
1507
+ # "unrealizedFundingPnl": "0.000000",
1508
+ # "unrealizedTradingPnl": "-0.022369"
1509
+ # }
1510
+ # ],
1511
+ # }
1512
+ #
1513
+ data = self.safe_list(response, 'positions', [])
1514
+ return self.parse_positions(data, symbols)
1515
+
1516
+ def parse_position(self, position: dict, market: Market = None):
1517
+ #
1518
+ # {
1519
+ # "direction": "Short",
1520
+ # "entryNotional": "10.302213",
1521
+ # "notionalValue": "10.225008",
1522
+ # "quantity": "0.004310550",
1523
+ # "symbol": "ETH/USDT-P",
1524
+ # "unrealizedFundingPnl": "0.000000",
1525
+ # "unrealizedTradingPnl": "0.077204"
1526
+ # }
1527
+ #
1528
+ marketId = self.safe_string(position, 'symbol')
1529
+ market = self.safe_market(marketId, market)
1530
+ symbol = market['symbol']
1531
+ side = self.safe_string_lower(position, 'direction')
1532
+ quantity = self.safe_string(position, 'quantity')
1533
+ unrealizedFunding = self.safe_string(position, 'unrealizedFundingPnl', '0')
1534
+ unrealizedTrading = self.safe_string(position, 'unrealizedTradingPnl', '0')
1535
+ unrealizedPnl = Precise.string_add(unrealizedFunding, unrealizedTrading)
1536
+ return self.safe_position({
1537
+ 'info': position,
1538
+ 'id': None,
1539
+ 'symbol': symbol,
1540
+ 'entryPrice': self.safe_string(position, 'average_entry_price'),
1541
+ 'markPrice': None,
1542
+ 'notional': self.safe_string(position, 'notionalValue'),
1543
+ 'collateral': None,
1544
+ 'unrealizedPnl': unrealizedPnl,
1545
+ 'side': side,
1546
+ 'contracts': self.parse_number(quantity),
1547
+ 'contractSize': None,
1548
+ 'timestamp': None,
1549
+ 'datetime': None,
1550
+ 'hedged': None,
1551
+ 'maintenanceMargin': None,
1552
+ 'maintenanceMarginPercentage': None,
1553
+ 'initialMargin': None,
1554
+ 'initialMarginPercentage': None,
1555
+ 'leverage': None,
1556
+ 'liquidationPrice': None,
1557
+ 'marginRatio': None,
1558
+ 'marginMode': None,
1559
+ 'percentage': None,
1560
+ })
1561
+
1562
+ def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
1563
+ endpoint = '/' + self.implode_params(path, params)
1564
+ url = self.urls['api'][api] + endpoint
1565
+ headers = {}
1566
+ if method == 'GET':
1567
+ request = self.omit(params, self.extract_params(path))
1568
+ query = self.urlencode(request)
1569
+ if len(query) != 0:
1570
+ url += '?' + query
1571
+ if method == 'POST' or method == 'PUT' or method == 'DELETE':
1572
+ headers['Content-Type'] = 'application/json'
1573
+ body = self.json(params)
1574
+ if api == 'private':
1575
+ self.check_required_credentials()
1576
+ headers['Authorization'] = self.apiKey
1577
+ return {'url': url, 'method': method, 'body': body, 'headers': headers}
1578
+
1579
+ def handle_errors(self, httpCode: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
1580
+ if response is None:
1581
+ return None # fallback to default error handler
1582
+ if 'status' in response:
1583
+ #
1584
+ # {"errorCode":4,"message":"Invalid input: Invalid quantity: 0","status":"failed"}
1585
+ #
1586
+ status = self.safe_string(response, 'status')
1587
+ if status == 'failed':
1588
+ code = self.safe_string(response, 'errorCode')
1589
+ feedback = self.id + ' ' + body
1590
+ self.throw_broadly_matched_exception(self.exceptions['broad'], body, feedback)
1591
+ self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
1592
+ message = self.safe_string(response, 'message')
1593
+ self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
1594
+ raise ExchangeError(feedback)
1595
+ return None
1596
+
1597
+ def parse_transaction_type(self, type):
1598
+ types: dict = {
1599
+ 'deposit': 'transaction',
1600
+ 'withdrawal': 'transaction',
1601
+ 'transfer-in': 'transfer',
1602
+ 'transfer-out': 'transfer',
1603
+ }
1604
+ return self.safe_string(types, type, type)
1605
+
1606
+ def parse_transaction_status(self, status):
1607
+ statuses: dict = {
1608
+ 'pending': 'pending',
1609
+ 'claimable': 'pending',
1610
+ 'completed': 'ok',
1611
+ 'failed': 'canceled',
1612
+ }
1613
+ return self.safe_string(statuses, status, status)
1614
+
1615
+ def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
1616
+ transactionType = self.safe_string(item, 'transactionType')
1617
+ timestamp = None
1618
+ type = None
1619
+ direction = None
1620
+ amount = None
1621
+ fee = None
1622
+ referenceId = None
1623
+ referenceAccount = None
1624
+ status = None
1625
+ if transactionType is None:
1626
+ # response from TradeAccountTradingHistory
1627
+ timestamp = self.safe_integer_product(item, 'timestamp', 1000)
1628
+ type = 'trade'
1629
+ amountStr = self.safe_string(item, 'realizedPnl')
1630
+ if Precise.string_lt(amountStr, '0'):
1631
+ direction = 'out'
1632
+ amountStr = Precise.string_neg(amountStr)
1633
+ else:
1634
+ direction = 'in'
1635
+ amount = self.parse_number(amountStr)
1636
+ fee = {'currency': 'USDT', 'cost': self.safe_number(item, 'fee')}
1637
+ status = 'ok'
1638
+ else:
1639
+ # response from CapitalHistory
1640
+ timestamp = self.safe_integer_product(item, 'timestampSec', 1000)
1641
+ amount = self.safe_number(item, 'quantity')
1642
+ direction = 'in' if (transactionType == 'deposit' or transactionType == 'transfer-in') else 'out'
1643
+ type = self.parse_transaction_type(transactionType)
1644
+ status = self.parse_transaction_status(self.safe_string(item, 'status'))
1645
+ if transactionType == 'transfer-in':
1646
+ referenceAccount = self.safe_string(item, 'srcAccountId')
1647
+ elif transactionType == 'transfer-out':
1648
+ referenceAccount = self.safe_string(item, 'receivingAccountId')
1649
+ referenceId = self.safe_string(item, 'transactionHash')
1650
+ return self.safe_ledger_entry({
1651
+ 'id': self.safe_string(item, 'id'),
1652
+ 'currency': self.currency('USDT'),
1653
+ 'account': self.number_to_string(self.accountId),
1654
+ 'referenceAccount': referenceAccount,
1655
+ 'referenceId': referenceId,
1656
+ 'status': status,
1657
+ 'amount': amount,
1658
+ 'before': None,
1659
+ 'after': None,
1660
+ 'fee': fee,
1661
+ 'direction': direction,
1662
+ 'timestamp': timestamp,
1663
+ 'datetime': self.iso8601(timestamp),
1664
+ 'type': type,
1665
+ 'info': item,
1666
+ }, currency)
1667
+
1668
+ async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
1669
+ """
1670
+ fetch the history of changes, actions done by the user or operations that altered the balance of the user
1671
+
1672
+ https://api-doc.hibachi.xyz/#35125e3f-d154-4bfd-8276-a48bb1c62020
1673
+
1674
+ :param str [code]: unified currency code, default is None
1675
+ :param int [since]: timestamp in ms of the earliest ledger entry, default is None
1676
+ :param int [limit]: max number of ledger entries to return, default is None
1677
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1678
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
1679
+ """
1680
+ await self.load_markets()
1681
+ currency = self.currency('USDT')
1682
+ request = {'accountId': self.get_account_id()}
1683
+ rawPromises = [
1684
+ self.privateGetCapitalHistory(self.extend(request, params)),
1685
+ self.privateGetTradeAccountTradingHistory(self.extend(request, params)),
1686
+ ]
1687
+ promises = await asyncio.gather(*rawPromises)
1688
+ responseCapitalHistory = promises[0]
1689
+ #
1690
+ # {
1691
+ # "transactions": [
1692
+ # {
1693
+ # "assetId": 1,
1694
+ # "blockNumber": 358396669,
1695
+ # "chain": "Arbitrum",
1696
+ # "etaTsSec": null,
1697
+ # "id": 358396669,
1698
+ # "quantity": "0.999500",
1699
+ # "status": "pending",
1700
+ # "timestampSec": 1752692872,
1701
+ # "token": "USDT",
1702
+ # "transactionHash": "0x408e48881e0ba77d8638e3fe57bc06bdec513ddaa8b672e0aefa7e22e2f18b5e",
1703
+ # "transactionType": "deposit"
1704
+ # },
1705
+ # {
1706
+ # "assetId": 1,
1707
+ # "etaTsSec": null,
1708
+ # "id": 13116,
1709
+ # "instantWithdrawalChain": null,
1710
+ # "instantWithdrawalToken": null,
1711
+ # "isInstantWithdrawal": False,
1712
+ # "quantity": "0.040000",
1713
+ # "status": "completed",
1714
+ # "timestampSec": 1752542708,
1715
+ # "transactionHash": "0xe89cf90b2408d1a273dc9427654145def102d9449e5e2cfc10690ccffc3d7e28",
1716
+ # "transactionType": "withdrawal",
1717
+ # "withdrawalAddress": "0x23625d5fc6a6e32638d908eb4c3a3415e5121f76"
1718
+ # },
1719
+ # {
1720
+ # "assetId": 1,
1721
+ # "id": 167,
1722
+ # "quantity": "10.000000",
1723
+ # "srcAccountId": 175,
1724
+ # "srcAddress": "0xc2f77ce029438a3fdfe68ddee25991a9fb985a86",
1725
+ # "status": "completed",
1726
+ # "timestampSec": 1732224729,
1727
+ # "transactionType": "transfer-in"
1728
+ # },
1729
+ # {
1730
+ # "assetId": 1,
1731
+ # "id": 170,
1732
+ # "quantity": "10.000000",
1733
+ # "receivingAccountId": 175,
1734
+ # "receivingAddress": "0xc2f77ce029438a3fdfe68ddee25991a9fb985a86",
1735
+ # "status": "completed",
1736
+ # "timestampSec": 1732225631,
1737
+ # "transactionType": "transfer-out"
1738
+ # },
1739
+ # ]
1740
+ # }
1741
+ #
1742
+ rowsCapitalHistory = self.safe_list(responseCapitalHistory, 'transactions')
1743
+ responseTradingHistory = promises[1]
1744
+ #
1745
+ # {
1746
+ # "tradingHistory": [
1747
+ # {
1748
+ # "eventType": "MARKET",
1749
+ # "fee": "0.000008",
1750
+ # "priceOrFundingRate": "119687.82481",
1751
+ # "quantity": "0.0000003727",
1752
+ # "realizedPnl": "0.004634",
1753
+ # "side": "Sell",
1754
+ # "symbol": "BTC/USDT-P",
1755
+ # "timestamp": 1752522571
1756
+ # },
1757
+ # {
1758
+ # "eventType": "FundingEvent",
1759
+ # "fee": "0",
1760
+ # "priceOrFundingRate": "0.000203",
1761
+ # "quantity": "0.0000003727",
1762
+ # "realizedPnl": "-0.000009067899008751979",
1763
+ # "side": "Long",
1764
+ # "symbol": "BTC/USDT-P",
1765
+ # "timestamp": 1752508800
1766
+ # },
1767
+ # ]
1768
+ # }
1769
+ #
1770
+ rowsTradingHistory = self.safe_list(responseTradingHistory, 'tradingHistory')
1771
+ rows = self.array_concat(rowsCapitalHistory, rowsTradingHistory)
1772
+ return self.parse_ledger(rows, currency, since, limit, params)
1773
+
1774
+ async def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
1775
+ """
1776
+ fetch deposit address for given currency and chain. currently, we have a single EVM address across multiple EVM chains. Note: This method is currently only supported for trustless accounts
1777
+ :param str code: unified currency code
1778
+ :param dict [params]: extra parameters for API
1779
+ :param str [params.publicKey]: your public key, you can get it from UI after creating API key
1780
+ :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
1781
+ """
1782
+ request = {
1783
+ 'publicKey': self.safe_string(params, 'publicKey'),
1784
+ 'accountId': self.get_account_id(),
1785
+ }
1786
+ response = await self.privateGetCapitalDepositInfo(self.extend(request, params))
1787
+ # {
1788
+ # "depositAddressEvm": "0x0b95d90b9345dadf1460bd38b9f4bb0d2f4ed788"
1789
+ # }
1790
+ return {
1791
+ 'info': response,
1792
+ 'currency': 'USDT',
1793
+ 'network': 'ARBITRUM',
1794
+ 'address': self.safe_string(response, 'depositAddressEvm'),
1795
+ 'tag': None,
1796
+ }
1797
+
1798
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
1799
+ timestamp = self.safe_integer_product(transaction, 'timestampSec', 1000)
1800
+ address = self.safe_string(transaction, 'withdrawalAddress')
1801
+ transactionType = self.safe_string(transaction, 'transactionType')
1802
+ if transactionType != 'deposit' and transactionType != 'withdrawal':
1803
+ transactionType = self.parse_transaction_type(transactionType)
1804
+ return {
1805
+ 'info': transaction,
1806
+ 'id': self.safe_string(transaction, 'id'),
1807
+ 'txid': self.safe_string(transaction, 'transactionHash'),
1808
+ 'timestamp': timestamp,
1809
+ 'datetime': self.iso8601(timestamp),
1810
+ 'network': 'ARBITRUM', # Currently the exchange only exists on Arbitrum,
1811
+ 'address': address,
1812
+ 'addressTo': address,
1813
+ 'addressFrom': None,
1814
+ 'tag': None,
1815
+ 'tagTo': None,
1816
+ 'tagFrom': None,
1817
+ 'type': transactionType,
1818
+ 'amount': self.safe_number(transaction, 'quantity'),
1819
+ 'currency': 'USDT',
1820
+ 'status': self.parse_transaction_status(self.safe_string(transaction, 'status')),
1821
+ 'updated': None,
1822
+ 'internal': None,
1823
+ 'comment': None,
1824
+ 'fee': None,
1825
+ }
1826
+
1827
+ async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
1828
+ """
1829
+ fetch deposits made to account
1830
+
1831
+ https://api-doc.hibachi.xyz/#35125e3f-d154-4bfd-8276-a48bb1c62020
1832
+
1833
+ :param str [code]: unified currency code
1834
+ :param int [since]: filter by earliest timestamp(ms)
1835
+ :param int [limit]: maximum number of deposits to be returned
1836
+ :param dict [params]: extra parameters to be passed to API
1837
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
1838
+ """
1839
+ currency = self.safe_currency(code)
1840
+ request = {
1841
+ 'accountId': self.get_account_id(),
1842
+ }
1843
+ response = await self.privateGetCapitalHistory(self.extend(request, params))
1844
+ # {
1845
+ # "transactions": [
1846
+ # {
1847
+ # "assetId": 1,
1848
+ # "blockNumber": 0,
1849
+ # "chain": null,
1850
+ # "etaTsSec": 1752758789,
1851
+ # "id": 42688,
1852
+ # "quantity": "6.130000",
1853
+ # "status": "completed",
1854
+ # "timestampSec": 1752758788,
1855
+ # "token": null,
1856
+ # "transactionHash": "0x8dcd7bd1155b5624fb5e38a1365888f712ec633a57434340e05080c70b0e3bba",
1857
+ # "transactionType": "deposit"
1858
+ # },
1859
+ # {
1860
+ # "assetId": 1,
1861
+ # "etaTsSec": null,
1862
+ # "id": 12993,
1863
+ # "instantWithdrawalChain": null,
1864
+ # "instantWithdrawalToken": null,
1865
+ # "isInstantWithdrawal": False,
1866
+ # "quantity": "0.111930",
1867
+ # "status": "completed",
1868
+ # "timestampSec": 1752387891,
1869
+ # "transactionHash": "0x32ab5fe5b90f6d753bab83523ebc8465eb9daef54580e13cb9ff031d400c5620",
1870
+ # "transactionType": "withdrawal",
1871
+ # "withdrawalAddress": "0x43f15ef2ef2ab5e61e987ee3d652a5872aea8a6c"
1872
+ # },
1873
+ # ]
1874
+ # }
1875
+ transactions = self.safe_list(response, 'transactions')
1876
+ deposits = []
1877
+ for i in range(0, len(transactions)):
1878
+ transaction = transactions[i]
1879
+ if self.safe_string(transaction, 'transactionType') == 'deposit':
1880
+ deposits.append(transaction)
1881
+ return self.parse_transactions(deposits, currency, since, limit, params)
1882
+
1883
+ async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
1884
+ """
1885
+ fetch withdrawals made from account
1886
+
1887
+ https://api-doc.hibachi.xyz/#35125e3f-d154-4bfd-8276-a48bb1c62020
1888
+
1889
+ :param str [code]: unified currency code
1890
+ :param int [since]: filter by earliest timestamp(ms)
1891
+ :param int [limit]: maximum number of deposits to be returned
1892
+ :param dict [params]: extra parameters to be passed to API
1893
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
1894
+ """
1895
+ currency = self.safe_currency(code)
1896
+ request = {
1897
+ 'accountId': self.get_account_id(),
1898
+ }
1899
+ response = await self.privateGetCapitalHistory(self.extend(request, params))
1900
+ # {
1901
+ # "transactions": [
1902
+ # {
1903
+ # "assetId": 1,
1904
+ # "blockNumber": 0,
1905
+ # "chain": null,
1906
+ # "etaTsSec": 1752758789,
1907
+ # "id": 42688,
1908
+ # "quantity": "6.130000",
1909
+ # "status": "completed",
1910
+ # "timestampSec": 1752758788,
1911
+ # "token": null,
1912
+ # "transactionHash": "0x8dcd7bd1155b5624fb5e38a1365888f712ec633a57434340e05080c70b0e3bba",
1913
+ # "transactionType": "deposit"
1914
+ # },
1915
+ # {
1916
+ # "assetId": 1,
1917
+ # "etaTsSec": null,
1918
+ # "id": 12993,
1919
+ # "instantWithdrawalChain": null,
1920
+ # "instantWithdrawalToken": null,
1921
+ # "isInstantWithdrawal": False,
1922
+ # "quantity": "0.111930",
1923
+ # "status": "completed",
1924
+ # "timestampSec": 1752387891,
1925
+ # "transactionHash": "0x32ab5fe5b90f6d753bab83523ebc8465eb9daef54580e13cb9ff031d400c5620",
1926
+ # "transactionType": "withdrawal",
1927
+ # "withdrawalAddress": "0x43f15ef2ef2ab5e61e987ee3d652a5872aea8a6c"
1928
+ # },
1929
+ # ]
1930
+ # }
1931
+ transactions = self.safe_list(response, 'transactions')
1932
+ withdrawals = []
1933
+ for i in range(0, len(transactions)):
1934
+ transaction = transactions[i]
1935
+ if self.safe_string(transaction, 'transactionType') == 'withdrawal':
1936
+ withdrawals.append(transaction)
1937
+ return self.parse_transactions(withdrawals, currency, since, limit, params)
1938
+
1939
+ async def fetch_time(self, params={}) -> Int:
1940
+ """
1941
+ fetches the current integer timestamp in milliseconds from the exchange server
1942
+
1943
+ http://api-doc.hibachi.xyz/#b5c6a3bc-243d-4d35-b6d4-a74c92495434
1944
+
1945
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1946
+ :returns int: the current integer timestamp in milliseconds from the exchange server
1947
+ """
1948
+ response = await self.publicGetExchangeUtcTimestamp(params)
1949
+ #
1950
+ # {"timestampMs":1754077574040}
1951
+ #
1952
+ return self.safe_integer(response, 'timestampMs')
1953
+
1954
+ async def fetch_open_interest(self, symbol: str, params={}):
1955
+ """
1956
+ retrieves the open interest of a contract trading pair
1957
+
1958
+ https://api-doc.hibachi.xyz/#bc34e8ae-e094-4802-8d56-3efe3a7bad49
1959
+
1960
+ :param str symbol: unified CCXT market symbol
1961
+ :param dict [params]: exchange specific parameters
1962
+ :returns dict} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure:
1963
+ """
1964
+ await self.load_markets()
1965
+ market = self.market(symbol)
1966
+ request: dict = {
1967
+ 'symbol': market['id'],
1968
+ }
1969
+ response = await self.publicGetMarketDataOpenInterest(self.extend(request, params))
1970
+ #
1971
+ # {"totalQuantity" : "2.3299770166"}
1972
+ #
1973
+ timestamp = self.milliseconds()
1974
+ return self.safe_open_interest({
1975
+ 'symbol': symbol,
1976
+ 'openInterestAmount': self.safe_string(response, 'totalQuantity'),
1977
+ 'openInterestValue': None,
1978
+ 'timestamp': timestamp,
1979
+ 'datetime': self.iso8601(timestamp),
1980
+ 'info': response,
1981
+ }, market)
1982
+
1983
+ async def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
1984
+ """
1985
+ fetch the current funding rate
1986
+
1987
+ https://api-doc.hibachi.xyz/#bca696ca-b9b2-4072-8864-5d6b8c09807e
1988
+
1989
+ :param str symbol: unified market symbol
1990
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1991
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
1992
+ """
1993
+ await self.load_markets()
1994
+ market = self.market(symbol)
1995
+ request: dict = {
1996
+ 'symbol': market['id'],
1997
+ }
1998
+ response = await self.publicGetMarketDataPrices(self.extend(request, params))
1999
+ #
2000
+ # {
2001
+ # "askPrice": "3514.650296",
2002
+ # "bidPrice": "3513.596112",
2003
+ # "fundingRateEstimation": {
2004
+ # "estimatedFundingRate": "0.000001",
2005
+ # "nextFundingTimestamp": 1712707200
2006
+ # },
2007
+ # "markPrice": "3514.288858",
2008
+ # "spotPrice": "3514.715000",
2009
+ # "symbol": "ETH/USDT-P",
2010
+ # "tradePrice": "2372.746570"
2011
+ # }
2012
+ #
2013
+ funding = self.safe_dict(response, 'fundingRateEstimation', {})
2014
+ timestamp = self.milliseconds()
2015
+ nextFundingTimestamp = self.safe_integer_product(funding, 'nextFundingTimestamp', 1000)
2016
+ return {
2017
+ 'info': funding,
2018
+ 'symbol': market['symbol'],
2019
+ 'markPrice': None,
2020
+ 'indexPrice': None,
2021
+ 'interestRate': self.parse_number('0'),
2022
+ 'estimatedSettlePrice': None,
2023
+ 'timestamp': timestamp,
2024
+ 'datetime': self.iso8601(timestamp),
2025
+ 'fundingRate': self.safe_number(funding, 'estimatedFundingRate'),
2026
+ 'fundingTimestamp': nextFundingTimestamp,
2027
+ 'fundingDatetime': self.iso8601(nextFundingTimestamp),
2028
+ 'nextFundingRate': None,
2029
+ 'nextFundingTimestamp': None,
2030
+ 'nextFundingDatetime': None,
2031
+ 'previousFundingRate': None,
2032
+ 'previousFundingTimestamp': None,
2033
+ 'previousFundingDatetime': None,
2034
+ 'interval': '8h',
2035
+ }
2036
+
2037
+ async def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2038
+ """
2039
+ fetches historical funding rate prices
2040
+
2041
+ https://api-doc.hibachi.xyz/#4abb30c4-e5c7-4b0f-9ade-790111dbfa47
2042
+
2043
+ :param str symbol: unified symbol of the market to fetch the funding rate history for
2044
+ :param int [since]: timestamp in ms of the earliest funding rate to fetch
2045
+ :param int [limit]: the maximum amount of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>` to fetch
2046
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2047
+ :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>`
2048
+ """
2049
+ await self.load_markets()
2050
+ market = self.market(symbol)
2051
+ request: dict = {
2052
+ 'symbol': market['id'],
2053
+ }
2054
+ response = await self.publicGetMarketDataFundingRates(self.extend(request, params))
2055
+ #
2056
+ # {
2057
+ # "data": [
2058
+ # {
2059
+ # "contractId": 2,
2060
+ # "fundingTimestamp": 1753488000,
2061
+ # "fundingRate": "0.000137",
2062
+ # "indexPrice": "117623.65010"
2063
+ # }
2064
+ # ]
2065
+ # }
2066
+ #
2067
+ data = self.safe_list(response, 'data')
2068
+ rates = []
2069
+ for i in range(0, len(data)):
2070
+ entry = data[i]
2071
+ timestamp = self.safe_integer_product(entry, 'fundingTimestamp', 1000)
2072
+ rates.append({
2073
+ 'info': entry,
2074
+ 'symbol': symbol,
2075
+ 'fundingRate': self.safe_number(entry, 'fundingRate'),
2076
+ 'timestamp': timestamp,
2077
+ 'datetime': self.iso8601(timestamp),
2078
+ })
2079
+ sorted = self.sort_by(rates, 'timestamp')
2080
+ return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)