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