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
@@ -0,0 +1,4628 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+
6
+ from ccxt.async_support.base.exchange import Exchange
7
+ from ccxt.abstract.xt import ImplicitAPI
8
+ import asyncio
9
+ import hashlib
10
+ from ccxt.base.types import Currencies, Currency, DepositAddress, Int, LedgerEntry, LeverageTier, LeverageTiers, MarginModification, Market, Num, Order, OrderSide, OrderType, Str, Tickers, FundingRate, Transaction, TransferEntry
11
+ from typing import List
12
+ from ccxt.base.errors import ExchangeError
13
+ from ccxt.base.errors import AuthenticationError
14
+ from ccxt.base.errors import PermissionDenied
15
+ from ccxt.base.errors import ArgumentsRequired
16
+ from ccxt.base.errors import BadRequest
17
+ from ccxt.base.errors import BadSymbol
18
+ from ccxt.base.errors import InsufficientFunds
19
+ from ccxt.base.errors import InvalidOrder
20
+ from ccxt.base.errors import NotSupported
21
+ from ccxt.base.errors import NetworkError
22
+ from ccxt.base.errors import RateLimitExceeded
23
+ from ccxt.base.errors import OnMaintenance
24
+ from ccxt.base.errors import RequestTimeout
25
+ from ccxt.base.decimal_to_precision import TICK_SIZE
26
+ from ccxt.base.precise import Precise
27
+
28
+
29
+ class xt(Exchange, ImplicitAPI):
30
+
31
+ def describe(self):
32
+ return self.deep_extend(super(xt, self).describe(), {
33
+ 'id': 'xt',
34
+ 'name': 'XT',
35
+ 'countries': ['SC'], # Seychelles
36
+ # spot api ratelimits are None, 10/s/ip, 50/s/ip, 100/s/ip or 200/s/ip
37
+ # futures 3 requests per second => 1000ms / (100 * 3.33) = 3.003(get assets -> fetchMarkets & fetchCurrencies)
38
+ # futures 10 requests per second => 1000ms / (100 * 1) = 10(all other)
39
+ # futures 1000 times per minute for each single IP -> Otherwise account locked for 10min
40
+ 'rateLimit': 100,
41
+ 'version': 'v4',
42
+ 'certified': False,
43
+ 'pro': True,
44
+ 'has': {
45
+ 'CORS': False,
46
+ 'spot': True,
47
+ 'margin': True,
48
+ 'swap': True,
49
+ 'future': True,
50
+ 'option': False,
51
+ 'addMargin': True,
52
+ 'borrowMargin': False,
53
+ 'cancelAllOrders': True,
54
+ 'cancelOrder': True,
55
+ 'cancelOrders': True,
56
+ 'createDepositAddress': False,
57
+ 'createMarketBuyOrderWithCost': True,
58
+ 'createMarketSellOrderWithCost': False,
59
+ 'createOrder': True,
60
+ 'createPostOnlyOrder': False,
61
+ 'createReduceOnlyOrder': True,
62
+ 'editOrder': False,
63
+ 'fetchAccounts': False,
64
+ 'fetchBalance': True,
65
+ 'fetchBidsAsks': True,
66
+ 'fetchBorrowInterest': False,
67
+ 'fetchBorrowRate': False,
68
+ 'fetchBorrowRateHistories': False,
69
+ 'fetchBorrowRateHistory': False,
70
+ 'fetchBorrowRatesPerSymbol': False,
71
+ 'fetchCanceledOrders': True,
72
+ 'fetchClosedOrders': True,
73
+ 'fetchCurrencies': True,
74
+ 'fetchDeposit': False,
75
+ 'fetchDepositAddress': True,
76
+ 'fetchDepositAddresses': False,
77
+ 'fetchDepositAddressesByNetwork': False,
78
+ 'fetchDeposits': True,
79
+ 'fetchDepositWithdrawals': False,
80
+ 'fetchDepositWithdrawFee': False,
81
+ 'fetchDepositWithdrawFees': False,
82
+ 'fetchFundingHistory': True,
83
+ 'fetchFundingInterval': True,
84
+ 'fetchFundingIntervals': False,
85
+ 'fetchFundingRate': True,
86
+ 'fetchFundingRateHistory': True,
87
+ 'fetchFundingRates': False,
88
+ 'fetchIndexOHLCV': False,
89
+ 'fetchL3OrderBook': False,
90
+ 'fetchLedger': True,
91
+ 'fetchLedgerEntry': False,
92
+ 'fetchLeverage': False,
93
+ 'fetchLeverageTiers': True,
94
+ 'fetchMarketLeverageTiers': True,
95
+ 'fetchMarkets': True,
96
+ 'fetchMarkOHLCV': False,
97
+ 'fetchMyTrades': True,
98
+ 'fetchOHLCV': True,
99
+ 'fetchOpenInterest': False,
100
+ 'fetchOpenInterestHistory': False,
101
+ 'fetchOpenOrders': True,
102
+ 'fetchOrder': True,
103
+ 'fetchOrderBook': True,
104
+ 'fetchOrderBooks': False,
105
+ 'fetchOrders': True,
106
+ 'fetchOrdersByStatus': True,
107
+ 'fetchOrderTrades': False,
108
+ 'fetchPosition': True,
109
+ 'fetchPositions': True,
110
+ 'fetchPremiumIndexOHLCV': False,
111
+ 'fetchSettlementHistory': False,
112
+ 'fetchStatus': False,
113
+ 'fetchTicker': True,
114
+ 'fetchTickers': True,
115
+ 'fetchTime': True,
116
+ 'fetchTrades': True,
117
+ 'fetchTradingFee': False,
118
+ 'fetchTradingFees': False,
119
+ 'fetchTradingLimits': False,
120
+ 'fetchTransactionFee': False,
121
+ 'fetchTransactionFees': False,
122
+ 'fetchTransactions': False,
123
+ 'fetchTransfer': False,
124
+ 'fetchTransfers': False,
125
+ 'fetchWithdrawal': False,
126
+ 'fetchWithdrawals': True,
127
+ 'fetchWithdrawalWhitelist': False,
128
+ 'reduceMargin': True,
129
+ 'repayMargin': False,
130
+ 'setLeverage': True,
131
+ 'setMargin': False,
132
+ 'setMarginMode': False,
133
+ 'setPositionMode': False,
134
+ 'signIn': False,
135
+ 'transfer': True,
136
+ 'withdraw': True,
137
+ },
138
+ 'precisionMode': TICK_SIZE,
139
+ 'urls': {
140
+ 'logo': 'https://user-images.githubusercontent.com/14319357/232636712-466df2fc-560a-4ca4-aab2-b1d954a58e24.jpg',
141
+ 'api': {
142
+ 'spot': 'https://sapi.xt.com',
143
+ 'linear': 'https://fapi.xt.com',
144
+ 'inverse': 'https://dapi.xt.com',
145
+ 'user': 'https://api.xt.com',
146
+ },
147
+ 'www': 'https://xt.com',
148
+ 'referral': 'https://www.xt.com/en/accounts/register?ref=9PTM9VW',
149
+ 'doc': [
150
+ 'https://doc.xt.com/',
151
+ 'https://github.com/xtpub/api-doc',
152
+ ],
153
+ 'fees': 'https://www.xt.com/en/rate',
154
+ },
155
+ 'api': {
156
+ 'public': {
157
+ 'spot': {
158
+ 'get': {
159
+ 'currencies': 1,
160
+ 'depth': 10,
161
+ 'kline': 1,
162
+ 'symbol': 1, # 1 for a single symbol
163
+ 'ticker': 1, # 1 for a single symbol
164
+ 'ticker/book': 1, # 1 for a single symbol
165
+ 'ticker/price': 1, # 1 for a single symbol
166
+ 'ticker/24h': 1, # 1 for a single symbol
167
+ 'time': 1,
168
+ 'trade/history': 1,
169
+ 'trade/recent': 1,
170
+ 'wallet/support/currency': 1,
171
+ },
172
+ },
173
+ 'linear': {
174
+ 'get': {
175
+ 'future/market/v1/public/contract/risk-balance': 1,
176
+ 'future/market/v1/public/contract/open-interest': 1,
177
+ 'future/market/v1/public/leverage/bracket/detail': 1,
178
+ 'future/market/v1/public/leverage/bracket/list': 1,
179
+ 'future/market/v1/public/q/agg-ticker': 1,
180
+ 'future/market/v1/public/q/agg-tickers': 1,
181
+ 'future/market/v1/public/q/deal': 1,
182
+ 'future/market/v1/public/q/depth': 1,
183
+ 'future/market/v1/public/q/funding-rate': 1,
184
+ 'future/market/v1/public/q/funding-rate-record': 1,
185
+ 'future/market/v1/public/q/index-price': 1,
186
+ 'future/market/v1/public/q/kline': 1,
187
+ 'future/market/v1/public/q/mark-price': 1,
188
+ 'future/market/v1/public/q/symbol-index-price': 1,
189
+ 'future/market/v1/public/q/symbol-mark-price': 1,
190
+ 'future/market/v1/public/q/ticker': 1,
191
+ 'future/market/v1/public/q/tickers': 1,
192
+ 'future/market/v1/public/symbol/coins': 3.33,
193
+ 'future/market/v1/public/symbol/detail': 3.33,
194
+ 'future/market/v1/public/symbol/list': 1,
195
+ },
196
+ },
197
+ 'inverse': {
198
+ 'get': {
199
+ 'future/market/v1/public/contract/risk-balance': 1,
200
+ 'future/market/v1/public/contract/open-interest': 1,
201
+ 'future/market/v1/public/leverage/bracket/detail': 1,
202
+ 'future/market/v1/public/leverage/bracket/list': 1,
203
+ 'future/market/v1/public/q/agg-ticker': 1,
204
+ 'future/market/v1/public/q/agg-tickers': 1,
205
+ 'future/market/v1/public/q/deal': 1,
206
+ 'future/market/v1/public/q/depth': 1,
207
+ 'future/market/v1/public/q/funding-rate': 1,
208
+ 'future/market/v1/public/q/funding-rate-record': 1,
209
+ 'future/market/v1/public/q/index-price': 1,
210
+ 'future/market/v1/public/q/kline': 1,
211
+ 'future/market/v1/public/q/mark-price': 1,
212
+ 'future/market/v1/public/q/symbol-index-price': 1,
213
+ 'future/market/v1/public/q/symbol-mark-price': 1,
214
+ 'future/market/v1/public/q/ticker': 1,
215
+ 'future/market/v1/public/q/tickers': 1,
216
+ 'future/market/v1/public/symbol/coins': 3.33,
217
+ 'future/market/v1/public/symbol/detail': 3.33,
218
+ 'future/market/v1/public/symbol/list': 1,
219
+ },
220
+ },
221
+ },
222
+ 'private': {
223
+ 'spot': {
224
+ 'get': {
225
+ 'balance': 1,
226
+ 'balances': 1,
227
+ 'batch-order': 1,
228
+ 'deposit/address': 1,
229
+ 'deposit/history': 1,
230
+ 'history-order': 1,
231
+ 'open-order': 1,
232
+ 'order': 1,
233
+ 'order/{orderId}': 1,
234
+ 'trade': 1,
235
+ 'withdraw/history': 1,
236
+ },
237
+ 'post': {
238
+ 'order': 0.2,
239
+ 'withdraw': 10,
240
+ 'balance/transfer': 1,
241
+ 'balance/account/transfer': 1,
242
+ 'ws-token': 1,
243
+ },
244
+ 'delete': {
245
+ 'batch-order': 1,
246
+ 'open-order': 1,
247
+ 'order/{orderId}': 1,
248
+ },
249
+ },
250
+ 'linear': {
251
+ 'get': {
252
+ 'future/trade/v1/entrust/plan-detail': 1,
253
+ 'future/trade/v1/entrust/plan-list': 1,
254
+ 'future/trade/v1/entrust/plan-list-history': 1,
255
+ 'future/trade/v1/entrust/profit-detail': 1,
256
+ 'future/trade/v1/entrust/profit-list': 1,
257
+ 'future/trade/v1/order/detail': 1,
258
+ 'future/trade/v1/order/list': 1,
259
+ 'future/trade/v1/order/list-history': 1,
260
+ 'future/trade/v1/order/trade-list': 1,
261
+ 'future/user/v1/account/info': 1,
262
+ 'future/user/v1/balance/bills': 1,
263
+ 'future/user/v1/balance/detail': 1,
264
+ 'future/user/v1/balance/funding-rate-list': 1,
265
+ 'future/user/v1/balance/list': 1,
266
+ 'future/user/v1/position/adl': 1,
267
+ 'future/user/v1/position/list': 1,
268
+ 'future/user/v1/user/collection/list': 1,
269
+ 'future/user/v1/user/listen-key': 1,
270
+ },
271
+ 'post': {
272
+ 'future/trade/v1/entrust/cancel-all-plan': 1,
273
+ 'future/trade/v1/entrust/cancel-all-profit-stop': 1,
274
+ 'future/trade/v1/entrust/cancel-plan': 1,
275
+ 'future/trade/v1/entrust/cancel-profit-stop': 1,
276
+ 'future/trade/v1/entrust/create-plan': 1,
277
+ 'future/trade/v1/entrust/create-profit': 1,
278
+ 'future/trade/v1/entrust/update-profit-stop': 1,
279
+ 'future/trade/v1/order/cancel': 1,
280
+ 'future/trade/v1/order/cancel-all': 1,
281
+ 'future/trade/v1/order/create': 1,
282
+ 'future/trade/v1/order/create-batch': 1,
283
+ 'future/user/v1/account/open': 1,
284
+ 'future/user/v1/position/adjust-leverage': 1,
285
+ 'future/user/v1/position/auto-margin': 1,
286
+ 'future/user/v1/position/close-all': 1,
287
+ 'future/user/v1/position/margin': 1,
288
+ 'future/user/v1/user/collection/add': 1,
289
+ 'future/user/v1/user/collection/cancel': 1,
290
+ },
291
+ },
292
+ 'inverse': {
293
+ 'get': {
294
+ 'future/trade/v1/entrust/plan-detail': 1,
295
+ 'future/trade/v1/entrust/plan-list': 1,
296
+ 'future/trade/v1/entrust/plan-list-history': 1,
297
+ 'future/trade/v1/entrust/profit-detail': 1,
298
+ 'future/trade/v1/entrust/profit-list': 1,
299
+ 'future/trade/v1/order/detail': 1,
300
+ 'future/trade/v1/order/list': 1,
301
+ 'future/trade/v1/order/list-history': 1,
302
+ 'future/trade/v1/order/trade-list': 1,
303
+ 'future/user/v1/account/info': 1,
304
+ 'future/user/v1/balance/bills': 1,
305
+ 'future/user/v1/balance/detail': 1,
306
+ 'future/user/v1/balance/funding-rate-list': 1,
307
+ 'future/user/v1/balance/list': 1,
308
+ 'future/user/v1/position/adl': 1,
309
+ 'future/user/v1/position/list': 1,
310
+ 'future/user/v1/user/collection/list': 1,
311
+ 'future/user/v1/user/listen-key': 1,
312
+ },
313
+ 'post': {
314
+ 'future/trade/v1/entrust/cancel-all-plan': 1,
315
+ 'future/trade/v1/entrust/cancel-all-profit-stop': 1,
316
+ 'future/trade/v1/entrust/cancel-plan': 1,
317
+ 'future/trade/v1/entrust/cancel-profit-stop': 1,
318
+ 'future/trade/v1/entrust/create-plan': 1,
319
+ 'future/trade/v1/entrust/create-profit': 1,
320
+ 'future/trade/v1/entrust/update-profit-stop': 1,
321
+ 'future/trade/v1/order/cancel': 1,
322
+ 'future/trade/v1/order/cancel-all': 1,
323
+ 'future/trade/v1/order/create': 1,
324
+ 'future/trade/v1/order/create-batch': 1,
325
+ 'future/user/v1/account/open': 1,
326
+ 'future/user/v1/position/adjust-leverage': 1,
327
+ 'future/user/v1/position/auto-margin': 1,
328
+ 'future/user/v1/position/close-all': 1,
329
+ 'future/user/v1/position/margin': 1,
330
+ 'future/user/v1/user/collection/add': 1,
331
+ 'future/user/v1/user/collection/cancel': 1,
332
+ },
333
+ },
334
+ 'user': {
335
+ 'get': {
336
+ 'user/account': 1,
337
+ 'user/account/api-key': 1,
338
+ },
339
+ 'post': {
340
+ 'user/account': 1,
341
+ 'user/account/api-key': 1,
342
+ },
343
+ 'put': {
344
+ 'user/account/api-key': 1,
345
+ },
346
+ 'delete': {
347
+ 'user/account/{apikeyId}': 1,
348
+ },
349
+ },
350
+ },
351
+ },
352
+ 'fees': {
353
+ 'spot': {
354
+ 'tierBased': True,
355
+ 'percentage': True,
356
+ 'maker': self.parse_number('0.002'),
357
+ 'taker': self.parse_number('0.002'),
358
+ 'tiers': {
359
+ 'maker': [
360
+ [self.parse_number('0'), self.parse_number('0.002')],
361
+ [self.parse_number('5000'), self.parse_number('0.0018')],
362
+ [self.parse_number('10000'), self.parse_number('0.0016')],
363
+ [self.parse_number('20000'), self.parse_number('0.0014')],
364
+ [self.parse_number('50000'), self.parse_number('0.0012')],
365
+ [self.parse_number('150000'), self.parse_number('0.0010')],
366
+ [self.parse_number('300000'), self.parse_number('0.0008')],
367
+ [self.parse_number('600000'), self.parse_number('0.0007')],
368
+ [self.parse_number('1200000'), self.parse_number('0.0006')],
369
+ [self.parse_number('2500000'), self.parse_number('0.0005')],
370
+ [self.parse_number('6000000'), self.parse_number('0.0004')],
371
+ [self.parse_number('15000000'), self.parse_number('0.0003')],
372
+ [self.parse_number('30000000'), self.parse_number('0.0002')],
373
+ ],
374
+ 'taker': [
375
+ [self.parse_number('0'), self.parse_number('0.002')],
376
+ [self.parse_number('5000'), self.parse_number('0.0018')],
377
+ [self.parse_number('10000'), self.parse_number('0.0016')],
378
+ [self.parse_number('20000'), self.parse_number('0.0014')],
379
+ [self.parse_number('50000'), self.parse_number('0.0012')],
380
+ [self.parse_number('150000'), self.parse_number('0.0010')],
381
+ [self.parse_number('300000'), self.parse_number('0.0008')],
382
+ [self.parse_number('600000'), self.parse_number('0.0007')],
383
+ [self.parse_number('1200000'), self.parse_number('0.0006')],
384
+ [self.parse_number('2500000'), self.parse_number('0.0005')],
385
+ [self.parse_number('6000000'), self.parse_number('0.0004')],
386
+ [self.parse_number('15000000'), self.parse_number('0.0003')],
387
+ [self.parse_number('30000000'), self.parse_number('0.0002')],
388
+ ],
389
+ },
390
+ },
391
+ 'contract': {
392
+ 'tierBased': True,
393
+ 'percentage': True,
394
+ 'maker': self.parse_number('0.0004'),
395
+ 'taker': self.parse_number('0.0006'),
396
+ 'tiers': {
397
+ 'maker': [
398
+ [self.parse_number('0'), self.parse_number('0.0004')],
399
+ [self.parse_number('200000'), self.parse_number('0.00038')],
400
+ [self.parse_number('1000000'), self.parse_number('0.00036')],
401
+ [self.parse_number('5000000'), self.parse_number('0.00034')],
402
+ [self.parse_number('10000000'), self.parse_number('0.00032')],
403
+ [self.parse_number('15000000'), self.parse_number('0.00028')],
404
+ [self.parse_number('30000000'), self.parse_number('0.00024')],
405
+ [self.parse_number('50000000'), self.parse_number('0.0002')],
406
+ [self.parse_number('100000000'), self.parse_number('0.00016')],
407
+ [self.parse_number('300000000'), self.parse_number('0.00012')],
408
+ [self.parse_number('500000000'), self.parse_number('0.00008')],
409
+ ],
410
+ 'taker': [
411
+ [self.parse_number('0'), self.parse_number('0.0006')],
412
+ [self.parse_number('200000'), self.parse_number('0.000588')],
413
+ [self.parse_number('1000000'), self.parse_number('0.00057')],
414
+ [self.parse_number('5000000'), self.parse_number('0.00054')],
415
+ [self.parse_number('10000000'), self.parse_number('0.00051')],
416
+ [self.parse_number('15000000'), self.parse_number('0.00048')],
417
+ [self.parse_number('30000000'), self.parse_number('0.00045')],
418
+ [self.parse_number('50000000'), self.parse_number('0.00045')],
419
+ [self.parse_number('100000000'), self.parse_number('0.00036')],
420
+ [self.parse_number('300000000'), self.parse_number('0.00033')],
421
+ [self.parse_number('500000000'), self.parse_number('0.0003')],
422
+ ],
423
+ },
424
+ },
425
+ },
426
+ 'exceptions': {
427
+ 'exact': {
428
+ '400': NetworkError, # {"returnCode":1,"msgInfo":"failure","error":{"code":"400","msg":"Connection refused: /10.0.26.71:8080"},"result":null}
429
+ '404': ExchangeError, # interface does not exist
430
+ '429': RateLimitExceeded, # The request is too frequent, please control the request rate according to the speed limit requirement
431
+ '500': ExchangeError, # Service exception
432
+ '502': ExchangeError, # Gateway exception
433
+ '503': OnMaintenance, # Service unavailable, please try again later
434
+ 'AUTH_001': AuthenticationError, # missing request header xt-validate-appkey
435
+ 'AUTH_002': AuthenticationError, # missing request header xt-validate-timestamp
436
+ 'AUTH_003': AuthenticationError, # missing request header xt-validate-recvwindow
437
+ 'AUTH_004': AuthenticationError, # bad request header xt-validate-recvwindow
438
+ 'AUTH_005': AuthenticationError, # missing request header xt-validate-algorithms
439
+ 'AUTH_006': AuthenticationError, # bad request header xt-validate-algorithms
440
+ 'AUTH_007': AuthenticationError, # missing request header xt-validate-signature
441
+ 'AUTH_101': AuthenticationError, # ApiKey does not exist
442
+ 'AUTH_102': AuthenticationError, # ApiKey is not activated
443
+ 'AUTH_103': AuthenticationError, # Signature error, {"rc":1,"mc":"AUTH_103","ma":[],"result":null}
444
+ 'AUTH_104': AuthenticationError, # Unbound IP request
445
+ 'AUTH_105': AuthenticationError, # outdated message
446
+ 'AUTH_106': PermissionDenied, # Exceeded apikey permission
447
+ 'SYMBOL_001': BadSymbol, # Symbol not exist
448
+ 'SYMBOL_002': BadSymbol, # Symbol offline
449
+ 'SYMBOL_003': BadSymbol, # Symbol suspend trading
450
+ 'SYMBOL_004': BadSymbol, # Symbol country disallow trading
451
+ 'SYMBOL_005': BadSymbol, # The symbol does not support trading via API
452
+ 'ORDER_001': InvalidOrder, # Platform rejection
453
+ 'ORDER_002': InsufficientFunds, # insufficient funds
454
+ 'ORDER_003': InvalidOrder, # Trading Pair Suspended
455
+ 'ORDER_004': InvalidOrder, # no transaction
456
+ 'ORDER_005': InvalidOrder, # Order not exist
457
+ 'ORDER_006': InvalidOrder, # Too many open orders
458
+ 'ORDER_007': PermissionDenied, # The sub-account has no transaction authority
459
+ 'ORDER_F0101': InvalidOrder, # Trigger Price Filter - Min
460
+ 'ORDER_F0102': InvalidOrder, # Trigger Price Filter - Max
461
+ 'ORDER_F0103': InvalidOrder, # Trigger Price Filter - Step Value
462
+ 'ORDER_F0201': InvalidOrder, # Trigger Quantity Filter - Min
463
+ 'ORDER_F0202': InvalidOrder, # Trigger Quantity Filter - Max
464
+ 'ORDER_F0203': InvalidOrder, # Trigger Quantity Filter - Step Value
465
+ 'ORDER_F0301': InvalidOrder, # Trigger QUOTE_QTY Filter - Min Value
466
+ 'ORDER_F0401': InvalidOrder, # Trigger PROTECTION_ONLINE Filter
467
+ 'ORDER_F0501': InvalidOrder, # Trigger PROTECTION_LIMIT Filter - Buy Max Deviation
468
+ 'ORDER_F0502': InvalidOrder, # Trigger PROTECTION_LIMIT Filter - Sell Max Deviation
469
+ 'ORDER_F0601': InvalidOrder, # Trigger PROTECTION_MARKET Filter
470
+ 'COMMON_001': ExchangeError, # The user does not exist
471
+ 'COMMON_002': ExchangeError, # System busy, please try it later
472
+ 'COMMON_003': BadRequest, # Operation failed, please try it later
473
+ 'CURRENCY_001': BadRequest, # Information of currency is abnormal
474
+ 'DEPOSIT_001': BadRequest, # Deposit is not open
475
+ 'DEPOSIT_002': PermissionDenied, # The current account security level is low, please bind any two security verifications in mobile phone/email/Google Authenticator before deposit
476
+ 'DEPOSIT_003': BadRequest, # The format of address is incorrect, please enter again
477
+ 'DEPOSIT_004': BadRequest, # The address is already exists, please enter again
478
+ 'DEPOSIT_005': BadRequest, # Can not find the address of offline wallet
479
+ 'DEPOSIT_006': BadRequest, # No deposit address, please try it later
480
+ 'DEPOSIT_007': BadRequest, # Address is being generated, please try it later
481
+ 'DEPOSIT_008': BadRequest, # Deposit is not available
482
+ 'WITHDRAW_001': BadRequest, # Withdraw is not open
483
+ 'WITHDRAW_002': BadRequest, # The withdrawal address is invalid
484
+ 'WITHDRAW_003': PermissionDenied, # The current account security level is low, please bind any two security verifications in mobile phone/email/Google Authenticator before withdraw
485
+ 'WITHDRAW_004': BadRequest, # The withdrawal address is not added
486
+ 'WITHDRAW_005': BadRequest, # The withdrawal address cannot be empty
487
+ 'WITHDRAW_006': BadRequest, # Memo cannot be empty
488
+ 'WITHDRAW_008': PermissionDenied, # Risk control is triggered, withdraw of self currency is not currently supported
489
+ 'WITHDRAW_009': PermissionDenied, # Withdraw failed, some hasattr(self, assets) withdraw are restricted by T+1 withdraw
490
+ 'WITHDRAW_010': BadRequest, # The precision of withdrawal is invalid
491
+ 'WITHDRAW_011': InsufficientFunds, # free balance is not enough
492
+ 'WITHDRAW_012': PermissionDenied, # Withdraw failed, your remaining withdrawal limit today is not enough
493
+ 'WITHDRAW_013': PermissionDenied, # Withdraw failed, your remaining withdrawal limit today is not enough, the withdrawal amount can be increased by completing a higher level of real-name authentication
494
+ 'WITHDRAW_014': BadRequest, # This withdrawal address cannot be used in the internal transfer function, please cancel the internal transfer function before submitting
495
+ 'WITHDRAW_015': BadRequest, # The withdrawal amount is not enough to deduct the handling fee
496
+ 'WITHDRAW_016': BadRequest, # This withdrawal address is already exists
497
+ 'WITHDRAW_017': BadRequest, # This withdrawal has been processed and cannot be canceled
498
+ 'WITHDRAW_018': BadRequest, # Memo must be a number
499
+ 'WITHDRAW_019': BadRequest, # Memo is incorrect, please enter again
500
+ 'WITHDRAW_020': PermissionDenied, # Your withdrawal amount has reached the upper limit for today, please try it tomorrow
501
+ 'WITHDRAW_021': PermissionDenied, # Your withdrawal amount has reached the upper limit for today, you can only withdraw up to {0} self time
502
+ 'WITHDRAW_022': BadRequest, # Withdrawal amount must be greater than {0}
503
+ 'WITHDRAW_023': BadRequest, # Withdrawal amount must be less than {0}
504
+ 'WITHDRAW_024': BadRequest, # Withdraw is not supported
505
+ 'WITHDRAW_025': BadRequest, # Please create a FIO address in the deposit page
506
+ 'FUND_001': BadRequest, # Duplicate request(a bizId can only be requested once)
507
+ 'FUND_002': InsufficientFunds, # Insufficient account balance
508
+ 'FUND_003': BadRequest, # Transfer operations are not supported(for example, sub-accounts do not support financial transfers)
509
+ 'FUND_004': ExchangeError, # Unfreeze failed
510
+ 'FUND_005': PermissionDenied, # Transfer prohibited
511
+ 'FUND_014': BadRequest, # The transfer-in account id and transfer-out account ID cannot be the same
512
+ 'FUND_015': BadRequest, # From and to business types cannot be the same
513
+ 'FUND_016': BadRequest, # Leverage transfer, symbol cannot be empty
514
+ 'FUND_017': BadRequest, # Parameter error
515
+ 'FUND_018': BadRequest, # Invalid freeze record
516
+ 'FUND_019': BadRequest, # Freeze users not equal
517
+ 'FUND_020': BadRequest, # Freeze currency are not equal
518
+ 'FUND_021': BadRequest, # Operation not supported
519
+ 'FUND_022': BadRequest, # Freeze record does not exist
520
+ 'FUND_044': BadRequest, # The maximum length of the amount is 113 and cannot exceed the limit
521
+ 'TRANSFER_001': BadRequest, # Duplicate request(a bizId can only be requested once)
522
+ 'TRANSFER_002': InsufficientFunds, # Insufficient account balance
523
+ 'TRANSFER_003': BadRequest, # User not registered
524
+ 'TRANSFER_004': PermissionDenied, # The currency is not allowed to be transferred
525
+ 'TRANSFER_005': PermissionDenied, # The user’s currency is not allowed to be transferred
526
+ 'TRANSFER_006': PermissionDenied, # Transfer prohibited
527
+ 'TRANSFER_007': RequestTimeout, # Request timed out
528
+ 'TRANSFER_008': BadRequest, # Transferring to a leveraged account is abnormal
529
+ 'TRANSFER_009': BadRequest, # Departing from a leveraged account is abnormal
530
+ 'TRANSFER_010': PermissionDenied, # Leverage cleared, transfer prohibited
531
+ 'TRANSFER_011': PermissionDenied, # Leverage with borrowing, transfer prohibited
532
+ 'TRANSFER_012': PermissionDenied, # Currency transfer prohibited
533
+ 'symbol_not_support_trading_via_api': BadSymbol, # {"returnCode":1,"msgInfo":"failure","error":{"code":"symbol_not_support_trading_via_api","msg":"The symbol does not support trading via API"},"result":null}
534
+ 'open_order_min_nominal_value_limit': InvalidOrder, # {"returnCode":1,"msgInfo":"failure","error":{"code":"open_order_min_nominal_value_limit","msg":"Exceeds the minimum notional value of a single order"},"result":null}
535
+ },
536
+ 'broad': {
537
+ 'The symbol does not support trading via API': BadSymbol, # {"returnCode":1,"msgInfo":"failure","error":{"code":"symbol_not_support_trading_via_api","msg":"The symbol does not support trading via API"},"result":null}
538
+ 'Exceeds the minimum notional value of a single order': InvalidOrder, # {"returnCode":1,"msgInfo":"failure","error":{"code":"open_order_min_nominal_value_limit","msg":"Exceeds the minimum notional value of a single order"},"result":null}
539
+ },
540
+ },
541
+ 'timeframes': {
542
+ '1m': '1m',
543
+ '5m': '5m',
544
+ '15m': '15m',
545
+ '30m': '30m',
546
+ '1h': '1h', # spot only
547
+ '2h': '2h', # spot only
548
+ '4h': '4h',
549
+ '6h': '6h', # spot only
550
+ '8h': '8h', # spot only
551
+ '1d': '1d',
552
+ '3d': '3d', # spot only
553
+ '1w': '1w',
554
+ '1M': '1M', # spot only
555
+ },
556
+ 'commonCurrencies': {},
557
+ 'options': {
558
+ 'adjustForTimeDifference': False,
559
+ 'timeDifference': 0,
560
+ 'accountsById': {
561
+ 'spot': 'SPOT',
562
+ 'leverage': 'LEVER',
563
+ 'finance': 'FINANCE',
564
+ 'swap': 'FUTURES_U',
565
+ 'future': 'FUTURES_U',
566
+ 'linear': 'FUTURES_U',
567
+ 'inverse': 'FUTURES_C',
568
+ },
569
+ 'networks': {
570
+ 'ERC20': 'Ethereum',
571
+ 'TRC20': 'Tron',
572
+ 'BEP20': 'BNB Smart Chain',
573
+ 'BEP2': 'BNB-BEP2',
574
+ 'ETH': 'Ethereum',
575
+ 'TRON': 'Tron',
576
+ 'BNB': 'BNB Smart Chain',
577
+ 'AVAX': 'AVAX C-Chain',
578
+ 'GAL': 'GAL(FT)',
579
+ 'ALEO': 'ALEO(IOU)',
580
+ 'BTC': 'Bitcoin',
581
+ 'XT': 'XT Smart Chain',
582
+ 'ETC': 'Ethereum Classic',
583
+ 'MATIC': 'Polygon',
584
+ 'LTC': 'Litecoin',
585
+ 'BTS': 'BitShares',
586
+ 'XRP': 'Ripple',
587
+ 'XLM': 'Stellar Network',
588
+ 'ADA': 'Cardano',
589
+ 'XWC': 'XWC-XWC',
590
+ 'DOGE': 'dogecoin',
591
+ 'DCR': 'Decred',
592
+ 'SC': 'Siacoin',
593
+ 'XTZ': 'Tezos',
594
+ 'ZEC': 'Zcash',
595
+ 'XMR': 'Monero',
596
+ 'LSK': 'Lisk',
597
+ 'ATOM': 'Cosmos',
598
+ 'ONT': 'Ontology',
599
+ 'ALGO': 'Algorand',
600
+ 'SOL': 'SOL-SOL',
601
+ 'DOT': 'Polkadot',
602
+ 'ZEN': 'Horizen',
603
+ 'FIL': 'Filecoin',
604
+ 'CHZ': 'chz',
605
+ 'ICP': 'Internet Computer',
606
+ 'KSM': 'Kusama',
607
+ 'LUNA': 'Terra',
608
+ 'THETA': 'Theta Token',
609
+ 'FTM': 'Fantom',
610
+ 'VET': 'VeChain',
611
+ 'NEAR': 'NEAR Protocol',
612
+ 'ONE': 'Harmony',
613
+ 'KLAY': 'Klaytn',
614
+ 'AR': 'Arweave',
615
+ 'CELT': 'OKT',
616
+ 'EGLD': 'Elrond eGold',
617
+ 'CRO': 'CRO-CRONOS',
618
+ 'BCH': 'Bitcoin Cash',
619
+ 'GLMR': 'Moonbeam',
620
+ 'LOOP': 'LOOP-LRC',
621
+ 'REI': 'REI Network',
622
+ 'ASTR': 'Astar Network',
623
+ 'OP': 'OPT',
624
+ 'MMT': 'MMT-MMT',
625
+ 'TBC': 'TBC-TBC',
626
+ 'OMAX': 'OMAX-OMAX CHAIN',
627
+ 'GMMT': 'GMMT chain',
628
+ 'ZIL': 'Zilliqa',
629
+ },
630
+ 'networksById': {
631
+ 'Ethereum': 'ERC20',
632
+ 'Tron': 'TRC20',
633
+ 'BNB Smart Chain': 'BEP20',
634
+ 'BNB-BEP2': 'BEP2',
635
+ 'Bitcoin': 'BTC',
636
+ 'XT Smart Chain': 'XT',
637
+ 'Ethereum Classic': 'ETC',
638
+ 'Polygon': 'MATIC',
639
+ 'Litecoin': 'LTC',
640
+ 'BitShares': 'BTS',
641
+ 'Ripple': 'XRP',
642
+ 'Stellar Network': 'XLM',
643
+ 'Cardano': 'ADA',
644
+ 'XWC-XWC': 'XWC',
645
+ 'dogecoin': 'DOGE',
646
+ 'Decred': 'DCR',
647
+ 'Siacoin': 'SC',
648
+ 'Tezos': 'XTZ',
649
+ 'Zcash': 'ZEC',
650
+ 'Monero': 'XMR',
651
+ 'Lisk': 'LSK',
652
+ 'Cosmos': 'ATOM',
653
+ 'Ontology': 'ONT',
654
+ 'Algorand': 'ALGO',
655
+ 'SOL-SOL': 'SOL',
656
+ 'Polkadot': 'DOT',
657
+ 'Horizen': 'ZEN',
658
+ 'Filecoin': 'FIL',
659
+ 'chz': 'CHZ',
660
+ 'Internet Computer': 'ICP',
661
+ 'Kusama': 'KSM',
662
+ 'Terra': 'LUNA',
663
+ 'Theta Token': 'THETA',
664
+ 'Fantom': 'FTM',
665
+ 'VeChain': 'VET',
666
+ 'AVAX C-Chain': 'AVAX',
667
+ 'NEAR Protocol': 'NEAR',
668
+ 'Harmony': 'ONE',
669
+ 'Klaytn': 'KLAY',
670
+ 'Arweave': 'AR',
671
+ 'OKT': 'CELT',
672
+ 'Elrond eGold': 'EGLD',
673
+ 'CRO-CRONOS': 'CRO',
674
+ 'Bitcoin Cash': 'BCH',
675
+ 'Moonbeam': 'GLMR',
676
+ 'LOOP-LRC': 'LOOP',
677
+ 'REI Network': 'REI',
678
+ 'Astar Network': 'ASTR',
679
+ 'GAL(FT)': 'GAL',
680
+ 'ALEO(IOU)': 'ALEO',
681
+ 'OPT': 'OP',
682
+ 'MMT-MMT': 'MMT',
683
+ 'TBC-TBC': 'TBC',
684
+ 'OMAX-OMAX CHAIN': 'OMAX',
685
+ 'GMMT chain': 'GMMT',
686
+ 'Zilliqa': 'ZIL',
687
+ },
688
+ 'createMarketBuyOrderRequiresPrice': True,
689
+ 'recvWindow': '5000', # in milliseconds, spot only
690
+ },
691
+ })
692
+
693
+ def nonce(self):
694
+ return self.milliseconds() - self.options['timeDifference']
695
+
696
+ async def fetch_time(self, params={}):
697
+ """
698
+ fetches the current integer timestamp in milliseconds from the xt server
699
+
700
+ https://doc.xt.com/#market1serverInfo
701
+
702
+ :param dict params: extra parameters specific to the xt api endpoint
703
+ :returns int: the current integer timestamp in milliseconds from the xt server
704
+ """
705
+ response = await self.publicSpotGetTime(params)
706
+ #
707
+ # {
708
+ # "rc": 0,
709
+ # "mc": "SUCCESS",
710
+ # "ma": [],
711
+ # "result": {
712
+ # "serverTime": 1677823301643
713
+ # }
714
+ # }
715
+ #
716
+ data = self.safe_value(response, 'result')
717
+ return self.safe_integer(data, 'serverTime')
718
+
719
+ async def fetch_currencies(self, params={}) -> Currencies:
720
+ """
721
+ fetches all available currencies on an exchange
722
+
723
+ https://doc.xt.com/#deposit_withdrawalsupportedCurrenciesGet
724
+
725
+ :param dict params: extra parameters specific to the xt api endpoint
726
+ :returns dict: an associative dictionary of currencies
727
+ """
728
+ promisesRaw = [self.publicSpotGetWalletSupportCurrency(params), self.publicSpotGetCurrencies(params)]
729
+ chainsResponse, currenciesResponse = await asyncio.gather(*promisesRaw)
730
+ #
731
+ # currencies
732
+ #
733
+ # {
734
+ # "time": "1686626116145",
735
+ # "version": "5dbbb2f2527c22b2b2e3b47187ef13d1",
736
+ # "currencies": [
737
+ # {
738
+ # "id": "2",
739
+ # "currency": "btc",
740
+ # "fullName": "Bitcoin",
741
+ # "logo": "https://a.static-global.com/1/currency/btc.png",
742
+ # "cmcLink": "https://coinmarketcap.com/currencies/bitcoin/",
743
+ # "weight": "99999",
744
+ # "maxPrecision": "10",
745
+ # "depositStatus": "1",
746
+ # "withdrawStatus": "1",
747
+ # "convertEnabled": "1",
748
+ # "transferEnabled": "1",
749
+ # "isChainExist": "1",
750
+ # "plates": [152]
751
+ # },
752
+ # ],
753
+ # }
754
+ #
755
+ #
756
+ # chains
757
+ #
758
+ # {
759
+ # "rc": 0,
760
+ # "mc": "SUCCESS",
761
+ # "ma": [],
762
+ # "result": [
763
+ # {
764
+ # "currency": "btc",
765
+ # "supportChains": [
766
+ # {
767
+ # "chain": "Bitcoin",
768
+ # "depositEnabled": True,
769
+ # "withdrawEnabled": True,
770
+ # "withdrawFeeAmount": 0.0009,
771
+ # "withdrawMinAmount": 0.0005,
772
+ # "depositFeeRate": 0
773
+ # },
774
+ # ]
775
+ # },
776
+ # ]
777
+ # }
778
+ #
779
+ # note: individual network's full data is available on per-currency endpoint: https://www.xt.com/sapi/v4/balance/public/currency/11
780
+ #
781
+ chainsData = self.safe_value(chainsResponse, 'result', [])
782
+ currenciesResult = self.safe_value(currenciesResponse, 'result', [])
783
+ currenciesData = self.safe_value(currenciesResult, 'currencies', [])
784
+ chainsDataIndexed = self.index_by(chainsData, 'currency')
785
+ result = {}
786
+ for i in range(0, len(currenciesData)):
787
+ entry = currenciesData[i]
788
+ currencyId = self.safe_string(entry, 'currency')
789
+ code = self.safe_currency_code(currencyId)
790
+ minPrecision = self.parse_number(self.parse_precision(self.safe_string(entry, 'maxPrecision')))
791
+ networkEntry = self.safe_value(chainsDataIndexed, currencyId, {})
792
+ rawNetworks = self.safe_value(networkEntry, 'supportChains', [])
793
+ networks = {}
794
+ minWithdrawString = None
795
+ minWithdrawFeeString = None
796
+ active = False
797
+ deposit = False
798
+ withdraw = False
799
+ for j in range(0, len(rawNetworks)):
800
+ rawNetwork = rawNetworks[j]
801
+ networkId = self.safe_string(rawNetwork, 'chain')
802
+ network = self.network_id_to_code(networkId)
803
+ depositEnabled = self.safe_value(rawNetwork, 'depositEnabled')
804
+ deposit = depositEnabled if (depositEnabled) else deposit
805
+ withdrawEnabled = self.safe_value(rawNetwork, 'withdrawEnabled')
806
+ withdraw = withdrawEnabled if (withdrawEnabled) else withdraw
807
+ networkActive = depositEnabled and withdrawEnabled
808
+ active = networkActive if (networkActive) else active
809
+ withdrawFeeString = self.safe_string(rawNetwork, 'withdrawFeeAmount')
810
+ if withdrawFeeString is not None:
811
+ minWithdrawFeeString = withdrawFeeString if (minWithdrawFeeString is None) else Precise.string_min(withdrawFeeString, minWithdrawFeeString)
812
+ minNetworkWithdrawString = self.safe_string(rawNetwork, 'withdrawMinAmount')
813
+ if minNetworkWithdrawString is not None:
814
+ minWithdrawString = minNetworkWithdrawString if (minWithdrawString is None) else Precise.string_min(minNetworkWithdrawString, minWithdrawString)
815
+ networks[network] = {
816
+ 'info': rawNetwork,
817
+ 'id': networkId,
818
+ 'network': network,
819
+ 'name': None,
820
+ 'active': networkActive,
821
+ 'fee': self.parse_number(withdrawFeeString),
822
+ 'precision': minPrecision,
823
+ 'deposit': depositEnabled,
824
+ 'withdraw': withdrawEnabled,
825
+ 'limits': {
826
+ 'amount': {
827
+ 'min': None,
828
+ 'max': None,
829
+ },
830
+ 'withdraw': {
831
+ 'min': self.parse_number(minNetworkWithdrawString),
832
+ 'max': None,
833
+ },
834
+ 'deposit': {
835
+ 'min': None,
836
+ 'max': None,
837
+ },
838
+ },
839
+ }
840
+ result[code] = {
841
+ 'info': entry,
842
+ 'id': currencyId,
843
+ 'code': code,
844
+ 'name': self.safe_string(entry, 'fullName'),
845
+ 'active': active,
846
+ 'fee': self.parse_number(minWithdrawFeeString),
847
+ 'precision': minPrecision,
848
+ 'deposit': deposit,
849
+ 'withdraw': withdraw,
850
+ 'networks': networks,
851
+ 'limits': {
852
+ 'amount': {
853
+ 'min': None,
854
+ 'max': None,
855
+ },
856
+ 'withdraw': {
857
+ 'min': self.parse_number(minWithdrawString),
858
+ 'max': None,
859
+ },
860
+ 'deposit': {
861
+ 'min': None,
862
+ 'max': None,
863
+ },
864
+ },
865
+ }
866
+ return result
867
+
868
+ async def fetch_markets(self, params={}) -> List[Market]:
869
+ """
870
+ retrieves data on all markets for xt
871
+
872
+ https://doc.xt.com/#market2symbol
873
+ https://doc.xt.com/#futures_quotesgetSymbols
874
+
875
+ :param dict params: extra parameters specific to the xt api endpoint
876
+ :returns dict[]: an array of objects representing market data
877
+ """
878
+ if self.options['adjustForTimeDifference']:
879
+ await self.load_time_difference()
880
+ promisesUnresolved = [
881
+ self.fetch_spot_markets(params),
882
+ self.fetch_swap_and_future_markets(params),
883
+ ]
884
+ promises = await asyncio.gather(*promisesUnresolved)
885
+ spotMarkets = promises[0]
886
+ swapAndFutureMarkets = promises[1]
887
+ return self.array_concat(spotMarkets, swapAndFutureMarkets)
888
+
889
+ async def fetch_spot_markets(self, params={}):
890
+ response = await self.publicSpotGetSymbol(params)
891
+ #
892
+ # {
893
+ # "rc": 0,
894
+ # "mc": "SUCCESS",
895
+ # "ma": [],
896
+ # "result": {
897
+ # "time": 1677881368812,
898
+ # "version": "abb101d1543e54bee40687b135411ba0",
899
+ # "symbols": [
900
+ # {
901
+ # "id": 640,
902
+ # "symbol": "xt_usdt",
903
+ # "state": "ONLINE",
904
+ # "stateTime": 1554048000000,
905
+ # "tradingEnabled": True,
906
+ # "openapiEnabled": True,
907
+ # "nextStateTime": null,
908
+ # "nextState": null,
909
+ # "depthMergePrecision": 5,
910
+ # "baseCurrency": "xt",
911
+ # "baseCurrencyPrecision": 8,
912
+ # "baseCurrencyId": 128,
913
+ # "quoteCurrency": "usdt",
914
+ # "quoteCurrencyPrecision": 8,
915
+ # "quoteCurrencyId": 11,
916
+ # "pricePrecision": 4,
917
+ # "quantityPrecision": 2,
918
+ # "orderTypes": ["LIMIT","MARKET"],
919
+ # "timeInForces": ["GTC","IOC"],
920
+ # "displayWeight": 10002,
921
+ # "displayLevel": "FULL",
922
+ # "plates": [],
923
+ # "filters":[
924
+ # {
925
+ # "filter": "QUOTE_QTY",
926
+ # "min": "1"
927
+ # },
928
+ # {
929
+ # "filter": "PROTECTION_LIMIT",
930
+ # "buyMaxDeviation": "0.8",
931
+ # "sellMaxDeviation": "4"
932
+ # },
933
+ # {
934
+ # "filter": "PROTECTION_MARKET",
935
+ # "maxDeviation": "0.02"
936
+ # }
937
+ # ]
938
+ # },
939
+ # ]
940
+ # }
941
+ # }
942
+ #
943
+ data = self.safe_value(response, 'result', {})
944
+ symbols = self.safe_value(data, 'symbols', [])
945
+ return self.parse_markets(symbols)
946
+
947
+ async def fetch_swap_and_future_markets(self, params={}):
948
+ markets = await asyncio.gather(*[self.publicLinearGetFutureMarketV1PublicSymbolList(params), self.publicInverseGetFutureMarketV1PublicSymbolList(params)])
949
+ #
950
+ # {
951
+ # "returnCode": 0,
952
+ # "msgInfo": "success",
953
+ # "error": null,
954
+ # "result": [
955
+ # {
956
+ # "id": 52,
957
+ # "symbolGroupId": 71,
958
+ # "symbol": "xt_usdt",
959
+ # "pair": "xt_usdt",
960
+ # "contractType": "PERPETUAL",
961
+ # "productType": "perpetual",
962
+ # "predictEventType": null,
963
+ # "underlyingType": "U_BASED",
964
+ # "contractSize": "1",
965
+ # "tradeSwitch": True,
966
+ # "isDisplay": True,
967
+ # "isOpenApi": False,
968
+ # "state": 0,
969
+ # "initLeverage": 20,
970
+ # "initPositionType": "CROSSED",
971
+ # "baseCoin": "xt",
972
+ # "quoteCoin": "usdt",
973
+ # "baseCoinPrecision": 8,
974
+ # "baseCoinDisplayPrecision": 4,
975
+ # "quoteCoinPrecision": 8,
976
+ # "quoteCoinDisplayPrecision": 4,
977
+ # "quantityPrecision": 0,
978
+ # "pricePrecision": 4,
979
+ # "supportOrderType": "LIMIT,MARKET",
980
+ # "supportTimeInForce": "GTC,FOK,IOC,GTX",
981
+ # "supportEntrustType": "TAKE_PROFIT,STOP,TAKE_PROFIT_MARKET,STOP_MARKET,TRAILING_STOP_MARKET",
982
+ # "supportPositionType": "CROSSED,ISOLATED",
983
+ # "minQty": "1",
984
+ # "minNotional": "5",
985
+ # "maxNotional": "20000000",
986
+ # "multiplierDown": "0.1",
987
+ # "multiplierUp": "0.1",
988
+ # "maxOpenOrders": 200,
989
+ # "maxEntrusts": 200,
990
+ # "makerFee": "0.0004",
991
+ # "takerFee": "0.0006",
992
+ # "liquidationFee": "0.01",
993
+ # "marketTakeBound": "0.1",
994
+ # "depthPrecisionMerge": 5,
995
+ # "labels": ["HOT"],
996
+ # "onboardDate": 1657101601000,
997
+ # "enName": "XTUSDT ",
998
+ # "cnName": "XTUSDT",
999
+ # "minStepPrice": "0.0001",
1000
+ # "minPrice": null,
1001
+ # "maxPrice": null,
1002
+ # "deliveryDate": 1669879634000,
1003
+ # "deliveryPrice": null,
1004
+ # "deliveryCompletion": False,
1005
+ # "cnDesc": null,
1006
+ # "enDesc": null
1007
+ # },
1008
+ # ]
1009
+ # }
1010
+ #
1011
+ swapAndFutureMarkets = self.array_concat(self.safe_value(markets[0], 'result', []), self.safe_value(markets[1], 'result', []))
1012
+ return self.parse_markets(swapAndFutureMarkets)
1013
+
1014
+ def parse_markets(self, markets):
1015
+ result = []
1016
+ for i in range(0, len(markets)):
1017
+ result.append(self.parse_market(markets[i]))
1018
+ return result
1019
+
1020
+ def parse_market(self, market: dict) -> Market:
1021
+ #
1022
+ # spot
1023
+ #
1024
+ # {
1025
+ # "id": 640,
1026
+ # "symbol": "xt_usdt",
1027
+ # "state": "ONLINE",
1028
+ # "stateTime": 1554048000000,
1029
+ # "tradingEnabled": True,
1030
+ # "openapiEnabled": True,
1031
+ # "nextStateTime": null,
1032
+ # "nextState": null,
1033
+ # "depthMergePrecision": 5,
1034
+ # "baseCurrency": "xt",
1035
+ # "baseCurrencyPrecision": 8,
1036
+ # "baseCurrencyId": 128,
1037
+ # "quoteCurrency": "usdt",
1038
+ # "quoteCurrencyPrecision": 8,
1039
+ # "quoteCurrencyId": 11,
1040
+ # "pricePrecision": 4,
1041
+ # "quantityPrecision": 2,
1042
+ # "orderTypes": ["LIMIT","MARKET"],
1043
+ # "timeInForces": ["GTC","IOC"],
1044
+ # "displayWeight": 10002,
1045
+ # "displayLevel": "FULL",
1046
+ # "plates": [],
1047
+ # "filters":[
1048
+ # {
1049
+ # "filter": "QUOTE_QTY",
1050
+ # "min": "1"
1051
+ # },
1052
+ # {
1053
+ # "filter": "PRICE",
1054
+ # "min": null,
1055
+ # "max": null,
1056
+ # "tickSize": null
1057
+ # },
1058
+ # {
1059
+ # "filter": "QUANTITY",
1060
+ # "min": null,
1061
+ # "max": null,
1062
+ # "tickSize": null
1063
+ # },
1064
+ # {
1065
+ # "filter": "PROTECTION_LIMIT",
1066
+ # "buyMaxDeviation": "0.8",
1067
+ # "sellMaxDeviation": "4"
1068
+ # },
1069
+ # {
1070
+ # "filter": "PROTECTION_MARKET",
1071
+ # "maxDeviation": "0.02"
1072
+ # },
1073
+ # {
1074
+ # "filter": "PROTECTION_ONLINE",
1075
+ # "durationSeconds": "300",
1076
+ # "maxPriceMultiple": "5"
1077
+ # },
1078
+ # ]
1079
+ # }
1080
+ #
1081
+ # swap and future
1082
+ #
1083
+ # {
1084
+ # "id": 52,
1085
+ # "symbolGroupId": 71,
1086
+ # "symbol": "xt_usdt",
1087
+ # "pair": "xt_usdt",
1088
+ # "contractType": "PERPETUAL",
1089
+ # "productType": "perpetual",
1090
+ # "predictEventType": null,
1091
+ # "underlyingType": "U_BASED",
1092
+ # "contractSize": "1",
1093
+ # "tradeSwitch": True,
1094
+ # "isDisplay": True,
1095
+ # "isOpenApi": False,
1096
+ # "state": 0,
1097
+ # "initLeverage": 20,
1098
+ # "initPositionType": "CROSSED",
1099
+ # "baseCoin": "xt",
1100
+ # "quoteCoin": "usdt",
1101
+ # "baseCoinPrecision": 8,
1102
+ # "baseCoinDisplayPrecision": 4,
1103
+ # "quoteCoinPrecision": 8,
1104
+ # "quoteCoinDisplayPrecision": 4,
1105
+ # "quantityPrecision": 0,
1106
+ # "pricePrecision": 4,
1107
+ # "supportOrderType": "LIMIT,MARKET",
1108
+ # "supportTimeInForce": "GTC,FOK,IOC,GTX",
1109
+ # "supportEntrustType": "TAKE_PROFIT,STOP,TAKE_PROFIT_MARKET,STOP_MARKET,TRAILING_STOP_MARKET",
1110
+ # "supportPositionType": "CROSSED,ISOLATED",
1111
+ # "minQty": "1",
1112
+ # "minNotional": "5",
1113
+ # "maxNotional": "20000000",
1114
+ # "multiplierDown": "0.1",
1115
+ # "multiplierUp": "0.1",
1116
+ # "maxOpenOrders": 200,
1117
+ # "maxEntrusts": 200,
1118
+ # "makerFee": "0.0004",
1119
+ # "takerFee": "0.0006",
1120
+ # "liquidationFee": "0.01",
1121
+ # "marketTakeBound": "0.1",
1122
+ # "depthPrecisionMerge": 5,
1123
+ # "labels": ["HOT"],
1124
+ # "onboardDate": 1657101601000,
1125
+ # "enName": "XTUSDT ",
1126
+ # "cnName": "XTUSDT",
1127
+ # "minStepPrice": "0.0001",
1128
+ # "minPrice": null,
1129
+ # "maxPrice": null,
1130
+ # "deliveryDate": 1669879634000,
1131
+ # "deliveryPrice": null,
1132
+ # "deliveryCompletion": False,
1133
+ # "cnDesc": null,
1134
+ # "enDesc": null
1135
+ # }
1136
+ #
1137
+ id = self.safe_string(market, 'symbol')
1138
+ baseId = self.safe_string_2(market, 'baseCurrency', 'baseCoin')
1139
+ quoteId = self.safe_string_2(market, 'quoteCurrency', 'quoteCoin')
1140
+ base = self.safe_currency_code(baseId)
1141
+ quote = self.safe_currency_code(quoteId)
1142
+ state = self.safe_string(market, 'state')
1143
+ symbol = base + '/' + quote
1144
+ filters = self.safe_value(market, 'filters', [])
1145
+ minAmount = None
1146
+ maxAmount = None
1147
+ minCost = None
1148
+ maxCost = None
1149
+ minPrice = None
1150
+ maxPrice = None
1151
+ amountPrecision = None
1152
+ for i in range(0, len(filters)):
1153
+ entry = filters[i]
1154
+ filter = self.safe_string(entry, 'filter')
1155
+ if filter == 'QUANTITY':
1156
+ minAmount = self.safe_number(entry, 'min')
1157
+ maxAmount = self.safe_number(entry, 'max')
1158
+ amountPrecision = self.safe_number(entry, 'tickSize')
1159
+ if filter == 'QUOTE_QTY':
1160
+ minCost = self.safe_number(entry, 'min')
1161
+ if filter == 'PRICE':
1162
+ minPrice = self.safe_number(entry, 'min')
1163
+ maxPrice = self.safe_number(entry, 'max')
1164
+ if amountPrecision is None:
1165
+ amountPrecision = self.parse_number(self.parse_precision(self.safe_string(market, 'quantityPrecision')))
1166
+ underlyingType = self.safe_string(market, 'underlyingType')
1167
+ linear = None
1168
+ inverse = None
1169
+ settleId = None
1170
+ settle = None
1171
+ expiry = None
1172
+ future = False
1173
+ swap = False
1174
+ contract = False
1175
+ spot = True
1176
+ type = 'spot'
1177
+ if underlyingType == 'U_BASED':
1178
+ symbol = symbol + ':' + quote
1179
+ settleId = baseId
1180
+ settle = quote
1181
+ linear = True
1182
+ inverse = False
1183
+ elif underlyingType == 'COIN_BASED':
1184
+ symbol = symbol + ':' + base
1185
+ settleId = baseId
1186
+ settle = base
1187
+ linear = False
1188
+ inverse = True
1189
+ if underlyingType is not None:
1190
+ expiry = self.safe_integer(market, 'deliveryDate')
1191
+ productType = self.safe_string(market, 'productType')
1192
+ if productType != 'perpetual':
1193
+ symbol = symbol + '-' + self.yymmdd(expiry)
1194
+ type = 'future'
1195
+ future = True
1196
+ else:
1197
+ type = 'swap'
1198
+ swap = True
1199
+ minAmount = self.safe_number(market, 'minQty')
1200
+ minCost = self.safe_number(market, 'minNotional')
1201
+ maxCost = self.safe_number(market, 'maxNotional')
1202
+ minPrice = self.safe_number(market, 'minPrice')
1203
+ maxPrice = self.safe_number(market, 'maxPrice')
1204
+ contract = True
1205
+ spot = False
1206
+ isActive = False
1207
+ if contract:
1208
+ isActive = self.safe_value(market, 'isOpenApi', False)
1209
+ else:
1210
+ if (state == 'ONLINE') and (self.safe_value(market, 'tradingEnabled')) and (self.safe_value(market, 'openapiEnabled')):
1211
+ isActive = True
1212
+ return self.safe_market_structure({
1213
+ 'id': id,
1214
+ 'symbol': symbol,
1215
+ 'base': base,
1216
+ 'quote': quote,
1217
+ 'settle': settle,
1218
+ 'baseId': baseId,
1219
+ 'quoteId': quoteId,
1220
+ 'settleId': settleId,
1221
+ 'type': type,
1222
+ 'spot': spot,
1223
+ 'margin': None,
1224
+ 'swap': swap,
1225
+ 'future': future,
1226
+ 'option': False,
1227
+ 'active': isActive,
1228
+ 'contract': contract,
1229
+ 'linear': linear,
1230
+ 'inverse': inverse,
1231
+ 'taker': self.safe_number(market, 'takerFee'),
1232
+ 'maker': self.safe_number(market, 'makerFee'),
1233
+ 'contractSize': self.safe_number(market, 'contractSize'),
1234
+ 'expiry': expiry,
1235
+ 'expiryDatetime': self.iso8601(expiry),
1236
+ 'strike': None,
1237
+ 'optionType': None,
1238
+ 'precision': {
1239
+ 'price': self.parse_number(self.parse_precision(self.safe_string(market, 'pricePrecision'))),
1240
+ 'amount': amountPrecision,
1241
+ 'base': self.parse_number(self.parse_precision(self.safe_string(market, 'baseCoinPrecision'))),
1242
+ 'quote': self.parse_number(self.parse_precision(self.safe_string(market, 'quoteCoinPrecision'))),
1243
+ },
1244
+ 'limits': {
1245
+ 'leverage': {
1246
+ 'min': self.parse_number('1'),
1247
+ 'max': None,
1248
+ },
1249
+ 'amount': {
1250
+ 'min': minAmount,
1251
+ 'max': maxAmount,
1252
+ },
1253
+ 'price': {
1254
+ 'min': minPrice,
1255
+ 'max': maxPrice,
1256
+ },
1257
+ 'cost': {
1258
+ 'min': minCost,
1259
+ 'max': maxCost,
1260
+ },
1261
+ },
1262
+ 'info': market,
1263
+ })
1264
+
1265
+ async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}):
1266
+ """
1267
+ fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1268
+
1269
+ https://doc.xt.com/#market4kline
1270
+ https://doc.xt.com/#futures_quotesgetKLine
1271
+
1272
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
1273
+ :param str timeframe: the length of time each candle represents
1274
+ :param int [since]: timestamp in ms of the earliest candle to fetch
1275
+ :param int [limit]: the maximum amount of candles to fetch
1276
+ :param dict params: extra parameters specific to the xt api endpoint
1277
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
1278
+ """
1279
+ await self.load_markets()
1280
+ market = self.market(symbol)
1281
+ request = {
1282
+ 'symbol': market['id'],
1283
+ 'interval': self.safe_string(self.timeframes, timeframe, timeframe),
1284
+ }
1285
+ if since is not None:
1286
+ request['startTime'] = since
1287
+ if limit is not None:
1288
+ request['limit'] = limit
1289
+ response = None
1290
+ if market['linear']:
1291
+ response = await self.publicLinearGetFutureMarketV1PublicQKline(self.extend(request, params))
1292
+ elif market['inverse']:
1293
+ response = await self.publicInverseGetFutureMarketV1PublicQKline(self.extend(request, params))
1294
+ else:
1295
+ response = await self.publicSpotGetKline(self.extend(request, params))
1296
+ #
1297
+ # spot
1298
+ #
1299
+ # {
1300
+ # "rc": 0,
1301
+ # "mc": "SUCCESS",
1302
+ # "ma": [],
1303
+ # "result": [
1304
+ # {
1305
+ # "t": 1678167720000,
1306
+ # "o": "22467.85",
1307
+ # "c": "22465.87",
1308
+ # "h": "22468.86",
1309
+ # "l": "22465.21",
1310
+ # "q": "1.316656",
1311
+ # "v": "29582.73018498"
1312
+ # },
1313
+ # ]
1314
+ # }
1315
+ #
1316
+ # swap and future
1317
+ #
1318
+ # {
1319
+ # "returnCode": 0,
1320
+ # "msgInfo": "success",
1321
+ # "error": null,
1322
+ # "result": [
1323
+ # {
1324
+ # "s": "btc_usdt",
1325
+ # "p": "btc_usdt",
1326
+ # "t": 1678168020000,
1327
+ # "o": "22450.0",
1328
+ # "c": "22441.5",
1329
+ # "h": "22450.0",
1330
+ # "l": "22441.5",
1331
+ # "a": "312931",
1332
+ # "v": "702461.58895"
1333
+ # },
1334
+ # ]
1335
+ # }
1336
+ #
1337
+ ohlcvs = self.safe_value(response, 'result', [])
1338
+ return self.parse_ohlcvs(ohlcvs, market, timeframe, since, limit)
1339
+
1340
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
1341
+ #
1342
+ # spot
1343
+ #
1344
+ # {
1345
+ # "t": 1678167720000,
1346
+ # "o": "22467.85",
1347
+ # "c": "22465.87",
1348
+ # "h": "22468.86",
1349
+ # "l": "22465.21",
1350
+ # "q": "1.316656",
1351
+ # "v": "29582.73018498"
1352
+ # }
1353
+ #
1354
+ # swap and future
1355
+ #
1356
+ # {
1357
+ # "s": "btc_usdt",
1358
+ # "p": "btc_usdt",
1359
+ # "t": 1678168020000,
1360
+ # "o": "22450.0",
1361
+ # "c": "22441.5",
1362
+ # "h": "22450.0",
1363
+ # "l": "22441.5",
1364
+ # "a": "312931",
1365
+ # "v": "702461.58895"
1366
+ # }
1367
+ #
1368
+ volumeIndex = 'v' if (market['inverse']) else 'a'
1369
+ return [
1370
+ self.safe_integer(ohlcv, 't'),
1371
+ self.safe_number(ohlcv, 'o'),
1372
+ self.safe_number(ohlcv, 'h'),
1373
+ self.safe_number(ohlcv, 'l'),
1374
+ self.safe_number(ohlcv, 'c'),
1375
+ self.safe_number_2(ohlcv, 'q', volumeIndex),
1376
+ ]
1377
+
1378
+ async def fetch_order_book(self, symbol: str, limit: Int = None, params={}):
1379
+ """
1380
+
1381
+ https://doc.xt.com/#market3depth
1382
+ https://doc.xt.com/#futures_quotesgetDepth
1383
+
1384
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1385
+ :param str symbol: unified market symbol to fetch the order book for
1386
+ :param int [limit]: the maximum amount of order book entries to return
1387
+ :param dict params: extra parameters specific to the xt api endpoint
1388
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/en/latest/manual.html#order-book-structure>` indexed by market symbols
1389
+ """
1390
+ await self.load_markets()
1391
+ market = self.market(symbol)
1392
+ request = {
1393
+ 'symbol': market['id'],
1394
+ }
1395
+ response = None
1396
+ if market['spot']:
1397
+ if limit is not None:
1398
+ request['limit'] = min(limit, 500)
1399
+ response = await self.publicSpotGetDepth(self.extend(request, params))
1400
+ else:
1401
+ if limit is not None:
1402
+ request['level'] = min(limit, 50)
1403
+ else:
1404
+ request['level'] = 50
1405
+ if market['linear']:
1406
+ response = await self.publicLinearGetFutureMarketV1PublicQDepth(self.extend(request, params))
1407
+ elif market['inverse']:
1408
+ response = await self.publicInverseGetFutureMarketV1PublicQDepth(self.extend(request, params))
1409
+ #
1410
+ # spot
1411
+ #
1412
+ # {
1413
+ # "rc": 0,
1414
+ # "mc": "SUCCESS",
1415
+ # "ma": [],
1416
+ # "result": {
1417
+ # "timestamp": 1678169975184,
1418
+ # "lastUpdateId": 1675333221812,
1419
+ # "bids": [
1420
+ # ["22444.51", "0.129887"],
1421
+ # ["22444.49", "0.114245"],
1422
+ # ["22444.30", "0.225956"]
1423
+ # ],
1424
+ # "asks": [
1425
+ # ["22446.19", "0.095330"],
1426
+ # ["22446.24", "0.224413"],
1427
+ # ["22446.28", "0.329095"]
1428
+ # ]
1429
+ # }
1430
+ # }
1431
+ #
1432
+ # swap and future
1433
+ #
1434
+ # {
1435
+ # "returnCode": 0,
1436
+ # "msgInfo": "success",
1437
+ # "error": null,
1438
+ # "result": {
1439
+ # "t": 1678170311005,
1440
+ # "s": "btc_usdt",
1441
+ # "u": 471694545627,
1442
+ # "b": [
1443
+ # ["22426", "198623"],
1444
+ # ["22423.5", "80295"],
1445
+ # ["22423", "163580"]
1446
+ # ],
1447
+ # "a": [
1448
+ # ["22427", "3417"],
1449
+ # ["22428.5", "43532"],
1450
+ # ["22429", "119"]
1451
+ # ]
1452
+ # }
1453
+ # }
1454
+ #
1455
+ orderBook = self.safe_value(response, 'result', {})
1456
+ timestamp = self.safe_integer_2(orderBook, 'timestamp', 't')
1457
+ if market['spot']:
1458
+ ob = self.parse_order_book(orderBook, symbol, timestamp)
1459
+ ob['nonce'] = self.safe_integer(orderBook, 'lastUpdateId')
1460
+ return ob
1461
+ swapOb = self.parse_order_book(orderBook, symbol, timestamp, 'b', 'a')
1462
+ swapOb['nonce'] = self.safe_integer_2(orderBook, 'u', 'lastUpdateId')
1463
+ return swapOb
1464
+
1465
+ async def fetch_ticker(self, symbol: str, params={}):
1466
+ """
1467
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1468
+
1469
+ https://doc.xt.com/#market10ticker24h
1470
+ https://doc.xt.com/#futures_quotesgetAggTicker
1471
+
1472
+ :param str symbol: unified market symbol to fetch the ticker for
1473
+ :param dict params: extra parameters specific to the xt api endpoint
1474
+ :returns dict: a `ticker structure <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
1475
+ """
1476
+ await self.load_markets()
1477
+ market = self.market(symbol)
1478
+ request = {
1479
+ 'symbol': market['id'],
1480
+ }
1481
+ response = None
1482
+ if market['linear']:
1483
+ response = await self.publicLinearGetFutureMarketV1PublicQAggTicker(self.extend(request, params))
1484
+ elif market['inverse']:
1485
+ response = await self.publicInverseGetFutureMarketV1PublicQAggTicker(self.extend(request, params))
1486
+ else:
1487
+ response = await self.publicSpotGetTicker24h(self.extend(request, params))
1488
+ #
1489
+ # spot
1490
+ #
1491
+ # {
1492
+ # "rc": 0,
1493
+ # "mc": "SUCCESS",
1494
+ # "ma": [],
1495
+ # "result": [
1496
+ # {
1497
+ # "s": "btc_usdt",
1498
+ # "t": 1678172693931,
1499
+ # "cv": "34.00",
1500
+ # "cr": "0.0015",
1501
+ # "o": "22398.05",
1502
+ # "l": "22323.72",
1503
+ # "h": "22600.50",
1504
+ # "c": "22432.05",
1505
+ # "q": "7962.256931",
1506
+ # "v": "178675209.47416856"
1507
+ # }
1508
+ # ]
1509
+ # }
1510
+ #
1511
+ # swap and future
1512
+ #
1513
+ # {
1514
+ # "returnCode": 0,
1515
+ # "msgInfo": "success",
1516
+ # "error": null,
1517
+ # "result": {
1518
+ # "t": 1678172848572,
1519
+ # "s": "btc_usdt",
1520
+ # "c": "22415.5",
1521
+ # "h": "22590.0",
1522
+ # "l": "22310.0",
1523
+ # "a": "623654031",
1524
+ # "v": "1399166074.31675",
1525
+ # "o": "22381.5",
1526
+ # "r": "0.0015",
1527
+ # "i": "22424.5",
1528
+ # "m": "22416.5",
1529
+ # "bp": "22415",
1530
+ # "ap": "22415.5"
1531
+ # }
1532
+ # }
1533
+ #
1534
+ ticker = self.safe_value(response, 'result')
1535
+ if market['spot']:
1536
+ return self.parse_ticker(ticker[0], market)
1537
+ return self.parse_ticker(ticker, market)
1538
+
1539
+ async def fetch_tickers(self, symbols: List[str] = None, params={}) -> Tickers:
1540
+ """
1541
+ fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
1542
+
1543
+ https://doc.xt.com/#market10ticker24h
1544
+ https://doc.xt.com/#futures_quotesgetAggTickers
1545
+
1546
+ :param str [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1547
+ :param dict params: extra parameters specific to the xt api endpoint
1548
+ :returns dict: an array of `ticker structures <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
1549
+ """
1550
+ await self.load_markets()
1551
+ market = None
1552
+ if symbols is not None:
1553
+ symbols = self.market_symbols(symbols)
1554
+ market = self.market(symbols[0])
1555
+ request = {}
1556
+ type = None
1557
+ subType = None
1558
+ response = None
1559
+ type, params = self.handle_market_type_and_params('fetchTickers', market, params)
1560
+ subType, params = self.handle_sub_type_and_params('fetchTickers', market, params)
1561
+ if subType == 'inverse':
1562
+ response = await self.publicInverseGetFutureMarketV1PublicQAggTickers(self.extend(request, params))
1563
+ elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
1564
+ response = await self.publicLinearGetFutureMarketV1PublicQAggTickers(self.extend(request, params))
1565
+ else:
1566
+ response = await self.publicSpotGetTicker24h(self.extend(request, params))
1567
+ #
1568
+ # spot
1569
+ #
1570
+ # {
1571
+ # "rc": 0,
1572
+ # "mc": "SUCCESS",
1573
+ # "ma": [],
1574
+ # "result": [
1575
+ # {
1576
+ # "s": "btc_usdt",
1577
+ # "t": 1678172693931,
1578
+ # "cv": "34.00",
1579
+ # "cr": "0.0015",
1580
+ # "o": "22398.05",
1581
+ # "l": "22323.72",
1582
+ # "h": "22600.50",
1583
+ # "c": "22432.05",
1584
+ # "q": "7962.256931",
1585
+ # "v": "178675209.47416856"
1586
+ # }
1587
+ # ]
1588
+ # }
1589
+ #
1590
+ # swap and future
1591
+ #
1592
+ # {
1593
+ # "returnCode": 0,
1594
+ # "msgInfo": "success",
1595
+ # "error": null,
1596
+ # "result": [
1597
+ # {
1598
+ # "t": 1680738775108,
1599
+ # "s": "badger_usdt",
1600
+ # "c": "2.7176",
1601
+ # "h": "2.7917",
1602
+ # "l": "2.6818",
1603
+ # "a": "88332",
1604
+ # "v": "242286.3520",
1605
+ # "o": "2.7422",
1606
+ # "r": "-0.0089",
1607
+ # "i": "2.7155",
1608
+ # "m": "2.7161",
1609
+ # "bp": "2.7152",
1610
+ # "ap": "2.7176"
1611
+ # },
1612
+ # ]
1613
+ # }
1614
+ #
1615
+ tickers = self.safe_value(response, 'result', [])
1616
+ result = {}
1617
+ for i in range(0, len(tickers)):
1618
+ ticker = self.parse_ticker(tickers[i], market)
1619
+ symbol = ticker['symbol']
1620
+ result[symbol] = ticker
1621
+ return self.filter_by_array(result, 'symbol', symbols)
1622
+
1623
+ async def fetch_bids_asks(self, symbols: List[str] = None, params={}):
1624
+ """
1625
+ fetches the bid and ask price and volume for multiple markets
1626
+
1627
+ https://doc.xt.com/#market9tickerBook
1628
+
1629
+ :param str [symbols]: unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
1630
+ :param dict params: extra parameters specific to the xt api endpoint
1631
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
1632
+ """
1633
+ await self.load_markets()
1634
+ symbols = self.market_symbols(symbols)
1635
+ request = {}
1636
+ market = None
1637
+ if symbols is not None:
1638
+ market = self.market(symbols[0])
1639
+ subType = None
1640
+ subType, params = self.handle_sub_type_and_params('fetchBidsAsks', market, params)
1641
+ if subType is not None:
1642
+ raise NotSupported(self.id + ' fetchBidsAsks() is not available for swap and future markets, only spot markets are supported')
1643
+ response = await self.publicSpotGetTickerBook(self.extend(request, params))
1644
+ #
1645
+ # {
1646
+ # "rc": 0,
1647
+ # "mc": "SUCCESS",
1648
+ # "ma": [],
1649
+ # "result": [
1650
+ # {
1651
+ # "s": "kas_usdt",
1652
+ # "t": 1679539891853,
1653
+ # "ap": "0.016298",
1654
+ # "aq": "5119.09",
1655
+ # "bp": "0.016290",
1656
+ # "bq": "135.37"
1657
+ # },
1658
+ # ]
1659
+ # }
1660
+ #
1661
+ tickers = self.safe_value(response, 'result', [])
1662
+ return self.parse_tickers(tickers, symbols)
1663
+
1664
+ def parse_ticker(self, ticker, market=None):
1665
+ #
1666
+ # spot: fetchTicker, fetchTickers
1667
+ #
1668
+ # {
1669
+ # "s": "btc_usdt",
1670
+ # "t": 1678172693931,
1671
+ # "cv": "34.00",
1672
+ # "cr": "0.0015",
1673
+ # "o": "22398.05",
1674
+ # "l": "22323.72",
1675
+ # "h": "22600.50",
1676
+ # "c": "22432.05",
1677
+ # "q": "7962.256931",
1678
+ # "v": "178675209.47416856"
1679
+ # }
1680
+ #
1681
+ # swap and future: fetchTicker, fetchTickers
1682
+ #
1683
+ # {
1684
+ # "t": 1678172848572,
1685
+ # "s": "btc_usdt",
1686
+ # "c": "22415.5",
1687
+ # "h": "22590.0",
1688
+ # "l": "22310.0",
1689
+ # "a": "623654031",
1690
+ # "v": "1399166074.31675",
1691
+ # "o": "22381.5",
1692
+ # "r": "0.0015",
1693
+ # "i": "22424.5",
1694
+ # "m": "22416.5",
1695
+ # "bp": "22415",
1696
+ # "ap": "22415.5"
1697
+ # }
1698
+ #
1699
+ # fetchBidsAsks
1700
+ #
1701
+ # {
1702
+ # "s": "kas_usdt",
1703
+ # "t": 1679539891853,
1704
+ # "ap": "0.016298",
1705
+ # "aq": "5119.09",
1706
+ # "bp": "0.016290",
1707
+ # "bq": "135.37"
1708
+ # }
1709
+ #
1710
+ marketId = self.safe_string(ticker, 's')
1711
+ marketType = market['type'] if (market is not None) else None
1712
+ hasSpotKeys = ('cv' in ticker) or ('aq' in ticker)
1713
+ if marketType is None:
1714
+ marketType = 'spot' if hasSpotKeys else 'contract'
1715
+ market = self.safe_market(marketId, market, '_', marketType)
1716
+ symbol = market['symbol']
1717
+ timestamp = self.safe_integer(ticker, 't')
1718
+ percentage = self.safe_string_2(ticker, 'cr', 'r')
1719
+ if percentage is not None:
1720
+ percentage = Precise.string_mul(percentage, '100')
1721
+ return self.safe_ticker({
1722
+ 'symbol': symbol,
1723
+ 'timestamp': timestamp,
1724
+ 'datetime': self.iso8601(timestamp),
1725
+ 'high': self.safe_number(ticker, 'h'),
1726
+ 'low': self.safe_number(ticker, 'l'),
1727
+ 'bid': self.safe_number(ticker, 'bp'),
1728
+ 'bidVolume': self.safe_number(ticker, 'bq'),
1729
+ 'ask': self.safe_number(ticker, 'ap'),
1730
+ 'askVolume': self.safe_number(ticker, 'aq'),
1731
+ 'vwap': None,
1732
+ 'open': self.safe_string(ticker, 'o'),
1733
+ 'close': self.safe_string(ticker, 'c'),
1734
+ 'last': self.safe_string(ticker, 'c'),
1735
+ 'previousClose': None,
1736
+ 'change': self.safe_number(ticker, 'cv'),
1737
+ 'percentage': self.parse_number(percentage),
1738
+ 'average': None,
1739
+ 'baseVolume': None,
1740
+ 'quoteVolume': self.safe_number_2(ticker, 'a', 'v'),
1741
+ 'info': ticker,
1742
+ }, market)
1743
+
1744
+ async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}):
1745
+ """
1746
+ get the list of most recent trades for a particular symbol
1747
+
1748
+ https://doc.xt.com/#market5tradeRecent
1749
+ https://doc.xt.com/#futures_quotesgetDeal
1750
+
1751
+ :param str symbol: unified market symbol to fetch trades for
1752
+ :param int [since]: timestamp in ms of the earliest trade to fetch
1753
+ :param int [limit]: the maximum amount of trades to fetch
1754
+ :param dict params: extra parameters specific to the xt api endpoint
1755
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
1756
+ """
1757
+ await self.load_markets()
1758
+ market = self.market(symbol)
1759
+ request = {
1760
+ 'symbol': market['id'],
1761
+ }
1762
+ response = None
1763
+ if market['spot']:
1764
+ if limit is not None:
1765
+ request['limit'] = limit
1766
+ response = await self.publicSpotGetTradeRecent(self.extend(request, params))
1767
+ else:
1768
+ if limit is not None:
1769
+ request['num'] = limit
1770
+ if market['linear']:
1771
+ response = await self.publicLinearGetFutureMarketV1PublicQDeal(self.extend(request, params))
1772
+ elif market['inverse']:
1773
+ response = await self.publicInverseGetFutureMarketV1PublicQDeal(self.extend(request, params))
1774
+ #
1775
+ # spot
1776
+ #
1777
+ # {
1778
+ # "rc": 0,
1779
+ # "mc": "SUCCESS",
1780
+ # "ma": [],
1781
+ # "result": [
1782
+ # {
1783
+ # "i": 203530723141917063,
1784
+ # "t": 1678227505815,
1785
+ # "p": "22038.81",
1786
+ # "q": "0.000978",
1787
+ # "v": "21.55395618",
1788
+ # "b": True
1789
+ # },
1790
+ # ]
1791
+ # }
1792
+ #
1793
+ # swap and future
1794
+ #
1795
+ # {
1796
+ # "returnCode": 0,
1797
+ # "msgInfo": "success",
1798
+ # "error": null,
1799
+ # "result": [
1800
+ # {
1801
+ # "t": 1678227683897,
1802
+ # "s": "btc_usdt",
1803
+ # "p": "22031",
1804
+ # "a": "1067",
1805
+ # "m": "BID"
1806
+ # },
1807
+ # ]
1808
+ # }
1809
+ #
1810
+ trades = self.safe_value(response, 'result', [])
1811
+ return self.parse_trades(trades, market)
1812
+
1813
+ async def fetch_my_trades(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
1814
+ """
1815
+ fetch all trades made by the user
1816
+
1817
+ https://doc.xt.com/#tradetradeGet
1818
+ https://doc.xt.com/#futures_ordergetTrades
1819
+
1820
+ :param str [symbol]: unified market symbol to fetch trades for
1821
+ :param int [since]: timestamp in ms of the earliest trade to fetch
1822
+ :param int [limit]: the maximum amount of trades to fetch
1823
+ :param dict params: extra parameters specific to the xt api endpoint
1824
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
1825
+ """
1826
+ await self.load_markets()
1827
+ request = {}
1828
+ market = None
1829
+ if symbol is not None:
1830
+ market = self.market(symbol)
1831
+ request['symbol'] = market['id']
1832
+ if since is not None:
1833
+ request['startTime'] = since
1834
+ type = None
1835
+ subType = None
1836
+ response = None
1837
+ type, params = self.handle_market_type_and_params('fetchMyTrades', market, params)
1838
+ subType, params = self.handle_sub_type_and_params('fetchMyTrades', market, params)
1839
+ if (subType is not None) or (type == 'swap') or (type == 'future'):
1840
+ if limit is not None:
1841
+ request['size'] = limit
1842
+ if subType == 'inverse':
1843
+ response = await self.privateInverseGetFutureTradeV1OrderTradeList(self.extend(request, params))
1844
+ else:
1845
+ response = await self.privateLinearGetFutureTradeV1OrderTradeList(self.extend(request, params))
1846
+ else:
1847
+ marginMode = None
1848
+ marginMode, params = self.handle_margin_mode_and_params('fetchMyTrades', params)
1849
+ marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
1850
+ request['bizType'] = marginOrSpotRequest
1851
+ if limit is not None:
1852
+ request['limit'] = limit
1853
+ response = await self.privateSpotGetTrade(self.extend(request, params))
1854
+ #
1855
+ # spot and margin
1856
+ #
1857
+ # {
1858
+ # "rc": 0,
1859
+ # "mc": "SUCCESS",
1860
+ # "ma": [],
1861
+ # "result": {
1862
+ # "hasPrev": False,
1863
+ # "hasNext": False,
1864
+ # "items": [
1865
+ # {
1866
+ # "symbol": "btc_usdt",
1867
+ # "tradeId": "206906233569974658",
1868
+ # "orderId": "206906233178463488",
1869
+ # "orderSide": "SELL",
1870
+ # "orderType": "MARKET",
1871
+ # "bizType": "SPOT",
1872
+ # "time": 1679032290215,
1873
+ # "price": "25703.46",
1874
+ # "quantity": "0.000099",
1875
+ # "quoteQty": "2.54464254",
1876
+ # "baseCurrency": "btc",
1877
+ # "quoteCurrency": "usdt",
1878
+ # "fee": "0.00508929",
1879
+ # "feeCurrency": "usdt",
1880
+ # "takerMaker": "TAKER"
1881
+ # },
1882
+ # ]
1883
+ # }
1884
+ # }
1885
+ #
1886
+ # swap and future
1887
+ #
1888
+ # {
1889
+ # "returnCode": 0,
1890
+ # "msgInfo": "success",
1891
+ # "error": null,
1892
+ # "result": {
1893
+ # "page": 1,
1894
+ # "ps": 10,
1895
+ # "total": 2,
1896
+ # "items": [
1897
+ # {
1898
+ # "orderId": "207260566170987200",
1899
+ # "execId": "207260566790603265",
1900
+ # "symbol": "btc_usdt",
1901
+ # "quantity": "13",
1902
+ # "price": "27368",
1903
+ # "fee": "0.02134704",
1904
+ # "feeCoin": "usdt",
1905
+ # "timestamp": 1679116769838,
1906
+ # "takerMaker": "TAKER"
1907
+ # },
1908
+ # ]
1909
+ # }
1910
+ # }
1911
+ #
1912
+ data = self.safe_value(response, 'result', {})
1913
+ trades = self.safe_value(data, 'items', [])
1914
+ return self.parse_trades(trades, market, since, limit)
1915
+
1916
+ def parse_trade(self, trade, market=None):
1917
+ #
1918
+ # spot: fetchTrades
1919
+ #
1920
+ # {
1921
+ # "i": 203530723141917063,
1922
+ # "t": 1678227505815,
1923
+ # "p": "22038.81",
1924
+ # "q": "0.000978",
1925
+ # "v": "21.55395618",
1926
+ # "b": True
1927
+ # }
1928
+ #
1929
+ # spot: watchTrades
1930
+ #
1931
+ # {
1932
+ # s: 'btc_usdt',
1933
+ # i: '228825383103928709',
1934
+ # t: 1684258222702,
1935
+ # p: '27003.65',
1936
+ # q: '0.000796',
1937
+ # b: True
1938
+ # }
1939
+ #
1940
+ # spot: watchMyTrades
1941
+ #
1942
+ # {
1943
+ # "s": "btc_usdt", # symbol
1944
+ # "t": 1656043204763, # time
1945
+ # "i": "6316559590087251233", # tradeId
1946
+ # "oi": "6216559590087220004", # orderId
1947
+ # "p": "30000", # trade price
1948
+ # "q": "3", # qty quantity
1949
+ # "v": "90000" # volume trade amount
1950
+ # }
1951
+ #
1952
+ # swap and future: fetchTrades
1953
+ #
1954
+ # {
1955
+ # "t": 1678227683897,
1956
+ # "s": "btc_usdt",
1957
+ # "p": "22031",
1958
+ # "a": "1067",
1959
+ # "m": "BID"
1960
+ # }
1961
+ #
1962
+ # spot: fetchMyTrades
1963
+ #
1964
+ # {
1965
+ # "symbol": "btc_usdt",
1966
+ # "tradeId": "206906233569974658",
1967
+ # "orderId": "206906233178463488",
1968
+ # "orderSide": "SELL",
1969
+ # "orderType": "MARKET",
1970
+ # "bizType": "SPOT",
1971
+ # "time": 1679032290215,
1972
+ # "price": "25703.46",
1973
+ # "quantity": "0.000099",
1974
+ # "quoteQty": "2.54464254",
1975
+ # "baseCurrency": "btc",
1976
+ # "quoteCurrency": "usdt",
1977
+ # "fee": "0.00508929",
1978
+ # "feeCurrency": "usdt",
1979
+ # "takerMaker": "TAKER"
1980
+ # }
1981
+ #
1982
+ # swap and future: fetchMyTrades
1983
+ #
1984
+ # {
1985
+ # "orderId": "207260566170987200",
1986
+ # "execId": "207260566790603265",
1987
+ # "symbol": "btc_usdt",
1988
+ # "quantity": "13",
1989
+ # "price": "27368",
1990
+ # "fee": "0.02134704",
1991
+ # "feeCoin": "usdt",
1992
+ # "timestamp": 1679116769838,
1993
+ # "takerMaker": "TAKER"
1994
+ # }
1995
+ #
1996
+ # contract watchMyTrades
1997
+ #
1998
+ # {
1999
+ # "symbol": 'btc_usdt',
2000
+ # "orderSide": 'SELL',
2001
+ # "positionSide": 'LONG',
2002
+ # "orderId": '231485367663419328',
2003
+ # "price": '27152.7',
2004
+ # "quantity": '33',
2005
+ # "marginUnfrozen": '2.85318000',
2006
+ # "timestamp": 1684892412565
2007
+ # }
2008
+ #
2009
+ # watchMyTrades(ws, swap)
2010
+ #
2011
+ # {
2012
+ # 'fee': '0.04080840',
2013
+ # 'isMaker': False,
2014
+ # 'marginUnfrozen': '0.75711984',
2015
+ # 'orderId': '376172779053188416',
2016
+ # 'orderSide': 'BUY',
2017
+ # 'positionSide': 'LONG',
2018
+ # 'price': '3400.70',
2019
+ # 'quantity': '2',
2020
+ # 'symbol': 'eth_usdt',
2021
+ # 'timestamp': 1719388579622
2022
+ # }
2023
+ #
2024
+ marketId = self.safe_string_2(trade, 's', 'symbol')
2025
+ marketType = market['type'] if (market is not None) else None
2026
+ hasSpotKeys = ('b' in trade) or ('bizType' in trade) or ('oi' in trade)
2027
+ if marketType is None:
2028
+ marketType = 'spot' if hasSpotKeys else 'contract'
2029
+ market = self.safe_market(marketId, market, '_', marketType)
2030
+ side = None
2031
+ takerOrMaker = None
2032
+ isBuyerMaker = self.safe_bool(trade, 'b')
2033
+ if isBuyerMaker is not None:
2034
+ side = 'sell' if isBuyerMaker else 'buy'
2035
+ takerOrMaker = 'taker' # public trades always taker
2036
+ else:
2037
+ takerMaker = self.safe_string_lower(trade, 'takerMaker')
2038
+ if takerMaker is not None:
2039
+ takerOrMaker = takerMaker
2040
+ else:
2041
+ isMaker = self.safe_bool(trade, 'isMaker')
2042
+ if isMaker is not None:
2043
+ takerOrMaker = 'maker' if isMaker else 'taker'
2044
+ orderSide = self.safe_string_lower(trade, 'orderSide')
2045
+ if orderSide is not None:
2046
+ side = orderSide
2047
+ else:
2048
+ bidOrAsk = self.safe_string(trade, 'm')
2049
+ if bidOrAsk is not None:
2050
+ side = 'buy' if (bidOrAsk == 'BID') else 'sell'
2051
+ timestamp = self.safe_integer_n(trade, ['t', 'time', 'timestamp'])
2052
+ quantity = self.safe_string_2(trade, 'q', 'quantity')
2053
+ amount = None
2054
+ if marketType == 'spot':
2055
+ amount = quantity
2056
+ else:
2057
+ if quantity is None:
2058
+ amount = Precise.string_mul(self.safe_string(trade, 'a'), self.number_to_string(market['contractSize']))
2059
+ else:
2060
+ amount = Precise.string_mul(quantity, self.number_to_string(market['contractSize']))
2061
+ return self.safe_trade({
2062
+ 'info': trade,
2063
+ 'id': self.safe_string_n(trade, ['i', 'tradeId', 'execId']),
2064
+ 'timestamp': timestamp,
2065
+ 'datetime': self.iso8601(timestamp),
2066
+ 'symbol': market['symbol'],
2067
+ 'order': self.safe_string_2(trade, 'orderId', 'oi'),
2068
+ 'type': self.safe_string_lower(trade, 'orderType'),
2069
+ 'side': side,
2070
+ 'takerOrMaker': takerOrMaker,
2071
+ 'price': self.safe_string_2(trade, 'p', 'price'),
2072
+ 'amount': amount,
2073
+ 'cost': None,
2074
+ 'fee': {
2075
+ 'currency': self.safe_currency_code(self.safe_string_2(trade, 'feeCurrency', 'feeCoin')),
2076
+ 'cost': self.safe_string(trade, 'fee'),
2077
+ },
2078
+ }, market)
2079
+
2080
+ async def fetch_balance(self, params={}):
2081
+ """
2082
+ query for balance and get the amount of funds available for trading or funds locked in orders
2083
+
2084
+ https://doc.xt.com/#balancebalancesGet
2085
+ https://doc.xt.com/#futures_usergetBalances
2086
+
2087
+ :param dict params: extra parameters specific to the xt api endpoint
2088
+ :returns dict: a `balance structure <https://docs.ccxt.com/en/latest/manual.html?#balance-structure>`
2089
+ """
2090
+ await self.load_markets()
2091
+ type = None
2092
+ subType = None
2093
+ response = None
2094
+ type, params = self.handle_market_type_and_params('fetchBalance', None, params)
2095
+ subType, params = self.handle_sub_type_and_params('fetchBalance', None, params)
2096
+ isContractWallet = ((type == 'swap') or (type == 'future'))
2097
+ if subType == 'inverse':
2098
+ response = await self.privateInverseGetFutureUserV1BalanceList(params)
2099
+ elif (subType == 'linear') or isContractWallet:
2100
+ response = await self.privateLinearGetFutureUserV1BalanceList(params)
2101
+ else:
2102
+ response = await self.privateSpotGetBalances(params)
2103
+ #
2104
+ # spot
2105
+ #
2106
+ # {
2107
+ # "rc": 0,
2108
+ # "mc": "SUCCESS",
2109
+ # "ma": [],
2110
+ # "result": {
2111
+ # "totalUsdtAmount": "31.75931133",
2112
+ # "totalBtcAmount": "0.00115951",
2113
+ # "assets": [
2114
+ # {
2115
+ # "currency": "usdt",
2116
+ # "currencyId": 11,
2117
+ # "frozenAmount": "0.03834082",
2118
+ # "availableAmount": "31.70995965",
2119
+ # "totalAmount": "31.74830047",
2120
+ # "convertBtcAmount": "0.00115911",
2121
+ # "convertUsdtAmount": "31.74830047"
2122
+ # },
2123
+ # ]
2124
+ # }
2125
+ # }
2126
+ #
2127
+ # swap and future
2128
+ #
2129
+ # {
2130
+ # "returnCode": 0,
2131
+ # "msgInfo": "success",
2132
+ # "error": null,
2133
+ # "result": [
2134
+ # {
2135
+ # "coin": "usdt",
2136
+ # "walletBalance": "19.29849875",
2137
+ # "openOrderMarginFrozen": "0",
2138
+ # "isolatedMargin": "0.709475",
2139
+ # "crossedMargin": "0",
2140
+ # "availableBalance": "18.58902375",
2141
+ # "bonus": "0",
2142
+ # "coupon":"0"
2143
+ # }
2144
+ # ]
2145
+ # }
2146
+ #
2147
+ balances = None
2148
+ if (subType is not None) or isContractWallet:
2149
+ balances = self.safe_value(response, 'result', [])
2150
+ else:
2151
+ data = self.safe_value(response, 'result', {})
2152
+ balances = self.safe_value(data, 'assets', [])
2153
+ return self.parse_balance(balances)
2154
+
2155
+ def parse_balance(self, response):
2156
+ #
2157
+ # spot
2158
+ #
2159
+ # {
2160
+ # "currency": "usdt",
2161
+ # "currencyId": 11,
2162
+ # "frozenAmount": "0.03834082",
2163
+ # "availableAmount": "31.70995965",
2164
+ # "totalAmount": "31.74830047",
2165
+ # "convertBtcAmount": "0.00115911",
2166
+ # "convertUsdtAmount": "31.74830047"
2167
+ # }
2168
+ #
2169
+ # swap and future
2170
+ #
2171
+ # {
2172
+ # "coin": "usdt",
2173
+ # "walletBalance": "19.29849875",
2174
+ # "openOrderMarginFrozen": "0",
2175
+ # "isolatedMargin": "0.709475",
2176
+ # "crossedMargin": "0",
2177
+ # "availableBalance": "18.58902375",
2178
+ # "bonus": "0",
2179
+ # "coupon":"0"
2180
+ # }
2181
+ #
2182
+ result = {'info': response}
2183
+ for i in range(0, len(response)):
2184
+ balance = response[i]
2185
+ currencyId = self.safe_string_2(balance, 'currency', 'coin')
2186
+ code = self.safe_currency_code(currencyId)
2187
+ account = self.account()
2188
+ free = self.safe_string_2(balance, 'availableAmount', 'availableBalance')
2189
+ used = self.safe_string(balance, 'frozenAmount')
2190
+ total = self.safe_string_2(balance, 'totalAmount', 'walletBalance')
2191
+ if used is None:
2192
+ crossedAndIsolatedMargin = Precise.string_add(self.safe_string(balance, 'crossedMargin'), self.safe_string(balance, 'isolatedMargin'))
2193
+ used = Precise.string_add(self.safe_string(balance, 'openOrderMarginFrozen'), crossedAndIsolatedMargin)
2194
+ account['free'] = free
2195
+ account['used'] = used
2196
+ account['total'] = total
2197
+ result[code] = account
2198
+ return self.safe_balance(result)
2199
+
2200
+ async def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
2201
+ """
2202
+
2203
+ https://doc.xt.com/#orderorderPost
2204
+
2205
+ create a market buy order by providing the symbol and cost
2206
+ :param str symbol: unified symbol of the market to create an order in
2207
+ :param float cost: how much you want to trade in units of the quote currency
2208
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2209
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2210
+ """
2211
+ await self.load_markets()
2212
+ market = self.market(symbol)
2213
+ if not market['spot']:
2214
+ raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports spot orders only')
2215
+ return await self.create_order(symbol, 'market', 'buy', cost, 1, params)
2216
+
2217
+ async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
2218
+ """
2219
+ create a trade order
2220
+
2221
+ https://doc.xt.com/#orderorderPost
2222
+ https://doc.xt.com/#futures_ordercreate
2223
+ https://doc.xt.com/#futures_entrustcreatePlan
2224
+ https://doc.xt.com/#futures_entrustcreateProfit
2225
+
2226
+ :param str symbol: unified symbol of the market to create an order in
2227
+ :param str type: 'market' or 'limit'
2228
+ :param str side: 'buy' or 'sell'
2229
+ :param float amount: how much you want to trade in units of the base currency
2230
+ :param float [price]: the price to fulfill the order, in units of the quote currency, can be ignored in market orders
2231
+ :param dict params: extra parameters specific to the xt api endpoint
2232
+ :param str [params.timeInForce]: 'GTC', 'IOC', 'FOK' or 'GTX'
2233
+ :param str [params.entrustType]: 'TAKE_PROFIT', 'STOP', 'TAKE_PROFIT_MARKET', 'STOP_MARKET', 'TRAILING_STOP_MARKET', required if stopPrice is defined, currently isn't functioning on xt's side
2234
+ :param str [params.triggerPriceType]: 'INDEX_PRICE', 'MARK_PRICE', 'LATEST_PRICE', required if stopPrice is defined
2235
+ :param float [params.triggerPrice]: price to trigger a stop order
2236
+ :param float [params.stopPrice]: alias for triggerPrice
2237
+ :param float [params.stopLoss]: price to set a stop-loss on an open position
2238
+ :param float [params.takeProfit]: price to set a take-profit on an open position
2239
+ :returns dict: an `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
2240
+ """
2241
+ await self.load_markets()
2242
+ market = self.market(symbol)
2243
+ symbol = market['symbol']
2244
+ if market['spot']:
2245
+ return await self.create_spot_order(symbol, type, side, amount, price, params)
2246
+ else:
2247
+ return await self.create_contract_order(symbol, type, side, amount, price, params)
2248
+
2249
+ async def create_spot_order(self, symbol: str, type, side, amount, price=None, params={}):
2250
+ await self.load_markets()
2251
+ market = self.market(symbol)
2252
+ request = {
2253
+ 'symbol': market['id'],
2254
+ 'side': side.upper(),
2255
+ 'type': type.upper(),
2256
+ }
2257
+ timeInForce = None
2258
+ marginMode = None
2259
+ marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
2260
+ marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
2261
+ request['bizType'] = marginOrSpotRequest
2262
+ if type == 'market':
2263
+ timeInForce = self.safe_string_upper(params, 'timeInForce', 'FOK')
2264
+ if side == 'buy':
2265
+ cost = self.safe_string(params, 'cost')
2266
+ params = self.omit(params, 'cost')
2267
+ createMarketBuyOrderRequiresPrice = self.safe_bool(self.options, 'createMarketBuyOrderRequiresPrice', True)
2268
+ if createMarketBuyOrderRequiresPrice:
2269
+ if price is None and (cost is None):
2270
+ raise InvalidOrder(self.id + ' createOrder() requires a price argument or cost in params for market buy orders on spot markets to calculate the total amount to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option to False and pass in the cost to spend into the amount parameter')
2271
+ else:
2272
+ amountString = self.number_to_string(amount)
2273
+ priceString = self.number_to_string(price)
2274
+ costCalculated: Str = None
2275
+ if price is not None:
2276
+ costCalculated = Precise.string_mul(amountString, priceString)
2277
+ else:
2278
+ costCalculated = cost
2279
+ request['quoteQty'] = self.cost_to_precision(symbol, costCalculated)
2280
+ else:
2281
+ amountCost = cost if (cost is not None) else amount
2282
+ request['quoteQty'] = self.cost_to_precision(symbol, amountCost)
2283
+ else:
2284
+ timeInForce = self.safe_string_upper(params, 'timeInForce', 'GTC')
2285
+ request['price'] = self.price_to_precision(symbol, price)
2286
+ if (side == 'sell') or (type == 'limit'):
2287
+ request['quantity'] = self.amount_to_precision(symbol, amount)
2288
+ request['timeInForce'] = timeInForce
2289
+ response = await self.privateSpotPostOrder(self.extend(request, params))
2290
+ #
2291
+ # {
2292
+ # "rc": 0,
2293
+ # "mc": "SUCCESS",
2294
+ # "ma": [],
2295
+ # "result": {
2296
+ # "orderId": "204371980095156544"
2297
+ # }
2298
+ # }
2299
+ #
2300
+ order = self.safe_value(response, 'result', {})
2301
+ return self.parse_order(order, market)
2302
+
2303
+ async def create_contract_order(self, symbol: str, type, side, amount, price=None, params={}):
2304
+ await self.load_markets()
2305
+ market = self.market(symbol)
2306
+ request = {
2307
+ 'symbol': market['id'],
2308
+ 'origQty': self.amount_to_precision(symbol, amount),
2309
+ }
2310
+ timeInForce = self.safe_string_upper(params, 'timeInForce')
2311
+ if timeInForce is not None:
2312
+ request['timeInForce'] = timeInForce
2313
+ reduceOnly = self.safe_value(params, 'reduceOnly', False)
2314
+ if side == 'buy':
2315
+ requestType = 'SHORT' if (reduceOnly) else 'LONG'
2316
+ request['positionSide'] = requestType
2317
+ else:
2318
+ requestType = 'LONG' if (reduceOnly) else 'SHORT'
2319
+ request['positionSide'] = requestType
2320
+ response = None
2321
+ triggerPrice = self.safe_number_2(params, 'triggerPrice', 'stopPrice')
2322
+ stopLoss = self.safe_number_2(params, 'stopLoss', 'triggerStopPrice')
2323
+ takeProfit = self.safe_number_2(params, 'takeProfit', 'triggerProfitPrice')
2324
+ isTrigger = (triggerPrice is not None)
2325
+ isStopLoss = (stopLoss is not None)
2326
+ isTakeProfit = (takeProfit is not None)
2327
+ if price is not None:
2328
+ if not (isStopLoss) and not (isTakeProfit):
2329
+ request['price'] = self.price_to_precision(symbol, price)
2330
+ if isTrigger:
2331
+ request['timeInForce'] = self.safe_string_upper(params, 'timeInForce', 'GTC')
2332
+ request['triggerPriceType'] = self.safe_string(params, 'triggerPriceType', 'LATEST_PRICE')
2333
+ request['orderSide'] = side.upper()
2334
+ request['stopPrice'] = self.price_to_precision(symbol, triggerPrice)
2335
+ entrustType = 'STOP_MARKET' if (type == 'market') else 'STOP'
2336
+ request['entrustType'] = entrustType
2337
+ params = self.omit(params, 'triggerPrice')
2338
+ if market['linear']:
2339
+ response = await self.privateLinearPostFutureTradeV1EntrustCreatePlan(self.extend(request, params))
2340
+ elif market['inverse']:
2341
+ response = await self.privateInversePostFutureTradeV1EntrustCreatePlan(self.extend(request, params))
2342
+ elif isStopLoss or isTakeProfit:
2343
+ if isStopLoss:
2344
+ request['triggerStopPrice'] = self.price_to_precision(symbol, stopLoss)
2345
+ else:
2346
+ request['triggerProfitPrice'] = self.price_to_precision(symbol, takeProfit)
2347
+ params = self.omit(params, ['stopLoss', 'takeProfit'])
2348
+ if market['linear']:
2349
+ response = await self.privateLinearPostFutureTradeV1EntrustCreateProfit(self.extend(request, params))
2350
+ elif market['inverse']:
2351
+ response = await self.privateInversePostFutureTradeV1EntrustCreateProfit(self.extend(request, params))
2352
+ else:
2353
+ request['orderSide'] = side.upper()
2354
+ request['orderType'] = type.upper()
2355
+ if market['linear']:
2356
+ response = await self.privateLinearPostFutureTradeV1OrderCreate(self.extend(request, params))
2357
+ elif market['inverse']:
2358
+ response = await self.privateInversePostFutureTradeV1OrderCreate(self.extend(request, params))
2359
+ #
2360
+ # {
2361
+ # "returnCode": 0,
2362
+ # "msgInfo": "success",
2363
+ # "error": null,
2364
+ # "result": "206410760006650176"
2365
+ # }
2366
+ #
2367
+ return self.parse_order(response, market)
2368
+
2369
+ async def fetch_order(self, id: str, symbol: str = None, params={}):
2370
+ """
2371
+ fetches information on an order made by the user
2372
+
2373
+ https://doc.xt.com/#orderorderGet
2374
+ https://doc.xt.com/#futures_ordergetById
2375
+ https://doc.xt.com/#futures_entrustgetPlanById
2376
+ https://doc.xt.com/#futures_entrustgetProfitById
2377
+
2378
+ :param str id: order id
2379
+ :param str [symbol]: unified symbol of the market the order was made in
2380
+ :param dict params: extra parameters specific to the xt api endpoint
2381
+ :param bool [params.trigger]: if the order is a trigger order or not
2382
+ :param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
2383
+ :returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
2384
+ """
2385
+ await self.load_markets()
2386
+ market = None
2387
+ if symbol is not None:
2388
+ market = self.market(symbol)
2389
+ request = {}
2390
+ type = None
2391
+ subType = None
2392
+ response = None
2393
+ type, params = self.handle_market_type_and_params('fetchOrder', market, params)
2394
+ subType, params = self.handle_sub_type_and_params('fetchOrder', market, params)
2395
+ trigger = self.safe_value(params, 'stop')
2396
+ stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
2397
+ if trigger:
2398
+ request['entrustId'] = id
2399
+ elif stopLossTakeProfit:
2400
+ request['profitId'] = id
2401
+ else:
2402
+ request['orderId'] = id
2403
+ if trigger:
2404
+ params = self.omit(params, 'stop')
2405
+ if subType == 'inverse':
2406
+ response = await self.privateInverseGetFutureTradeV1EntrustPlanDetail(self.extend(request, params))
2407
+ else:
2408
+ response = await self.privateLinearGetFutureTradeV1EntrustPlanDetail(self.extend(request, params))
2409
+ elif stopLossTakeProfit:
2410
+ params = self.omit(params, 'stopLossTakeProfit')
2411
+ if subType == 'inverse':
2412
+ response = await self.privateInverseGetFutureTradeV1EntrustProfitDetail(self.extend(request, params))
2413
+ else:
2414
+ response = await self.privateLinearGetFutureTradeV1EntrustProfitDetail(self.extend(request, params))
2415
+ elif subType == 'inverse':
2416
+ response = await self.privateInverseGetFutureTradeV1OrderDetail(self.extend(request, params))
2417
+ elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
2418
+ response = await self.privateLinearGetFutureTradeV1OrderDetail(self.extend(request, params))
2419
+ else:
2420
+ response = await self.privateSpotGetOrderOrderId(self.extend(request, params))
2421
+ #
2422
+ # spot
2423
+ #
2424
+ # {
2425
+ # "rc": 0,
2426
+ # "mc": "SUCCESS",
2427
+ # "ma": [],
2428
+ # "result": {
2429
+ # "symbol": "btc_usdt",
2430
+ # "orderId": "207505997850909952",
2431
+ # "clientOrderId": null,
2432
+ # "baseCurrency": "btc",
2433
+ # "quoteCurrency": "usdt",
2434
+ # "side": "BUY",
2435
+ # "type": "LIMIT",
2436
+ # "timeInForce": "GTC",
2437
+ # "price": "20000.00",
2438
+ # "origQty": "0.001000",
2439
+ # "origQuoteQty": "20.00",
2440
+ # "executedQty": "0.000000",
2441
+ # "leavingQty": "0.001000",
2442
+ # "tradeBase": "0.000000",
2443
+ # "tradeQuote": "0.00",
2444
+ # "avgPrice": null,
2445
+ # "fee": null,
2446
+ # "feeCurrency": null,
2447
+ # "closed": False,
2448
+ # "state": "NEW",
2449
+ # "time": 1679175285162,
2450
+ # "updatedTime": 1679175285255
2451
+ # }
2452
+ # }
2453
+ #
2454
+ # swap and future
2455
+ #
2456
+ # {
2457
+ # "returnCode": 0,
2458
+ # "msgInfo": "success",
2459
+ # "error": null,
2460
+ # "result": {
2461
+ # "orderId": "211451874783183936",
2462
+ # "clientOrderId": null,
2463
+ # "symbol": "btc_usdt",
2464
+ # "orderType": "LIMIT",
2465
+ # "orderSide": "BUY",
2466
+ # "positionSide": "LONG",
2467
+ # "timeInForce": "GTC",
2468
+ # "closePosition": False,
2469
+ # "price": "20000",
2470
+ # "origQty": "10",
2471
+ # "avgPrice": "0",
2472
+ # "executedQty": "0",
2473
+ # "marginFrozen": "1.34533334",
2474
+ # "remark": null,
2475
+ # "triggerProfitPrice": null,
2476
+ # "triggerStopPrice": null,
2477
+ # "sourceId": null,
2478
+ # "sourceType": "DEFAULT",
2479
+ # "forceClose": False,
2480
+ # "closeProfit": null,
2481
+ # "state": "NEW",
2482
+ # "createdTime": 1680116055693,
2483
+ # "updatedTime": 1680116055693
2484
+ # }
2485
+ # }
2486
+ #
2487
+ # trigger
2488
+ #
2489
+ # {
2490
+ # "returnCode": 0,
2491
+ # "msgInfo": "success",
2492
+ # "error": null,
2493
+ # "result": {
2494
+ # "entrustId": "216300248132756992",
2495
+ # "symbol": "btc_usdt",
2496
+ # "entrustType": "STOP",
2497
+ # "orderSide": "SELL",
2498
+ # "positionSide": "SHORT",
2499
+ # "timeInForce": "GTC",
2500
+ # "closePosition": null,
2501
+ # "price": "20000",
2502
+ # "origQty": "1",
2503
+ # "stopPrice": "19000",
2504
+ # "triggerPriceType": "LATEST_PRICE",
2505
+ # "state": "NOT_TRIGGERED",
2506
+ # "marketOrderLevel": null,
2507
+ # "createdTime": 1681271998064,
2508
+ # "updatedTime": 1681271998064,
2509
+ # "ordinary": False
2510
+ # }
2511
+ # }
2512
+ #
2513
+ # stop-loss and take-profit
2514
+ #
2515
+ # {
2516
+ # "returnCode": 0,
2517
+ # "msgInfo": "success",
2518
+ # "error": null,
2519
+ # "result": {
2520
+ # "profitId": "216306213226230400",
2521
+ # "symbol": "btc_usdt",
2522
+ # "positionSide": "LONG",
2523
+ # "origQty": "1",
2524
+ # "triggerPriceType": "LATEST_PRICE",
2525
+ # "triggerProfitPrice": null,
2526
+ # "triggerStopPrice": "20000",
2527
+ # "entryPrice": null,
2528
+ # "positionSize": null,
2529
+ # "isolatedMargin": null,
2530
+ # "executedQty": null,
2531
+ # "avgPrice": null,
2532
+ # "positionType": "ISOLATED",
2533
+ # "state": "NOT_TRIGGERED",
2534
+ # "createdTime": 1681273420039
2535
+ # }
2536
+ # }
2537
+ #
2538
+ order = self.safe_value(response, 'result', {})
2539
+ return self.parse_order(order, market)
2540
+
2541
+ async def fetch_orders(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
2542
+ """
2543
+ fetches information on multiple orders made by the user
2544
+
2545
+ https://doc.xt.com/#orderhistoryOrderGet
2546
+ https://doc.xt.com/#futures_ordergetHistory
2547
+ https://doc.xt.com/#futures_entrustgetPlanHistory
2548
+
2549
+ :param str [symbol]: unified market symbol of the market the orders were made in
2550
+ :param int [since]: timestamp in ms of the earliest order
2551
+ :param int [limit]: the maximum number of order structures to retrieve
2552
+ :param dict params: extra parameters specific to the xt api endpoint
2553
+ :param bool [params.trigger]: if the order is a trigger order or not
2554
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
2555
+ """
2556
+ await self.load_markets()
2557
+ request = {}
2558
+ market = None
2559
+ if symbol is not None:
2560
+ market = self.market(symbol)
2561
+ request['symbol'] = market['id']
2562
+ if since is not None:
2563
+ request['startTime'] = since
2564
+ if limit is not None:
2565
+ request['limit'] = limit
2566
+ type = None
2567
+ subType = None
2568
+ response = None
2569
+ type, params = self.handle_market_type_and_params('fetchOrders', market, params)
2570
+ subType, params = self.handle_sub_type_and_params('fetchOrders', market, params)
2571
+ trigger = self.safe_value_2(params, 'trigger', 'stop')
2572
+ if trigger:
2573
+ params = self.omit(params, ['trigger', 'stop'])
2574
+ if subType == 'inverse':
2575
+ response = await self.privateInverseGetFutureTradeV1EntrustPlanListHistory(self.extend(request, params))
2576
+ else:
2577
+ response = await self.privateLinearGetFutureTradeV1EntrustPlanListHistory(self.extend(request, params))
2578
+ elif subType == 'inverse':
2579
+ response = await self.privateInverseGetFutureTradeV1OrderListHistory(self.extend(request, params))
2580
+ elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
2581
+ response = await self.privateLinearGetFutureTradeV1OrderListHistory(self.extend(request, params))
2582
+ else:
2583
+ marginMode = None
2584
+ marginMode, params = self.handle_margin_mode_and_params('fetchOrders', params)
2585
+ marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
2586
+ request['bizType'] = marginOrSpotRequest
2587
+ response = await self.privateSpotGetHistoryOrder(self.extend(request, params))
2588
+ #
2589
+ # spot and margin
2590
+ #
2591
+ # {
2592
+ # "rc": 0,
2593
+ # "mc": "SUCCESS",
2594
+ # "ma": [],
2595
+ # "result": {
2596
+ # "hasPrev": False,
2597
+ # "hasNext": True,
2598
+ # "items": [
2599
+ # {
2600
+ # "symbol": "btc_usdt",
2601
+ # "orderId": "207505997850909952",
2602
+ # "clientOrderId": null,
2603
+ # "baseCurrency": "btc",
2604
+ # "quoteCurrency": "usdt",
2605
+ # "side": "BUY",
2606
+ # "type": "LIMIT",
2607
+ # "timeInForce": "GTC",
2608
+ # "price": "20000.00",
2609
+ # "origQty": "0.001000",
2610
+ # "origQuoteQty": "20.00",
2611
+ # "executedQty": "0.000000",
2612
+ # "leavingQty": "0.000000",
2613
+ # "tradeBase": "0.000000",
2614
+ # "tradeQuote": "0.00",
2615
+ # "avgPrice": null,
2616
+ # "fee": null,
2617
+ # "feeCurrency": null,
2618
+ # "closed": True,
2619
+ # "state": "CANCELED",
2620
+ # "time": 1679175285162,
2621
+ # "updatedTime": 1679175488492
2622
+ # },
2623
+ # ]
2624
+ # }
2625
+ # }
2626
+ #
2627
+ # swap and future
2628
+ #
2629
+ # {
2630
+ # "returnCode": 0,
2631
+ # "msgInfo": "success",
2632
+ # "error": null,
2633
+ # "result": {
2634
+ # "hasPrev": False,
2635
+ # "hasNext": True,
2636
+ # "items": [
2637
+ # {
2638
+ # "orderId": "207519546930995456",
2639
+ # "clientOrderId": null,
2640
+ # "symbol": "btc_usdt",
2641
+ # "orderType": "LIMIT",
2642
+ # "orderSide": "BUY",
2643
+ # "positionSide": "LONG",
2644
+ # "timeInForce": "GTC",
2645
+ # "closePosition": False,
2646
+ # "price": "20000",
2647
+ # "origQty": "100",
2648
+ # "avgPrice": "0",
2649
+ # "executedQty": "0",
2650
+ # "marginFrozen": "4.12",
2651
+ # "remark": null,
2652
+ # "triggerProfitPrice": null,
2653
+ # "triggerStopPrice": null,
2654
+ # "sourceId": null,
2655
+ # "sourceType": "DEFAULT",
2656
+ # "forceClose": False,
2657
+ # "closeProfit": null,
2658
+ # "state": "CANCELED",
2659
+ # "createdTime": 1679178515689,
2660
+ # "updatedTime": 1679180096172
2661
+ # },
2662
+ # ]
2663
+ # }
2664
+ # }
2665
+ #
2666
+ # stop
2667
+ #
2668
+ # {
2669
+ # "returnCode": 0,
2670
+ # "msgInfo": "success",
2671
+ # "error": null,
2672
+ # "result": {
2673
+ # "hasPrev": False,
2674
+ # "hasNext": False,
2675
+ # "items": [
2676
+ # {
2677
+ # "entrustId": "216300248132756992",
2678
+ # "symbol": "btc_usdt",
2679
+ # "entrustType": "STOP",
2680
+ # "orderSide": "SELL",
2681
+ # "positionSide": "SHORT",
2682
+ # "timeInForce": "GTC",
2683
+ # "closePosition": null,
2684
+ # "price": "20000",
2685
+ # "origQty": "1",
2686
+ # "stopPrice": "19000",
2687
+ # "triggerPriceType": "LATEST_PRICE",
2688
+ # "state": "USER_REVOCATION",
2689
+ # "marketOrderLevel": null,
2690
+ # "createdTime": 1681271998064,
2691
+ # "updatedTime": 1681273188674,
2692
+ # "ordinary": False
2693
+ # },
2694
+ # ]
2695
+ # }
2696
+ # }
2697
+ #
2698
+ data = self.safe_value(response, 'result', {})
2699
+ orders = self.safe_value(data, 'items', [])
2700
+ return self.parse_orders(orders, market, since, limit)
2701
+
2702
+ async def fetch_orders_by_status(self, status, symbol: str = None, since: Int = None, limit: Int = None, params={}):
2703
+ await self.load_markets()
2704
+ request = {}
2705
+ market = None
2706
+ if symbol is not None:
2707
+ market = self.market(symbol)
2708
+ request['symbol'] = market['id']
2709
+ type = None
2710
+ subType = None
2711
+ response = None
2712
+ type, params = self.handle_market_type_and_params('fetchOrdersByStatus', market, params)
2713
+ subType, params = self.handle_sub_type_and_params('fetchOrdersByStatus', market, params)
2714
+ trigger = self.safe_value(params, 'stop')
2715
+ stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
2716
+ if status == 'open':
2717
+ if trigger or stopLossTakeProfit:
2718
+ request['state'] = 'NOT_TRIGGERED'
2719
+ elif subType is not None:
2720
+ request['state'] = 'NEW'
2721
+ elif status == 'closed':
2722
+ if trigger or stopLossTakeProfit:
2723
+ request['state'] = 'TRIGGERED'
2724
+ else:
2725
+ request['state'] = 'FILLED'
2726
+ elif status == 'canceled':
2727
+ if trigger or stopLossTakeProfit:
2728
+ request['state'] = 'USER_REVOCATION'
2729
+ else:
2730
+ request['state'] = 'CANCELED'
2731
+ else:
2732
+ request['state'] = status
2733
+ if trigger or stopLossTakeProfit or (subType is not None) or (type == 'swap') or (type == 'future'):
2734
+ if since is not None:
2735
+ request['startTime'] = since
2736
+ if limit is not None:
2737
+ request['size'] = limit
2738
+ if trigger:
2739
+ params = self.omit(params, 'stop')
2740
+ if subType == 'inverse':
2741
+ response = await self.privateInverseGetFutureTradeV1EntrustPlanList(self.extend(request, params))
2742
+ else:
2743
+ response = await self.privateLinearGetFutureTradeV1EntrustPlanList(self.extend(request, params))
2744
+ elif stopLossTakeProfit:
2745
+ params = self.omit(params, 'stopLossTakeProfit')
2746
+ if subType == 'inverse':
2747
+ response = await self.privateInverseGetFutureTradeV1EntrustProfitList(self.extend(request, params))
2748
+ else:
2749
+ response = await self.privateLinearGetFutureTradeV1EntrustProfitList(self.extend(request, params))
2750
+ elif (subType is not None) or (type == 'swap') or (type == 'future'):
2751
+ if subType == 'inverse':
2752
+ response = await self.privateInverseGetFutureTradeV1OrderList(self.extend(request, params))
2753
+ else:
2754
+ response = await self.privateLinearGetFutureTradeV1OrderList(self.extend(request, params))
2755
+ else:
2756
+ marginMode = None
2757
+ marginMode, params = self.handle_margin_mode_and_params('fetchOrdersByStatus', params)
2758
+ marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
2759
+ request['bizType'] = marginOrSpotRequest
2760
+ if status != 'open':
2761
+ if since is not None:
2762
+ request['startTime'] = since
2763
+ if limit is not None:
2764
+ request['limit'] = limit
2765
+ response = await self.privateSpotGetHistoryOrder(self.extend(request, params))
2766
+ else:
2767
+ response = await self.privateSpotGetOpenOrder(self.extend(request, params))
2768
+ #
2769
+ # spot and margin
2770
+ #
2771
+ # {
2772
+ # "rc": 0,
2773
+ # "mc": "SUCCESS",
2774
+ # "ma": [],
2775
+ # "result": {
2776
+ # "hasPrev": False,
2777
+ # "hasNext": True,
2778
+ # "items": [
2779
+ # {
2780
+ # "symbol": "btc_usdt",
2781
+ # "orderId": "207505997850909952",
2782
+ # "clientOrderId": null,
2783
+ # "baseCurrency": "btc",
2784
+ # "quoteCurrency": "usdt",
2785
+ # "side": "BUY",
2786
+ # "type": "LIMIT",
2787
+ # "timeInForce": "GTC",
2788
+ # "price": "20000.00",
2789
+ # "origQty": "0.001000",
2790
+ # "origQuoteQty": "20.00",
2791
+ # "executedQty": "0.000000",
2792
+ # "leavingQty": "0.000000",
2793
+ # "tradeBase": "0.000000",
2794
+ # "tradeQuote": "0.00",
2795
+ # "avgPrice": null,
2796
+ # "fee": null,
2797
+ # "feeCurrency": null,
2798
+ # "closed": True,
2799
+ # "state": "CANCELED",
2800
+ # "time": 1679175285162,
2801
+ # "updatedTime": 1679175488492
2802
+ # },
2803
+ # ]
2804
+ # }
2805
+ # }
2806
+ #
2807
+ # spot and margin: fetchOpenOrders
2808
+ #
2809
+ # {
2810
+ # "rc": 0,
2811
+ # "mc": "SUCCESS",
2812
+ # "ma": [],
2813
+ # "result": [
2814
+ # {
2815
+ # "symbol": "eth_usdt",
2816
+ # "orderId": "208249323222264320",
2817
+ # "clientOrderId": null,
2818
+ # "baseCurrency": "eth",
2819
+ # "quoteCurrency": "usdt",
2820
+ # "side": "BUY",
2821
+ # "type": "LIMIT",
2822
+ # "timeInForce": "GTC",
2823
+ # "price": "1300.00",
2824
+ # "origQty": "0.0032",
2825
+ # "origQuoteQty": "4.16",
2826
+ # "executedQty": "0.0000",
2827
+ # "leavingQty": "0.0032",
2828
+ # "tradeBase": "0.0000",
2829
+ # "tradeQuote": "0.00",
2830
+ # "avgPrice": null,
2831
+ # "fee": null,
2832
+ # "feeCurrency": null,
2833
+ # "closed": False,
2834
+ # "state": "NEW",
2835
+ # "time": 1679352507741,
2836
+ # "updatedTime": 1679352507869
2837
+ # },
2838
+ # ]
2839
+ # }
2840
+ #
2841
+ # swap and future
2842
+ #
2843
+ # {
2844
+ # "returnCode": 0,
2845
+ # "msgInfo": "success",
2846
+ # "error": null,
2847
+ # "result": {
2848
+ # "page": 1,
2849
+ # "ps": 10,
2850
+ # "total": 25,
2851
+ # "items": [
2852
+ # {
2853
+ # "orderId": "207519546930995456",
2854
+ # "clientOrderId": null,
2855
+ # "symbol": "btc_usdt",
2856
+ # "orderType": "LIMIT",
2857
+ # "orderSide": "BUY",
2858
+ # "positionSide": "LONG",
2859
+ # "timeInForce": "GTC",
2860
+ # "closePosition": False,
2861
+ # "price": "20000",
2862
+ # "origQty": "100",
2863
+ # "avgPrice": "0",
2864
+ # "executedQty": "0",
2865
+ # "marginFrozen": "4.12",
2866
+ # "remark": null,
2867
+ # "triggerProfitPrice": null,
2868
+ # "triggerStopPrice": null,
2869
+ # "sourceId": null,
2870
+ # "sourceType": "DEFAULT",
2871
+ # "forceClose": False,
2872
+ # "closeProfit": null,
2873
+ # "state": "CANCELED",
2874
+ # "createdTime": 1679178515689,
2875
+ # "updatedTime": 1679180096172
2876
+ # },
2877
+ # ]
2878
+ # }
2879
+ # }
2880
+ #
2881
+ # stop
2882
+ #
2883
+ # {
2884
+ # "returnCode": 0,
2885
+ # "msgInfo": "success",
2886
+ # "error": null,
2887
+ # "result": {
2888
+ # "page": 1,
2889
+ # "ps": 3,
2890
+ # "total": 8,
2891
+ # "items": [
2892
+ # {
2893
+ # "entrustId": "216300248132756992",
2894
+ # "symbol": "btc_usdt",
2895
+ # "entrustType": "STOP",
2896
+ # "orderSide": "SELL",
2897
+ # "positionSide": "SHORT",
2898
+ # "timeInForce": "GTC",
2899
+ # "closePosition": null,
2900
+ # "price": "20000",
2901
+ # "origQty": "1",
2902
+ # "stopPrice": "19000",
2903
+ # "triggerPriceType": "LATEST_PRICE",
2904
+ # "state": "USER_REVOCATION",
2905
+ # "marketOrderLevel": null,
2906
+ # "createdTime": 1681271998064,
2907
+ # "updatedTime": 1681273188674,
2908
+ # "ordinary": False
2909
+ # },
2910
+ # ]
2911
+ # }
2912
+ # }
2913
+ #
2914
+ # stop-loss and take-profit
2915
+ #
2916
+ # {
2917
+ # "returnCode": 0,
2918
+ # "msgInfo": "success",
2919
+ # "error": null,
2920
+ # "result": {
2921
+ # "page": 1,
2922
+ # "ps": 3,
2923
+ # "total": 2,
2924
+ # "items": [
2925
+ # {
2926
+ # "profitId": "216306213226230400",
2927
+ # "symbol": "btc_usdt",
2928
+ # "positionSide": "LONG",
2929
+ # "origQty": "1",
2930
+ # "triggerPriceType": "LATEST_PRICE",
2931
+ # "triggerProfitPrice": null,
2932
+ # "triggerStopPrice": "20000",
2933
+ # "entryPrice": "0",
2934
+ # "positionSize": "0",
2935
+ # "isolatedMargin": "0",
2936
+ # "executedQty": "0",
2937
+ # "avgPrice": null,
2938
+ # "positionType": "ISOLATED",
2939
+ # "state": "USER_REVOCATION",
2940
+ # "createdTime": 1681273420039
2941
+ # },
2942
+ # ]
2943
+ # }
2944
+ # }
2945
+ #
2946
+ isSpotOpenOrders = ((status == 'open') and (subType is None))
2947
+ data = self.safe_value(response, 'result', {})
2948
+ orders = self.safe_value(response, 'result', []) if isSpotOpenOrders else self.safe_value(data, 'items', [])
2949
+ return self.parse_orders(orders, market, since, limit)
2950
+
2951
+ async def fetch_open_orders(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
2952
+ """
2953
+ fetch all unfilled currently open orders
2954
+
2955
+ https://doc.xt.com/#orderopenOrderGet
2956
+ https://doc.xt.com/#futures_ordergetOrders
2957
+ https://doc.xt.com/#futures_entrustgetPlan
2958
+ https://doc.xt.com/#futures_entrustgetProfit
2959
+
2960
+ :param str [symbol]: unified market symbol of the market the orders were made in
2961
+ :param int [since]: timestamp in ms of the earliest order
2962
+ :param int [limit]: the maximum number of open order structures to retrieve
2963
+ :param dict params: extra parameters specific to the xt api endpoint
2964
+ :param bool [params.trigger]: if the order is a trigger order or not
2965
+ :param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
2966
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
2967
+ """
2968
+ return await self.fetch_orders_by_status('open', symbol, since, limit, params)
2969
+
2970
+ async def fetch_closed_orders(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
2971
+ """
2972
+ fetches information on multiple closed orders made by the user
2973
+
2974
+ https://doc.xt.com/#orderhistoryOrderGet
2975
+ https://doc.xt.com/#futures_ordergetOrders
2976
+ https://doc.xt.com/#futures_entrustgetPlan
2977
+ https://doc.xt.com/#futures_entrustgetProfit
2978
+
2979
+ :param str [symbol]: unified market symbol of the market the orders were made in
2980
+ :param int [since]: timestamp in ms of the earliest order
2981
+ :param int [limit]: the maximum number of order structures to retrieve
2982
+ :param dict params: extra parameters specific to the xt api endpoint
2983
+ :param bool [params.trigger]: if the order is a trigger order or not
2984
+ :param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
2985
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
2986
+ """
2987
+ return await self.fetch_orders_by_status('closed', symbol, since, limit, params)
2988
+
2989
+ async def fetch_canceled_orders(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
2990
+ """
2991
+ fetches information on multiple canceled orders made by the user
2992
+
2993
+ https://doc.xt.com/#orderhistoryOrderGet
2994
+ https://doc.xt.com/#futures_ordergetOrders
2995
+ https://doc.xt.com/#futures_entrustgetPlan
2996
+ https://doc.xt.com/#futures_entrustgetProfit
2997
+
2998
+ :param str [symbol]: unified market symbol of the market the orders were made in
2999
+ :param int [since]: timestamp in ms of the earliest order
3000
+ :param int [limit]: the maximum number of order structures to retrieve
3001
+ :param dict params: extra parameters specific to the xt api endpoint
3002
+ :param bool [params.trigger]: if the order is a trigger order or not
3003
+ :param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
3004
+ :returns dict: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
3005
+ """
3006
+ return await self.fetch_orders_by_status('canceled', symbol, since, limit, params)
3007
+
3008
+ async def cancel_order(self, id: str, symbol: str = None, params={}):
3009
+ """
3010
+ cancels an open order
3011
+
3012
+ https://doc.xt.com/#orderorderDel
3013
+ https://doc.xt.com/#futures_ordercancel
3014
+ https://doc.xt.com/#futures_entrustcancelPlan
3015
+ https://doc.xt.com/#futures_entrustcancelProfit
3016
+
3017
+ :param str id: order id
3018
+ :param str [symbol]: unified symbol of the market the order was made in
3019
+ :param dict params: extra parameters specific to the xt api endpoint
3020
+ :param bool [params.trigger]: if the order is a trigger order or not
3021
+ :param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
3022
+ :returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
3023
+ """
3024
+ await self.load_markets()
3025
+ market = None
3026
+ if symbol is not None:
3027
+ market = self.market(symbol)
3028
+ request = {}
3029
+ type = None
3030
+ subType = None
3031
+ response = None
3032
+ type, params = self.handle_market_type_and_params('cancelOrder', market, params)
3033
+ subType, params = self.handle_sub_type_and_params('cancelOrder', market, params)
3034
+ trigger = self.safe_value_2(params, 'trigger', 'stop')
3035
+ stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
3036
+ if trigger:
3037
+ request['entrustId'] = id
3038
+ elif stopLossTakeProfit:
3039
+ request['profitId'] = id
3040
+ else:
3041
+ request['orderId'] = id
3042
+ if trigger:
3043
+ params = self.omit(params, ['trigger', 'stop'])
3044
+ if subType == 'inverse':
3045
+ response = await self.privateInversePostFutureTradeV1EntrustCancelPlan(self.extend(request, params))
3046
+ else:
3047
+ response = await self.privateLinearPostFutureTradeV1EntrustCancelPlan(self.extend(request, params))
3048
+ elif stopLossTakeProfit:
3049
+ params = self.omit(params, 'stopLossTakeProfit')
3050
+ if subType == 'inverse':
3051
+ response = await self.privateInversePostFutureTradeV1EntrustCancelProfitStop(self.extend(request, params))
3052
+ else:
3053
+ response = await self.privateLinearPostFutureTradeV1EntrustCancelProfitStop(self.extend(request, params))
3054
+ elif subType == 'inverse':
3055
+ response = await self.privateInversePostFutureTradeV1OrderCancel(self.extend(request, params))
3056
+ elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
3057
+ response = await self.privateLinearPostFutureTradeV1OrderCancel(self.extend(request, params))
3058
+ else:
3059
+ response = await self.privateSpotDeleteOrderOrderId(self.extend(request, params))
3060
+ #
3061
+ # spot
3062
+ #
3063
+ # {
3064
+ # "rc": 0,
3065
+ # "mc": "SUCCESS",
3066
+ # "ma": [],
3067
+ # "result": {
3068
+ # "cancelId": "208322474307982720"
3069
+ # }
3070
+ # }
3071
+ #
3072
+ # swap and future
3073
+ #
3074
+ # {
3075
+ # "returnCode": 0,
3076
+ # "msgInfo": "success",
3077
+ # "error": null,
3078
+ # "result": "208319789679471616"
3079
+ # }
3080
+ #
3081
+ isContractResponse = ((subType is not None) or (type == 'swap') or (type == 'future'))
3082
+ order = response if isContractResponse else self.safe_value(response, 'result', {})
3083
+ return self.parse_order(order, market)
3084
+
3085
+ async def cancel_all_orders(self, symbol: str = None, params={}):
3086
+ """
3087
+ cancel all open orders in a market
3088
+
3089
+ https://doc.xt.com/#orderopenOrderDel
3090
+ https://doc.xt.com/#futures_ordercancelBatch
3091
+ https://doc.xt.com/#futures_entrustcancelPlanBatch
3092
+ https://doc.xt.com/#futures_entrustcancelProfitBatch
3093
+
3094
+ :param str [symbol]: unified market symbol of the market to cancel orders in
3095
+ :param dict params: extra parameters specific to the xt api endpoint
3096
+ :param bool [params.trigger]: if the order is a trigger order or not
3097
+ :param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
3098
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
3099
+ """
3100
+ await self.load_markets()
3101
+ request = {}
3102
+ market = None
3103
+ if symbol is not None:
3104
+ market = self.market(symbol)
3105
+ request['symbol'] = market['id']
3106
+ type = None
3107
+ subType = None
3108
+ response = None
3109
+ type, params = self.handle_market_type_and_params('cancelAllOrders', market, params)
3110
+ subType, params = self.handle_sub_type_and_params('cancelAllOrders', market, params)
3111
+ trigger = self.safe_value_2(params, 'trigger', 'stop')
3112
+ stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
3113
+ if trigger:
3114
+ params = self.omit(params, ['trigger', 'stop'])
3115
+ if subType == 'inverse':
3116
+ response = await self.privateInversePostFutureTradeV1EntrustCancelAllPlan(self.extend(request, params))
3117
+ else:
3118
+ response = await self.privateLinearPostFutureTradeV1EntrustCancelAllPlan(self.extend(request, params))
3119
+ elif stopLossTakeProfit:
3120
+ params = self.omit(params, 'stopLossTakeProfit')
3121
+ if subType == 'inverse':
3122
+ response = await self.privateInversePostFutureTradeV1EntrustCancelAllProfitStop(self.extend(request, params))
3123
+ else:
3124
+ response = await self.privateLinearPostFutureTradeV1EntrustCancelAllProfitStop(self.extend(request, params))
3125
+ elif subType == 'inverse':
3126
+ response = await self.privateInversePostFutureTradeV1OrderCancelAll(self.extend(request, params))
3127
+ elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
3128
+ response = await self.privateLinearPostFutureTradeV1OrderCancelAll(self.extend(request, params))
3129
+ else:
3130
+ marginMode = None
3131
+ marginMode, params = self.handle_margin_mode_and_params('cancelAllOrders', params)
3132
+ marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
3133
+ request['bizType'] = marginOrSpotRequest
3134
+ response = await self.privateSpotDeleteOpenOrder(self.extend(request, params))
3135
+ #
3136
+ # spot and margin
3137
+ #
3138
+ # {
3139
+ # "rc": 0,
3140
+ # "mc": "SUCCESS",
3141
+ # "ma": [],
3142
+ # "result": null
3143
+ # }
3144
+ #
3145
+ # swap and future
3146
+ #
3147
+ # {
3148
+ # "returnCode": 0,
3149
+ # "msgInfo": "success",
3150
+ # "error": null,
3151
+ # "result": True
3152
+ # }
3153
+ #
3154
+ return [
3155
+ self.safe_order(response),
3156
+ ]
3157
+
3158
+ async def cancel_orders(self, ids: List[str], symbol: str = None, params={}) -> List[Order]:
3159
+ """
3160
+ cancel multiple orders
3161
+
3162
+ https://doc.xt.com/#orderbatchOrderDel
3163
+
3164
+ :param str[] ids: order ids
3165
+ :param str [symbol]: unified market symbol of the market to cancel orders in
3166
+ :param dict params: extra parameters specific to the xt api endpoint
3167
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
3168
+ """
3169
+ await self.load_markets()
3170
+ request = {
3171
+ 'orderIds': ids,
3172
+ }
3173
+ market = None
3174
+ if symbol is not None:
3175
+ market = self.market(symbol)
3176
+ subType = None
3177
+ subType, params = self.handle_sub_type_and_params('cancelOrders', market, params)
3178
+ if subType is not None:
3179
+ raise NotSupported(self.id + ' cancelOrders() does not support swap and future orders, only spot orders are accepted')
3180
+ response = await self.privateSpotDeleteBatchOrder(self.extend(request, params))
3181
+ #
3182
+ # spot
3183
+ #
3184
+ # {
3185
+ # "rc": 0,
3186
+ # "mc": "SUCCESS",
3187
+ # "ma": [],
3188
+ # "result": null
3189
+ # }
3190
+ #
3191
+ return [
3192
+ self.safe_order(response),
3193
+ ]
3194
+
3195
+ def parse_order(self, order, market=None):
3196
+ #
3197
+ # spot: createOrder
3198
+ #
3199
+ # {
3200
+ # "orderId": "204371980095156544"
3201
+ # }
3202
+ #
3203
+ # spot: cancelOrder
3204
+ #
3205
+ # {
3206
+ # "cancelId": "208322474307982720"
3207
+ # }
3208
+ #
3209
+ # swap and future: createOrder, cancelOrder
3210
+ #
3211
+ # {
3212
+ # "returnCode": 0,
3213
+ # "msgInfo": "success",
3214
+ # "error": null,
3215
+ # "result": "206410760006650176"
3216
+ # }
3217
+ #
3218
+ # spot: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
3219
+ #
3220
+ # {
3221
+ # "symbol": "btc_usdt",
3222
+ # "orderId": "207505997850909952",
3223
+ # "clientOrderId": null,
3224
+ # "baseCurrency": "btc",
3225
+ # "quoteCurrency": "usdt",
3226
+ # "side": "BUY",
3227
+ # "type": "LIMIT",
3228
+ # "timeInForce": "GTC",
3229
+ # "price": "20000.00",
3230
+ # "origQty": "0.001000",
3231
+ # "origQuoteQty": "20.00",
3232
+ # "executedQty": "0.000000",
3233
+ # "leavingQty": "0.001000",
3234
+ # "tradeBase": "0.000000",
3235
+ # "tradeQuote": "0.00",
3236
+ # "avgPrice": null,
3237
+ # "fee": null,
3238
+ # "feeCurrency": null,
3239
+ # "closed": False,
3240
+ # "state": "NEW",
3241
+ # "time": 1679175285162,
3242
+ # "updatedTime": 1679175285255
3243
+ # }
3244
+ #
3245
+ # swap and future: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
3246
+ #
3247
+ # {
3248
+ # "orderId": "207519546930995456",
3249
+ # "clientOrderId": null,
3250
+ # "symbol": "btc_usdt",
3251
+ # "orderType": "LIMIT",
3252
+ # "orderSide": "BUY",
3253
+ # "positionSide": "LONG",
3254
+ # "timeInForce": "GTC",
3255
+ # "closePosition": False,
3256
+ # "price": "20000",
3257
+ # "origQty": "100",
3258
+ # "avgPrice": "0",
3259
+ # "executedQty": "0",
3260
+ # "marginFrozen": "4.12",
3261
+ # "remark": null,
3262
+ # "triggerProfitPrice": null,
3263
+ # "triggerStopPrice": null,
3264
+ # "sourceId": null,
3265
+ # "sourceType": "DEFAULT",
3266
+ # "forceClose": False,
3267
+ # "closeProfit": null,
3268
+ # "state": "CANCELED",
3269
+ # "createdTime": 1679178515689,
3270
+ # "updatedTime": 1679180096172
3271
+ # }
3272
+ #
3273
+ # trigger: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
3274
+ #
3275
+ # {
3276
+ # "entrustId": "216300248132756992",
3277
+ # "symbol": "btc_usdt",
3278
+ # "entrustType": "STOP",
3279
+ # "orderSide": "SELL",
3280
+ # "positionSide": "SHORT",
3281
+ # "timeInForce": "GTC",
3282
+ # "closePosition": null,
3283
+ # "price": "20000",
3284
+ # "origQty": "1",
3285
+ # "stopPrice": "19000",
3286
+ # "triggerPriceType": "LATEST_PRICE",
3287
+ # "state": "NOT_TRIGGERED",
3288
+ # "marketOrderLevel": null,
3289
+ # "createdTime": 1681271998064,
3290
+ # "updatedTime": 1681271998064,
3291
+ # "ordinary": False
3292
+ # }
3293
+ #
3294
+ # stop-loss and take-profit: fetchOrder, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
3295
+ #
3296
+ # {
3297
+ # "profitId": "216306213226230400",
3298
+ # "symbol": "btc_usdt",
3299
+ # "positionSide": "LONG",
3300
+ # "origQty": "1",
3301
+ # "triggerPriceType": "LATEST_PRICE",
3302
+ # "triggerProfitPrice": null,
3303
+ # "triggerStopPrice": "20000",
3304
+ # "entryPrice": null,
3305
+ # "positionSize": null,
3306
+ # "isolatedMargin": null,
3307
+ # "executedQty": null,
3308
+ # "avgPrice": null,
3309
+ # "positionType": "ISOLATED",
3310
+ # "state": "NOT_TRIGGERED",
3311
+ # "createdTime": 1681273420039
3312
+ # }
3313
+ #
3314
+ marketId = self.safe_string(order, 'symbol')
3315
+ marketType = ('result' in order) or 'contract' if ('positionSide' in order) else 'spot'
3316
+ market = self.safe_market(marketId, market, None, marketType)
3317
+ symbol = self.safe_symbol(marketId, market, None, marketType)
3318
+ timestamp = self.safe_integer_2(order, 'time', 'createdTime')
3319
+ quantity = self.safe_number(order, 'origQty')
3320
+ amount = quantity if (marketType == 'spot') else Precise.string_mul(self.number_to_string(quantity), self.number_to_string(market['contractSize']))
3321
+ filledQuantity = self.safe_number(order, 'executedQty')
3322
+ filled = filledQuantity if (marketType == 'spot') else Precise.string_mul(self.number_to_string(filledQuantity), self.number_to_string(market['contractSize']))
3323
+ lastUpdatedTimestamp = self.safe_integer(order, 'updatedTime')
3324
+ return self.safe_order({
3325
+ 'info': order,
3326
+ 'id': self.safe_string_n(order, ['orderId', 'result', 'cancelId', 'entrustId', 'profitId']),
3327
+ 'clientOrderId': self.safe_string(order, 'clientOrderId'),
3328
+ 'timestamp': timestamp,
3329
+ 'datetime': self.iso8601(timestamp),
3330
+ 'lastTradeTimestamp': lastUpdatedTimestamp,
3331
+ 'lastUpdateTimestamp': lastUpdatedTimestamp,
3332
+ 'symbol': symbol,
3333
+ 'type': self.safe_string_lower_2(order, 'type', 'orderType'),
3334
+ 'timeInForce': self.safe_string(order, 'timeInForce'),
3335
+ 'postOnly': None,
3336
+ 'side': self.safe_string_lower_2(order, 'side', 'orderSide'),
3337
+ 'price': self.safe_number(order, 'price'),
3338
+ 'triggerPrice': self.safe_number(order, 'stopPrice'),
3339
+ 'stopLoss': self.safe_number(order, 'triggerStopPrice'),
3340
+ 'takeProfit': self.safe_number(order, 'triggerProfitPrice'),
3341
+ 'amount': amount,
3342
+ 'filled': filled,
3343
+ 'remaining': self.safe_number(order, 'leavingQty'),
3344
+ 'cost': None,
3345
+ 'average': self.safe_number(order, 'avgPrice'),
3346
+ 'status': self.parse_order_status(self.safe_string(order, 'state')),
3347
+ 'fee': {
3348
+ 'currency': self.safe_currency_code(self.safe_string(order, 'feeCurrency')),
3349
+ 'cost': self.safe_number(order, 'fee'),
3350
+ },
3351
+ 'trades': None,
3352
+ }, market)
3353
+
3354
+ def parse_order_status(self, status):
3355
+ statuses = {
3356
+ 'NEW': 'open',
3357
+ 'PARTIALLY_FILLED': 'open',
3358
+ 'FILLED': 'closed',
3359
+ 'CANCELED': 'canceled',
3360
+ 'REJECTED': 'rejected',
3361
+ 'EXPIRED': 'expired',
3362
+ 'UNFINISHED': 'open',
3363
+ 'NOT_TRIGGERED': 'open',
3364
+ 'TRIGGERING': 'open',
3365
+ 'TRIGGERED': 'closed',
3366
+ 'USER_REVOCATION': 'canceled',
3367
+ 'PLATFORM_REVOCATION': 'rejected',
3368
+ 'HISTORY': 'expired',
3369
+ }
3370
+ return self.safe_string(statuses, status, status)
3371
+
3372
+ async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
3373
+ """
3374
+ fetch the history of changes, actions done by the user or operations that altered the balance of the user
3375
+
3376
+ https://doc.xt.com/#futures_usergetBalanceBill
3377
+
3378
+ :param str [code]: unified currency code
3379
+ :param int [since]: timestamp in ms of the earliest ledger entry
3380
+ :param int [limit]: max number of ledger entries to return
3381
+ :param dict params: extra parameters specific to the xt api endpoint
3382
+ :returns dict: a `ledger structure <https://docs.ccxt.com/en/latest/manual.html#ledger-structure>`
3383
+ """
3384
+ await self.load_markets()
3385
+ request = {}
3386
+ currency = None
3387
+ if code is not None:
3388
+ currency = self.currency(code)
3389
+ if since is not None:
3390
+ request['startTime'] = since
3391
+ if limit is not None:
3392
+ request['limit'] = limit
3393
+ type = None
3394
+ subType = None
3395
+ response = None
3396
+ type, params = self.handle_market_type_and_params('fetchLedger', None, params)
3397
+ subType, params = self.handle_sub_type_and_params('fetchLedger', None, params)
3398
+ if subType == 'inverse':
3399
+ response = await self.privateInverseGetFutureUserV1BalanceBills(self.extend(request, params))
3400
+ elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
3401
+ response = await self.privateLinearGetFutureUserV1BalanceBills(self.extend(request, params))
3402
+ else:
3403
+ raise NotSupported(self.id + ' fetchLedger() does not support spot transactions, only swap and future wallet transactions are supported')
3404
+ #
3405
+ # {
3406
+ # "returnCode": 0,
3407
+ # "msgInfo": "success",
3408
+ # "error": null,
3409
+ # "result": {
3410
+ # "hasPrev": False,
3411
+ # "hasNext": False,
3412
+ # "items": [
3413
+ # {
3414
+ # "id": "207260567109387524",
3415
+ # "coin": "usdt",
3416
+ # "symbol": "btc_usdt",
3417
+ # "type": "FEE",
3418
+ # "amount": "-0.0213",
3419
+ # "side": "SUB",
3420
+ # "afterAmount": null,
3421
+ # "createdTime": 1679116769914
3422
+ # },
3423
+ # ]
3424
+ # }
3425
+ # }
3426
+ #
3427
+ data = self.safe_value(response, 'result', {})
3428
+ ledger = self.safe_value(data, 'items', [])
3429
+ return self.parse_ledger(ledger, currency, since, limit)
3430
+
3431
+ def parse_ledger_entry(self, item, currency=None) -> LedgerEntry:
3432
+ #
3433
+ # {
3434
+ # "id": "207260567109387524",
3435
+ # "coin": "usdt",
3436
+ # "symbol": "btc_usdt",
3437
+ # "type": "FEE",
3438
+ # "amount": "-0.0213",
3439
+ # "side": "SUB",
3440
+ # "afterAmount": null,
3441
+ # "createdTime": 1679116769914
3442
+ # }
3443
+ #
3444
+ side = self.safe_string(item, 'side')
3445
+ direction = 'in' if (side == 'ADD') else 'out'
3446
+ currencyId = self.safe_string(item, 'coin')
3447
+ currency = self.safe_currency(currencyId, currency)
3448
+ timestamp = self.safe_integer(item, 'createdTime')
3449
+ return self.safe_ledger_entry({
3450
+ 'info': item,
3451
+ 'id': self.safe_string(item, 'id'),
3452
+ 'direction': direction,
3453
+ 'account': None,
3454
+ 'referenceId': None,
3455
+ 'referenceAccount': None,
3456
+ 'type': self.parse_ledger_entry_type(self.safe_string(item, 'type')),
3457
+ 'currency': self.safe_currency_code(currencyId, currency),
3458
+ 'amount': self.safe_number(item, 'amount'),
3459
+ 'timestamp': timestamp,
3460
+ 'datetime': self.iso8601(timestamp),
3461
+ 'before': None,
3462
+ 'after': self.safe_number(item, 'afterAmount'),
3463
+ 'status': None,
3464
+ 'fee': {
3465
+ 'currency': None,
3466
+ 'cost': None,
3467
+ },
3468
+ }, currency)
3469
+
3470
+ def parse_ledger_entry_type(self, type):
3471
+ ledgerType = {
3472
+ 'EXCHANGE': 'transfer',
3473
+ 'CLOSE_POSITION': 'trade',
3474
+ 'TAKE_OVER': 'trade',
3475
+ 'MERGE': 'trade',
3476
+ 'QIANG_PING_MANAGER': 'fee',
3477
+ 'FUND': 'fee',
3478
+ 'FEE': 'fee',
3479
+ 'ADL': 'auto-deleveraging',
3480
+ }
3481
+ return self.safe_string(ledgerType, type, type)
3482
+
3483
+ async def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
3484
+ """
3485
+ fetch the deposit address for a currency associated with self account
3486
+
3487
+ https://doc.xt.com/#deposit_withdrawaldepositAddressGet
3488
+
3489
+ :param str code: unified currency code
3490
+ :param dict params: extra parameters specific to the xt api endpoint
3491
+ :param str params['network']: required network id
3492
+ :returns dict: an `address structure <https://docs.ccxt.com/en/latest/manual.html#address-structure>`
3493
+ """
3494
+ await self.load_markets()
3495
+ networkCode = None
3496
+ networkCode, params = self.handle_network_code_and_params(params)
3497
+ currency = self.currency(code)
3498
+ networkId = self.network_code_to_id(networkCode, code)
3499
+ self.check_required_argument('fetchDepositAddress', networkId, 'network')
3500
+ request = {
3501
+ 'currency': currency['id'],
3502
+ 'chain': networkId,
3503
+ }
3504
+ response = await self.privateSpotGetDepositAddress(self.extend(request, params))
3505
+ #
3506
+ # {
3507
+ # "rc": 0,
3508
+ # "mc": "SUCCESS",
3509
+ # "ma": [],
3510
+ # "result": {
3511
+ # "address": "0x7f7173cf29d3846d20ca5a3aec1120b93dbd157a",
3512
+ # "memo": ""
3513
+ # }
3514
+ # }
3515
+ #
3516
+ result = self.safe_value(response, 'result', {})
3517
+ return self.parse_deposit_address(result, currency)
3518
+
3519
+ def parse_deposit_address(self, depositAddress, currency=None) -> DepositAddress:
3520
+ #
3521
+ # {
3522
+ # "address": "0x7f7173cf29d3846d20ca5a3aec1120b93dbd157a",
3523
+ # "memo": ""
3524
+ # }
3525
+ #
3526
+ address = self.safe_string(depositAddress, 'address')
3527
+ self.check_address(address)
3528
+ return {
3529
+ 'info': depositAddress,
3530
+ 'currency': self.safe_currency_code(None, currency),
3531
+ 'network': None,
3532
+ 'address': address,
3533
+ 'tag': self.safe_string(depositAddress, 'memo'),
3534
+ }
3535
+
3536
+ async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
3537
+ """
3538
+ fetch all deposits made to an account
3539
+
3540
+ https://doc.xt.com/#deposit_withdrawalhistoryDepositGet
3541
+
3542
+ :param str [code]: unified currency code
3543
+ :param int [since]: the earliest time in ms to fetch deposits for
3544
+ :param int [limit]: the maximum number of transaction structures to retrieve
3545
+ :param dict params: extra parameters specific to the xt api endpoint
3546
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
3547
+ """
3548
+ await self.load_markets()
3549
+ request = {}
3550
+ currency = None
3551
+ if code is not None:
3552
+ currency = self.currency(code)
3553
+ request['currency'] = currency['id']
3554
+ if since is not None:
3555
+ request['startTime'] = since
3556
+ if limit is not None:
3557
+ request['limit'] = limit # default 10, max 200
3558
+ response = await self.privateSpotGetDepositHistory(self.extend(request, params))
3559
+ #
3560
+ # {
3561
+ # "rc": 0,
3562
+ # "mc": "SUCCESS",
3563
+ # "ma": [],
3564
+ # "result": {
3565
+ # "hasPrev": False,
3566
+ # "hasNext": False,
3567
+ # "items": [
3568
+ # {
3569
+ # "id": 170368702,
3570
+ # "currency": "usdt",
3571
+ # "chain": "Ethereum",
3572
+ # "memo": "",
3573
+ # "status": "SUCCESS",
3574
+ # "amount": "31.792528",
3575
+ # "confirmations": 12,
3576
+ # "transactionId": "0x90b8487c258b81b85e15e461b1839c49d4d8e6e9de4c1adb658cd47d4f5c5321",
3577
+ # "address": "0x7f7172cf29d3846d30ca5a3aec1120b92dbd150b",
3578
+ # "fromAddr": "0x7830c87c02e56aff27fa9ab1241711331fa86f58",
3579
+ # "createdTime": 1678491442000
3580
+ # },
3581
+ # ]
3582
+ # }
3583
+ # }
3584
+ #
3585
+ data = self.safe_value(response, 'result', {})
3586
+ deposits = self.safe_value(data, 'items', [])
3587
+ return self.parse_transactions(deposits, currency, since, limit, params)
3588
+
3589
+ async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
3590
+ """
3591
+ fetch all withdrawals made from an account
3592
+
3593
+ https://doc.xt.com/#deposit_withdrawalwithdrawHistory
3594
+
3595
+ :param str [code]: unified currency code
3596
+ :param int [since]: the earliest time in ms to fetch withdrawals for
3597
+ :param int [limit]: the maximum number of transaction structures to retrieve
3598
+ :param dict params: extra parameters specific to the xt api endpoint
3599
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
3600
+ """
3601
+ await self.load_markets()
3602
+ request = {}
3603
+ currency = None
3604
+ if code is not None:
3605
+ currency = self.currency(code)
3606
+ request['currency'] = currency['id']
3607
+ if since is not None:
3608
+ request['startTime'] = since
3609
+ if limit is not None:
3610
+ request['limit'] = limit # default 10, max 200
3611
+ response = await self.privateSpotGetWithdrawHistory(self.extend(request, params))
3612
+ #
3613
+ # {
3614
+ # "rc": 0,
3615
+ # "mc": "SUCCESS",
3616
+ # "ma": [],
3617
+ # "result": {
3618
+ # "hasPrev": False,
3619
+ # "hasNext": False,
3620
+ # "items": [
3621
+ # {
3622
+ # "id": 950898,
3623
+ # "currency": "usdt",
3624
+ # "chain": "Tron",
3625
+ # "address": "TGB2vxTjiqraVZBy7YHXF8V3CSMVhQKcaf",
3626
+ # "memo": "",
3627
+ # "status": "SUCCESS",
3628
+ # "amount": "5",
3629
+ # "fee": "2",
3630
+ # "confirmations": 6,
3631
+ # "transactionId": "c36e230b879842b1d7afd19d15ee1a866e26eaa0626e367d6f545d2932a15156",
3632
+ # "createdTime": 1680049062000
3633
+ # }
3634
+ # ]
3635
+ # }
3636
+ # }
3637
+ #
3638
+ data = self.safe_value(response, 'result', {})
3639
+ withdrawals = self.safe_value(data, 'items', [])
3640
+ return self.parse_transactions(withdrawals, currency, since, limit, params)
3641
+
3642
+ async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}) -> Transaction:
3643
+ """
3644
+ make a withdrawal
3645
+
3646
+ https://doc.xt.com/#deposit_withdrawalwithdraw
3647
+
3648
+ :param str code: unified currency code
3649
+ :param float amount: the amount to withdraw
3650
+ :param str address: the address to withdraw to
3651
+ :param str [tag]:
3652
+ :param dict params: extra parameters specific to the xt api endpoint
3653
+ :returns dict: a `transaction structure <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
3654
+ """
3655
+ self.check_address(address)
3656
+ await self.load_markets()
3657
+ currency = self.currency(code)
3658
+ tag, params = self.handle_withdraw_tag_and_params(tag, params)
3659
+ networkCode = None
3660
+ networkCode, params = self.handle_network_code_and_params(params)
3661
+ networkIdsByCodes = self.safe_value(self.options, 'networks', {})
3662
+ networkId = self.safe_string_2(networkIdsByCodes, networkCode, code, code)
3663
+ request = {
3664
+ 'currency': currency['id'],
3665
+ 'chain': networkId,
3666
+ 'amount': self.currency_to_precision(code, amount),
3667
+ 'address': address,
3668
+ }
3669
+ if tag is not None:
3670
+ request['memo'] = tag
3671
+ response = await self.privateSpotPostWithdraw(self.extend(request, params))
3672
+ #
3673
+ # {
3674
+ # "rc": 0,
3675
+ # "mc": "SUCCESS",
3676
+ # "ma": [],
3677
+ # "result": {
3678
+ # "id": 950898
3679
+ # }
3680
+ # }
3681
+ #
3682
+ result = self.safe_value(response, 'result', {})
3683
+ return self.parse_transaction(result, currency)
3684
+
3685
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
3686
+ #
3687
+ # fetchDeposits
3688
+ #
3689
+ # {
3690
+ # "id": 170368702,
3691
+ # "currency": "usdt",
3692
+ # "chain": "Ethereum",
3693
+ # "memo": "",
3694
+ # "status": "SUCCESS",
3695
+ # "amount": "31.792528",
3696
+ # "confirmations": 12,
3697
+ # "transactionId": "0x90b8487c258b81b85e15e461b1839c49d4d8e6e9de4c1adb658cd47d4f5c5321",
3698
+ # "address": "0x7f7172cf29d3846d30ca5a3aec1120b92dbd150b",
3699
+ # "fromAddr": "0x7830c87c02e56aff27fa9ab1241711331fa86f58",
3700
+ # "createdTime": 1678491442000
3701
+ # }
3702
+ #
3703
+ # fetchWithdrawals
3704
+ #
3705
+ # {
3706
+ # "id": 950898,
3707
+ # "currency": "usdt",
3708
+ # "chain": "Tron",
3709
+ # "address": "TGB2vxTjiqraVZBy7YHXF8V3CSMVhQKcaf",
3710
+ # "memo": "",
3711
+ # "status": "SUCCESS",
3712
+ # "amount": "5",
3713
+ # "fee": "2",
3714
+ # "confirmations": 6,
3715
+ # "transactionId": "c36e230b879842b1d7afd19d15ee1a866e26eaa0626e367d6f545d2932a15156",
3716
+ # "createdTime": 1680049062000
3717
+ # }
3718
+ #
3719
+ # withdraw
3720
+ #
3721
+ # {
3722
+ # "id": 950898
3723
+ # }
3724
+ #
3725
+ type = 'deposit' if ('fromAddr' in transaction) else 'withdraw'
3726
+ timestamp = self.safe_integer(transaction, 'createdTime')
3727
+ address = self.safe_string(transaction, 'address')
3728
+ memo = self.safe_string(transaction, 'memo')
3729
+ currencyCode = self.safe_currency_code(self.safe_string(transaction, 'currency'), currency)
3730
+ fee = self.safe_number(transaction, 'fee')
3731
+ feeCurrency = currencyCode if (fee is not None) else None
3732
+ networkId = self.safe_string(transaction, 'chain')
3733
+ return {
3734
+ 'info': transaction,
3735
+ 'id': self.safe_string(transaction, 'id'),
3736
+ 'txid': self.safe_string(transaction, 'transactionId'),
3737
+ 'timestamp': timestamp,
3738
+ 'datetime': self.iso8601(timestamp),
3739
+ 'updated': None,
3740
+ 'addressFrom': self.safe_string(transaction, 'fromAddr'),
3741
+ 'addressTo': address,
3742
+ 'address': address,
3743
+ 'tagFrom': None,
3744
+ 'tagTo': None,
3745
+ 'tag': memo,
3746
+ 'type': type,
3747
+ 'amount': self.safe_number(transaction, 'amount'),
3748
+ 'currency': currencyCode,
3749
+ 'network': self.network_id_to_code(networkId, currencyCode),
3750
+ 'status': self.parse_transaction_status(self.safe_string(transaction, 'status')),
3751
+ 'comment': memo,
3752
+ 'fee': {
3753
+ 'currency': feeCurrency,
3754
+ 'cost': fee,
3755
+ 'rate': None,
3756
+ },
3757
+ 'internal': None,
3758
+ }
3759
+
3760
+ def parse_transaction_status(self, status):
3761
+ statuses = {
3762
+ 'SUBMIT': 'pending',
3763
+ 'REVIEW': 'pending',
3764
+ 'AUDITED': 'pending',
3765
+ 'PENDING': 'pending',
3766
+ 'CANCEL': 'canceled',
3767
+ 'FAIL': 'failed',
3768
+ 'SUCCESS': 'ok',
3769
+ }
3770
+ return self.safe_string(statuses, status, status)
3771
+
3772
+ async def set_leverage(self, leverage: Int, symbol: str = None, params={}):
3773
+ """
3774
+ set the level of leverage for a market
3775
+
3776
+ https://doc.xt.com/#futures_useradjustLeverage
3777
+
3778
+ :param float leverage: the rate of leverage
3779
+ :param str symbol: unified market symbol
3780
+ :param dict params: extra parameters specific to the xt api endpoint
3781
+ :param str params['positionSide']: 'LONG' or 'SHORT'
3782
+ :returns dict: response from the exchange
3783
+ """
3784
+ if symbol is None:
3785
+ raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
3786
+ positionSide = self.safe_string(params, 'positionSide')
3787
+ self.check_required_argument('setLeverage', positionSide, 'positionSide', ['LONG', 'SHORT'])
3788
+ if (leverage < 1) or (leverage > 125):
3789
+ raise BadRequest(self.id + ' setLeverage() leverage should be between 1 and 125')
3790
+ await self.load_markets()
3791
+ market = self.market(symbol)
3792
+ if not (market['contract']):
3793
+ raise BadSymbol(self.id + ' setLeverage() supports contract markets only')
3794
+ request = {
3795
+ 'symbol': market['id'],
3796
+ 'positionSide': positionSide,
3797
+ 'leverage': leverage,
3798
+ }
3799
+ subType = None
3800
+ subType, params = self.handle_sub_type_and_params('setLeverage', market, params)
3801
+ response = None
3802
+ if subType == 'inverse':
3803
+ response = await self.privateInversePostFutureUserV1PositionAdjustLeverage(self.extend(request, params))
3804
+ else:
3805
+ response = await self.privateLinearPostFutureUserV1PositionAdjustLeverage(self.extend(request, params))
3806
+ #
3807
+ # {
3808
+ # "returnCode": 0,
3809
+ # "msgInfo": "success",
3810
+ # "error": null,
3811
+ # "result": null
3812
+ # }
3813
+ #
3814
+ return response
3815
+
3816
+ async def add_margin(self, symbol: str, amount: float, params={}):
3817
+ """
3818
+ add margin to a position
3819
+
3820
+ https://doc.xt.com/#futures_useradjustMargin
3821
+
3822
+ :param str symbol: unified market symbol
3823
+ :param float amount: amount of margin to add
3824
+ :param dict params: extra parameters specific to the xt api endpoint
3825
+ :param str params['positionSide']: 'LONG' or 'SHORT'
3826
+ :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=add-margin-structure>`
3827
+ """
3828
+ return await self.modify_margin_helper(symbol, amount, 'ADD', params)
3829
+
3830
+ async def reduce_margin(self, symbol: str, amount: float, params={}):
3831
+ """
3832
+ remove margin from a position
3833
+
3834
+ https://doc.xt.com/#futures_useradjustMargin
3835
+
3836
+ :param str symbol: unified market symbol
3837
+ :param float amount: the amount of margin to remove
3838
+ :param dict params: extra parameters specific to the xt api endpoint
3839
+ :param str params['positionSide']: 'LONG' or 'SHORT'
3840
+ :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=reduce-margin-structure>`
3841
+ """
3842
+ return await self.modify_margin_helper(symbol, amount, 'SUB', params)
3843
+
3844
+ async def modify_margin_helper(self, symbol: str, amount, addOrReduce, params={}) -> MarginModification:
3845
+ positionSide = self.safe_string(params, 'positionSide')
3846
+ self.check_required_argument('setLeverage', positionSide, 'positionSide', ['LONG', 'SHORT'])
3847
+ await self.load_markets()
3848
+ market = self.market(symbol)
3849
+ request = {
3850
+ 'symbol': market['id'],
3851
+ 'margin': amount,
3852
+ 'type': addOrReduce,
3853
+ 'positionSide': positionSide,
3854
+ }
3855
+ subType = None
3856
+ subType, params = self.handle_sub_type_and_params('modifyMarginHelper', market, params)
3857
+ response = None
3858
+ if subType == 'inverse':
3859
+ response = await self.privateInversePostFutureUserV1PositionMargin(self.extend(request, params))
3860
+ else:
3861
+ response = await self.privateLinearPostFutureUserV1PositionMargin(self.extend(request, params))
3862
+ #
3863
+ # {
3864
+ # "returnCode": 0,
3865
+ # "msgInfo": "success",
3866
+ # "error": null,
3867
+ # "result": null
3868
+ # }
3869
+ #
3870
+ return self.parse_margin_modification(response, market)
3871
+
3872
+ def parse_margin_modification(self, data, market=None) -> MarginModification:
3873
+ return {
3874
+ 'info': data,
3875
+ 'type': None,
3876
+ 'amount': None,
3877
+ 'code': None,
3878
+ 'symbol': self.safe_symbol(None, market),
3879
+ 'status': None,
3880
+ 'marginMode': None,
3881
+ 'total': None,
3882
+ 'timestamp': None,
3883
+ 'datetime': None,
3884
+ }
3885
+
3886
+ async def fetch_leverage_tiers(self, symbols: List[str] = None, params={}) -> LeverageTiers:
3887
+ """
3888
+ retrieve information on the maximum leverage for different trade sizes
3889
+
3890
+ https://doc.xt.com/#futures_quotesgetLeverageBrackets
3891
+
3892
+ :param str [symbols]: a list of unified market symbols
3893
+ :param dict params: extra parameters specific to the xt api endpoint
3894
+ :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`
3895
+ """
3896
+ await self.load_markets()
3897
+ subType = None
3898
+ subType, params = self.handle_sub_type_and_params('fetchLeverageTiers', None, params)
3899
+ response = None
3900
+ if subType == 'inverse':
3901
+ response = await self.publicInverseGetFutureMarketV1PublicLeverageBracketList(params)
3902
+ else:
3903
+ response = await self.publicLinearGetFutureMarketV1PublicLeverageBracketList(params)
3904
+ #
3905
+ # {
3906
+ # "returnCode": 0,
3907
+ # "msgInfo": "success",
3908
+ # "error": null,
3909
+ # "result": [
3910
+ # {
3911
+ # "symbol": "rad_usdt",
3912
+ # "leverageBrackets": [
3913
+ # {
3914
+ # "symbol": "rad_usdt",
3915
+ # "bracket": 1,
3916
+ # "maxNominalValue": "5000",
3917
+ # "maintMarginRate": "0.025",
3918
+ # "startMarginRate": "0.05",
3919
+ # "maxStartMarginRate": null,
3920
+ # "maxLeverage": "20",
3921
+ # "minLeverage": "1"
3922
+ # },
3923
+ # ]
3924
+ # },
3925
+ # ]
3926
+ # }
3927
+ #
3928
+ data = self.safe_value(response, 'result', [])
3929
+ symbols = self.market_symbols(symbols)
3930
+ return self.parse_leverage_tiers(data, symbols, 'symbol')
3931
+
3932
+ def parse_leverage_tiers(self, response, symbols=None, marketIdKey=None) -> LeverageTiers:
3933
+ #
3934
+ # {
3935
+ # "symbol": "rad_usdt",
3936
+ # "leverageBrackets": [
3937
+ # {
3938
+ # "symbol": "rad_usdt",
3939
+ # "bracket": 1,
3940
+ # "maxNominalValue": "5000",
3941
+ # "maintMarginRate": "0.025",
3942
+ # "startMarginRate": "0.05",
3943
+ # "maxStartMarginRate": null,
3944
+ # "maxLeverage": "20",
3945
+ # "minLeverage": "1"
3946
+ # },
3947
+ # ]
3948
+ # }
3949
+ #
3950
+ result = {}
3951
+ for i in range(0, len(response)):
3952
+ entry = response[i]
3953
+ marketId = self.safe_string(entry, 'symbol')
3954
+ market = self.safe_market(marketId, None, '_', 'contract')
3955
+ symbol = self.safe_symbol(marketId, market)
3956
+ if symbols is not None:
3957
+ if self.in_array(symbol, symbols):
3958
+ result[symbol] = self.parse_market_leverage_tiers(entry, market)
3959
+ else:
3960
+ result[symbol] = self.parse_market_leverage_tiers(response[i], market)
3961
+ return result
3962
+
3963
+ async def fetch_market_leverage_tiers(self, symbol: str, params={}) -> List[LeverageTier]:
3964
+ """
3965
+ retrieve information on the maximum leverage for different trade sizes of a single market
3966
+
3967
+ https://doc.xt.com/#futures_quotesgetLeverageBracket
3968
+
3969
+ :param str symbol: unified market symbol
3970
+ :param dict params: extra parameters specific to the xt api endpoint
3971
+ :returns dict: a `leverage tiers structure <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`
3972
+ """
3973
+ await self.load_markets()
3974
+ market = self.market(symbol)
3975
+ request = {
3976
+ 'symbol': market['id'],
3977
+ }
3978
+ subType = None
3979
+ subType, params = self.handle_sub_type_and_params('fetchMarketLeverageTiers', market, params)
3980
+ response = None
3981
+ if subType == 'inverse':
3982
+ response = await self.publicInverseGetFutureMarketV1PublicLeverageBracketDetail(self.extend(request, params))
3983
+ else:
3984
+ response = await self.publicLinearGetFutureMarketV1PublicLeverageBracketDetail(self.extend(request, params))
3985
+ #
3986
+ # {
3987
+ # "returnCode": 0,
3988
+ # "msgInfo": "success",
3989
+ # "error": null,
3990
+ # "result": {
3991
+ # "symbol": "btc_usdt",
3992
+ # "leverageBrackets": [
3993
+ # {
3994
+ # "symbol": "btc_usdt",
3995
+ # "bracket": 1,
3996
+ # "maxNominalValue": "500000",
3997
+ # "maintMarginRate": "0.004",
3998
+ # "startMarginRate": "0.008",
3999
+ # "maxStartMarginRate": null,
4000
+ # "maxLeverage": "125",
4001
+ # "minLeverage": "1"
4002
+ # },
4003
+ # ]
4004
+ # }
4005
+ # }
4006
+ #
4007
+ data = self.safe_value(response, 'result', {})
4008
+ return self.parse_market_leverage_tiers(data, market)
4009
+
4010
+ def parse_market_leverage_tiers(self, info, market=None) -> List[LeverageTier]:
4011
+ #
4012
+ # {
4013
+ # "symbol": "rad_usdt",
4014
+ # "leverageBrackets": [
4015
+ # {
4016
+ # "symbol": "rad_usdt",
4017
+ # "bracket": 1,
4018
+ # "maxNominalValue": "5000",
4019
+ # "maintMarginRate": "0.025",
4020
+ # "startMarginRate": "0.05",
4021
+ # "maxStartMarginRate": null,
4022
+ # "maxLeverage": "20",
4023
+ # "minLeverage": "1"
4024
+ # },
4025
+ # ]
4026
+ # }
4027
+ #
4028
+ tiers = []
4029
+ brackets = self.safe_value(info, 'leverageBrackets', [])
4030
+ for i in range(0, len(brackets)):
4031
+ tier = brackets[i]
4032
+ marketId = self.safe_string(info, 'symbol')
4033
+ market = self.safe_market(marketId, market, '_', 'contract')
4034
+ tiers.append({
4035
+ 'tier': self.safe_integer(tier, 'bracket'),
4036
+ 'symbol': self.safe_symbol(marketId, market, '_', 'contract'),
4037
+ 'currency': market['settle'],
4038
+ 'minNotional': self.safe_number(brackets[i - 1], 'maxNominalValue', 0),
4039
+ 'maxNotional': self.safe_number(tier, 'maxNominalValue'),
4040
+ 'maintenanceMarginRate': self.safe_number(tier, 'maintMarginRate'),
4041
+ 'maxLeverage': self.safe_number(tier, 'maxLeverage'),
4042
+ 'info': tier,
4043
+ })
4044
+ return tiers
4045
+
4046
+ async def fetch_funding_rate_history(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
4047
+ """
4048
+ fetches historical funding rates
4049
+
4050
+ https://doc.xt.com/#futures_quotesgetFundingRateRecord
4051
+
4052
+ :param str [symbol]: unified symbol of the market to fetch the funding rate history for
4053
+ :param int [since]: timestamp in ms of the earliest funding rate to fetch
4054
+ :param int [limit]: the maximum amount of [funding rate structures] to fetch
4055
+ :param dict params: extra parameters specific to the xt api endpoint
4056
+ :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/en/latest/manual.html?#funding-rate-history-structure>`
4057
+ """
4058
+ if symbol is None:
4059
+ raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
4060
+ await self.load_markets()
4061
+ market = self.market(symbol)
4062
+ if not market['swap']:
4063
+ raise BadSymbol(self.id + ' fetchFundingRateHistory() supports swap contracts only')
4064
+ request = {
4065
+ 'symbol': market['id'],
4066
+ }
4067
+ if limit is not None:
4068
+ request['limit'] = limit
4069
+ subType = None
4070
+ subType, params = self.handle_sub_type_and_params('fetchFundingRateHistory', market, params)
4071
+ response = None
4072
+ if subType == 'inverse':
4073
+ response = await self.publicInverseGetFutureMarketV1PublicQFundingRateRecord(self.extend(request, params))
4074
+ else:
4075
+ response = await self.publicLinearGetFutureMarketV1PublicQFundingRateRecord(self.extend(request, params))
4076
+ #
4077
+ # {
4078
+ # "returnCode": 0,
4079
+ # "msgInfo": "success",
4080
+ # "error": null,
4081
+ # "result": {
4082
+ # "hasPrev": False,
4083
+ # "hasNext": True,
4084
+ # "items": [
4085
+ # {
4086
+ # "id": "210441653482221888",
4087
+ # "symbol": "btc_usdt",
4088
+ # "fundingRate": "0.000057",
4089
+ # "createdTime": 1679875200000,
4090
+ # "collectionInternal": 28800
4091
+ # },
4092
+ # ]
4093
+ # }
4094
+ # }
4095
+ #
4096
+ result = self.safe_value(response, 'result', {})
4097
+ items = self.safe_value(result, 'items', [])
4098
+ rates = []
4099
+ for i in range(0, len(items)):
4100
+ entry = items[i]
4101
+ marketId = self.safe_string(entry, 'symbol')
4102
+ symbolInner = self.safe_symbol(marketId, market)
4103
+ timestamp = self.safe_integer(entry, 'createdTime')
4104
+ rates.append({
4105
+ 'info': entry,
4106
+ 'symbol': symbolInner,
4107
+ 'fundingRate': self.safe_number(entry, 'fundingRate'),
4108
+ 'timestamp': timestamp,
4109
+ 'datetime': self.iso8601(timestamp),
4110
+ })
4111
+ sorted = self.sort_by(rates, 'timestamp')
4112
+ return self.filter_by_symbol_since_limit(sorted, market['symbol'], since, limit)
4113
+
4114
+ async def fetch_funding_interval(self, symbol: str, params={}) -> FundingRate:
4115
+ """
4116
+ fetch the current funding rate interval
4117
+
4118
+ https://doc.xt.com/#futures_quotesgetFundingRate
4119
+
4120
+ :param str symbol: unified market symbol
4121
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4122
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
4123
+ """
4124
+ return await self.fetch_funding_rate(symbol, params)
4125
+
4126
+ async def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
4127
+ """
4128
+ fetch the current funding rate
4129
+
4130
+ https://doc.xt.com/#futures_quotesgetFundingRate
4131
+
4132
+ :param str symbol: unified market symbol
4133
+ :param dict params: extra parameters specific to the xt api endpoint
4134
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
4135
+ """
4136
+ await self.load_markets()
4137
+ market = self.market(symbol)
4138
+ if not market['swap']:
4139
+ raise BadSymbol(self.id + ' fetchFundingRate() supports swap contracts only')
4140
+ request = {
4141
+ 'symbol': market['id'],
4142
+ }
4143
+ subType = None
4144
+ subType, params = self.handle_sub_type_and_params('fetchFundingRate', market, params)
4145
+ response = None
4146
+ if subType == 'inverse':
4147
+ response = await self.publicInverseGetFutureMarketV1PublicQFundingRate(self.extend(request, params))
4148
+ else:
4149
+ response = await self.publicLinearGetFutureMarketV1PublicQFundingRate(self.extend(request, params))
4150
+ #
4151
+ # {
4152
+ # "returnCode": 0,
4153
+ # "msgInfo": "success",
4154
+ # "error": null,
4155
+ # "result": {
4156
+ # "symbol": "btc_usdt",
4157
+ # "fundingRate": "0.000086",
4158
+ # "nextCollectionTime": 1680307200000,
4159
+ # "collectionInternal": 8
4160
+ # }
4161
+ # }
4162
+ #
4163
+ result = self.safe_value(response, 'result', {})
4164
+ return self.parse_funding_rate(result, market)
4165
+
4166
+ def parse_funding_rate(self, contract, market=None) -> FundingRate:
4167
+ #
4168
+ # {
4169
+ # "symbol": "btc_usdt",
4170
+ # "fundingRate": "0.000086",
4171
+ # "nextCollectionTime": 1680307200000,
4172
+ # "collectionInternal": 8
4173
+ # }
4174
+ #
4175
+ marketId = self.safe_string(contract, 'symbol')
4176
+ symbol = self.safe_symbol(marketId, market, '_', 'swap')
4177
+ timestamp = self.safe_integer(contract, 'nextCollectionTime')
4178
+ interval = self.safe_string(contract, 'collectionInternal')
4179
+ if interval is not None:
4180
+ interval = interval + 'h'
4181
+ return {
4182
+ 'info': contract,
4183
+ 'symbol': symbol,
4184
+ 'markPrice': None,
4185
+ 'indexPrice': None,
4186
+ 'interestRate': None,
4187
+ 'estimatedSettlePrice': None,
4188
+ 'timestamp': None,
4189
+ 'datetime': None,
4190
+ 'fundingRate': self.safe_number(contract, 'fundingRate'),
4191
+ 'fundingTimestamp': timestamp,
4192
+ 'fundingDatetime': self.iso8601(timestamp),
4193
+ 'nextFundingRate': None,
4194
+ 'nextFundingTimestamp': None,
4195
+ 'nextFundingDatetime': None,
4196
+ 'previousFundingRate': None,
4197
+ 'previousFundingTimestamp': None,
4198
+ 'previousFundingDatetime': None,
4199
+ 'interval': interval,
4200
+ }
4201
+
4202
+ async def fetch_funding_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
4203
+ """
4204
+ fetch the funding history
4205
+
4206
+ https://doc.xt.com/#futures_usergetFunding
4207
+
4208
+ :param str symbol: unified market symbol
4209
+ :param int [since]: the starting timestamp in milliseconds
4210
+ :param int [limit]: the number of entries to return
4211
+ :param dict params: extra parameters specific to the xt api endpoint
4212
+ :returns dict[]: a list of `funding history structures <https://docs.ccxt.com/#/?id=funding-history-structure>`
4213
+ """
4214
+ await self.load_markets()
4215
+ market = self.market(symbol)
4216
+ if not market['swap']:
4217
+ raise BadSymbol(self.id + ' fetchFundingHistory() supports swap contracts only')
4218
+ request = {
4219
+ 'symbol': market['id'],
4220
+ }
4221
+ if since is not None:
4222
+ request['startTime'] = since
4223
+ if limit is not None:
4224
+ request['limit'] = limit
4225
+ subType = None
4226
+ subType, params = self.handle_sub_type_and_params('fetchFundingHistory', market, params)
4227
+ response = None
4228
+ if subType == 'inverse':
4229
+ response = await self.privateInverseGetFutureUserV1BalanceFundingRateList(self.extend(request, params))
4230
+ else:
4231
+ response = await self.privateLinearGetFutureUserV1BalanceFundingRateList(self.extend(request, params))
4232
+ #
4233
+ # {
4234
+ # "returnCode": 0,
4235
+ # "msgInfo": "success",
4236
+ # "error": null,
4237
+ # "result": {
4238
+ # "hasPrev": False,
4239
+ # "hasNext": False,
4240
+ # "items": [
4241
+ # {
4242
+ # "id": "210804044057280512",
4243
+ # "symbol": "btc_usdt",
4244
+ # "cast": "-0.0013",
4245
+ # "coin": "usdt",
4246
+ # "positionSide": "SHORT",
4247
+ # "createdTime": 1679961600653
4248
+ # },
4249
+ # ]
4250
+ # }
4251
+ # }
4252
+ #
4253
+ data = self.safe_value(response, 'result', {})
4254
+ items = self.safe_value(data, 'items', [])
4255
+ result = []
4256
+ for i in range(0, len(items)):
4257
+ entry = items[i]
4258
+ result.append(self.parse_funding_history(entry, market))
4259
+ sorted = self.sort_by(result, 'timestamp')
4260
+ return self.filter_by_since_limit(sorted, since, limit)
4261
+
4262
+ def parse_funding_history(self, contract, market=None):
4263
+ #
4264
+ # {
4265
+ # "id": "210804044057280512",
4266
+ # "symbol": "btc_usdt",
4267
+ # "cast": "-0.0013",
4268
+ # "coin": "usdt",
4269
+ # "positionSide": "SHORT",
4270
+ # "createdTime": 1679961600653
4271
+ # }
4272
+ #
4273
+ marketId = self.safe_string(contract, 'symbol')
4274
+ symbol = self.safe_symbol(marketId, market, '_', 'swap')
4275
+ currencyId = self.safe_string(contract, 'coin')
4276
+ code = self.safe_currency_code(currencyId)
4277
+ timestamp = self.safe_integer(contract, 'createdTime')
4278
+ return {
4279
+ 'info': contract,
4280
+ 'symbol': symbol,
4281
+ 'code': code,
4282
+ 'timestamp': timestamp,
4283
+ 'datetime': self.iso8601(timestamp),
4284
+ 'id': self.safe_string(contract, 'id'),
4285
+ 'amount': self.safe_number(contract, 'cast'),
4286
+ }
4287
+
4288
+ async def fetch_position(self, symbol: str, params={}):
4289
+ """
4290
+ fetch data on a single open contract trade position
4291
+
4292
+ https://doc.xt.com/#futures_usergetPosition
4293
+
4294
+ :param str symbol: unified market symbol of the market the position is held in
4295
+ :param dict params: extra parameters specific to the xt api endpoint
4296
+ :returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
4297
+ """
4298
+ await self.load_markets()
4299
+ market = self.market(symbol)
4300
+ request = {
4301
+ 'symbol': market['id'],
4302
+ }
4303
+ subType = None
4304
+ subType, params = self.handle_sub_type_and_params('fetchPosition', market, params)
4305
+ response = None
4306
+ if subType == 'inverse':
4307
+ response = await self.privateInverseGetFutureUserV1PositionList(self.extend(request, params))
4308
+ else:
4309
+ response = await self.privateLinearGetFutureUserV1PositionList(self.extend(request, params))
4310
+ #
4311
+ # {
4312
+ # "returnCode": 0,
4313
+ # "msgInfo": "success",
4314
+ # "error": null,
4315
+ # "result": [
4316
+ # {
4317
+ # "symbol": "btc_usdt",
4318
+ # "positionType": "ISOLATED",
4319
+ # "positionSide": "SHORT",
4320
+ # "contractType": "PERPETUAL",
4321
+ # "positionSize": "10",
4322
+ # "closeOrderSize": "0",
4323
+ # "availableCloseSize": "10",
4324
+ # "entryPrice": "27060",
4325
+ # "openOrderSize": "0",
4326
+ # "isolatedMargin": "1.0824",
4327
+ # "openOrderMarginFrozen": "0",
4328
+ # "realizedProfit": "-0.00130138",
4329
+ # "autoMargin": False,
4330
+ # "leverage": 25
4331
+ # },
4332
+ # ]
4333
+ # }
4334
+ #
4335
+ positions = self.safe_value(response, 'result', [])
4336
+ for i in range(0, len(positions)):
4337
+ entry = positions[i]
4338
+ marketId = self.safe_string(entry, 'symbol')
4339
+ marketInner = self.safe_market(marketId, None, None, 'contract')
4340
+ positionSize = self.safe_string(entry, 'positionSize')
4341
+ if positionSize != '0':
4342
+ return self.parse_position(entry, marketInner)
4343
+ return None
4344
+
4345
+ async def fetch_positions(self, symbols: List[str] = None, params={}):
4346
+ """
4347
+ fetch all open positions
4348
+
4349
+ https://doc.xt.com/#futures_usergetPosition
4350
+
4351
+ :param str [symbols]: list of unified market symbols, not supported with xt
4352
+ :param dict params: extra parameters specific to the xt api endpoint
4353
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
4354
+ """
4355
+ await self.load_markets()
4356
+ subType = None
4357
+ subType, params = self.handle_sub_type_and_params('fetchPositions', None, params)
4358
+ response = None
4359
+ if subType == 'inverse':
4360
+ response = await self.privateInverseGetFutureUserV1PositionList(params)
4361
+ else:
4362
+ response = await self.privateLinearGetFutureUserV1PositionList(params)
4363
+ #
4364
+ # {
4365
+ # "returnCode": 0,
4366
+ # "msgInfo": "success",
4367
+ # "error": null,
4368
+ # "result": [
4369
+ # {
4370
+ # "symbol": "btc_usdt",
4371
+ # "positionType": "ISOLATED",
4372
+ # "positionSide": "SHORT",
4373
+ # "contractType": "PERPETUAL",
4374
+ # "positionSize": "10",
4375
+ # "closeOrderSize": "0",
4376
+ # "availableCloseSize": "10",
4377
+ # "entryPrice": "27060",
4378
+ # "openOrderSize": "0",
4379
+ # "isolatedMargin": "1.0824",
4380
+ # "openOrderMarginFrozen": "0",
4381
+ # "realizedProfit": "-0.00130138",
4382
+ # "autoMargin": False,
4383
+ # "leverage": 25
4384
+ # },
4385
+ # ]
4386
+ # }
4387
+ #
4388
+ positions = self.safe_value(response, 'result', [])
4389
+ result = []
4390
+ for i in range(0, len(positions)):
4391
+ entry = positions[i]
4392
+ marketId = self.safe_string(entry, 'symbol')
4393
+ marketInner = self.safe_market(marketId, None, None, 'contract')
4394
+ result.append(self.parse_position(entry, marketInner))
4395
+ return self.filter_by_array_positions(result, 'symbol', symbols, False)
4396
+
4397
+ def parse_position(self, position, market=None):
4398
+ #
4399
+ # {
4400
+ # "symbol": "btc_usdt",
4401
+ # "positionType": "ISOLATED",
4402
+ # "positionSide": "SHORT",
4403
+ # "contractType": "PERPETUAL",
4404
+ # "positionSize": "10",
4405
+ # "closeOrderSize": "0",
4406
+ # "availableCloseSize": "10",
4407
+ # "entryPrice": "27060",
4408
+ # "openOrderSize": "0",
4409
+ # "isolatedMargin": "1.0824",
4410
+ # "openOrderMarginFrozen": "0",
4411
+ # "realizedProfit": "-0.00130138",
4412
+ # "autoMargin": False,
4413
+ # "leverage": 25
4414
+ # }
4415
+ #
4416
+ marketId = self.safe_string(position, 'symbol')
4417
+ market = self.safe_market(marketId, market, None, 'contract')
4418
+ symbol = self.safe_symbol(marketId, market, None, 'contract')
4419
+ positionType = self.safe_string(position, 'positionType')
4420
+ marginMode = 'cross' if (positionType == 'CROSSED') else 'isolated'
4421
+ collateral = self.safe_number(position, 'isolatedMargin')
4422
+ return self.safe_position({
4423
+ 'info': position,
4424
+ 'id': None,
4425
+ 'symbol': symbol,
4426
+ 'timestamp': None,
4427
+ 'datetime': None,
4428
+ 'hedged': None,
4429
+ 'side': self.safe_string_lower(position, 'positionSide'),
4430
+ 'contracts': self.safe_number(position, 'positionSize'),
4431
+ 'contractSize': market['contractSize'],
4432
+ 'entryPrice': self.safe_number(position, 'entryPrice'),
4433
+ 'markPrice': None,
4434
+ 'notional': None,
4435
+ 'leverage': self.safe_integer(position, 'leverage'),
4436
+ 'collateral': collateral,
4437
+ 'initialMargin': collateral,
4438
+ 'maintenanceMargin': None,
4439
+ 'initialMarginPercentage': None,
4440
+ 'maintenanceMarginPercentage': None,
4441
+ 'unrealizedPnl': None,
4442
+ 'liquidationPrice': None,
4443
+ 'marginMode': marginMode,
4444
+ 'percentage': None,
4445
+ 'marginRatio': None,
4446
+ })
4447
+
4448
+ async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
4449
+ """
4450
+ transfer currency internally between wallets on the same account
4451
+
4452
+ https://doc.xt.com/#transfersubTransferPost
4453
+
4454
+ :param str code: unified currency code
4455
+ :param float amount: amount to transfer
4456
+ :param str fromAccount: account to transfer from - spot, swap, leverage, finance
4457
+ :param str toAccount: account to transfer to - spot, swap, leverage, finance
4458
+ :param dict params: extra parameters specific to the whitebit api endpoint
4459
+ :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
4460
+ """
4461
+ await self.load_markets()
4462
+ currency = self.currency(code)
4463
+ accountsByType = self.safe_value(self.options, 'accountsById')
4464
+ fromAccountId = self.safe_string(accountsByType, fromAccount, fromAccount)
4465
+ toAccountId = self.safe_string(accountsByType, toAccount, toAccount)
4466
+ amountString = self.currency_to_precision(code, amount)
4467
+ request = {
4468
+ 'bizId': self.uuid(),
4469
+ 'currency': currency['id'],
4470
+ 'amount': amountString,
4471
+ 'from': fromAccountId,
4472
+ 'to': toAccountId,
4473
+ }
4474
+ response = await self.privateSpotPostBalanceTransfer(self.extend(request, params))
4475
+ #
4476
+ # {
4477
+ # info: {rc: '0', mc: 'SUCCESS', ma: [], result: '226971333791398656'},
4478
+ # id: '226971333791398656',
4479
+ # timestamp: None,
4480
+ # datetime: None,
4481
+ # currency: None,
4482
+ # amount: None,
4483
+ # fromAccount: None,
4484
+ # toAccount: None,
4485
+ # status: None
4486
+ # }
4487
+ #
4488
+ return self.parse_transfer(response, currency)
4489
+
4490
+ def parse_transfer(self, transfer, currency=None):
4491
+ return {
4492
+ 'info': transfer,
4493
+ 'id': self.safe_string(transfer, 'result'),
4494
+ 'timestamp': None,
4495
+ 'datetime': None,
4496
+ 'currency': None,
4497
+ 'amount': None,
4498
+ 'fromAccount': None,
4499
+ 'toAccount': None,
4500
+ 'status': None,
4501
+ }
4502
+
4503
+ def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
4504
+ #
4505
+ # spot: error
4506
+ #
4507
+ # {
4508
+ # "rc": 1,
4509
+ # "mc": "AUTH_103",
4510
+ # "ma": [],
4511
+ # "result": null
4512
+ # }
4513
+ #
4514
+ # spot: success
4515
+ #
4516
+ # {
4517
+ # "returnCode": 0,
4518
+ # "msgInfo": "success",
4519
+ # "error": null,
4520
+ # "result": []
4521
+ # }
4522
+ #
4523
+ # swap and future: error
4524
+ #
4525
+ # {
4526
+ # "returnCode": 1,
4527
+ # "msgInfo": "failure",
4528
+ # "error": {
4529
+ # "code": "403",
4530
+ # "msg": "invalid signature"
4531
+ # },
4532
+ # "result": null
4533
+ # }
4534
+ #
4535
+ # swap and future: success
4536
+ #
4537
+ # {
4538
+ # "returnCode": 0,
4539
+ # "msgInfo": "success",
4540
+ # "error": null,
4541
+ # "result": null
4542
+ # }
4543
+ #
4544
+ # other:
4545
+ #
4546
+ # {
4547
+ # "rc": 0,
4548
+ # "mc": "SUCCESS",
4549
+ # "ma": [],
4550
+ # "result": {}
4551
+ # }
4552
+ #
4553
+ status = self.safe_string_upper_2(response, 'msgInfo', 'mc')
4554
+ if status is not None and status != 'SUCCESS':
4555
+ feedback = self.id + ' ' + body
4556
+ error = self.safe_value(response, 'error', {})
4557
+ spotErrorCode = self.safe_string(response, 'mc')
4558
+ errorCode = self.safe_string(error, 'code', spotErrorCode)
4559
+ spotMessage = self.safe_string(response, 'msgInfo')
4560
+ message = self.safe_string(error, 'msg', spotMessage)
4561
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
4562
+ self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
4563
+ raise ExchangeError(feedback)
4564
+ return None
4565
+
4566
+ def sign(self, path, api=[], method='GET', params={}, headers=None, body=None):
4567
+ signed = api[0] == 'private'
4568
+ endpoint = api[1]
4569
+ request = '/' + self.implode_params(path, params)
4570
+ payload = None
4571
+ if (endpoint == 'spot') or (endpoint == 'user'):
4572
+ if signed:
4573
+ payload = '/' + self.version + request
4574
+ else:
4575
+ payload = '/' + self.version + '/public' + request
4576
+ else:
4577
+ payload = request
4578
+ url = self.urls['api'][endpoint] + payload
4579
+ query = self.omit(params, self.extract_params(path))
4580
+ urlencoded = self.urlencode(self.keysort(query))
4581
+ headers = {
4582
+ 'Content-Type': 'application/json',
4583
+ }
4584
+ if signed:
4585
+ self.check_required_credentials()
4586
+ defaultRecvWindow = self.safe_string(self.options, 'recvWindow')
4587
+ recvWindow = self.safe_string(query, 'recvWindow', defaultRecvWindow)
4588
+ timestamp = self.number_to_string(self.nonce())
4589
+ body = query
4590
+ if (payload == '/v4/order') or (payload == '/future/trade/v1/order/create') or (payload == '/future/trade/v1/entrust/create-plan') or (payload == '/future/trade/v1/entrust/create-profit') or (payload == '/future/trade/v1/order/create-batch'):
4591
+ id = 'CCXT'
4592
+ if payload.find('future') > -1:
4593
+ body['clientMedia'] = id
4594
+ else:
4595
+ body['media'] = id
4596
+ isUndefinedBody = ((method == 'GET') or (path == 'order/{orderId}') or (path == 'ws-token'))
4597
+ body = None if isUndefinedBody else self.json(body)
4598
+ payloadString = None
4599
+ if (endpoint == 'spot') or (endpoint == 'user'):
4600
+ payloadString = 'xt-validate-algorithms=HmacSHA256&xt-validate-appkey=' + self.apiKey + '&xt-validate-recvwindow=' + recvWindow + '&xt-validate-t' + 'imestamp=' + timestamp
4601
+ if isUndefinedBody:
4602
+ if urlencoded:
4603
+ url += '?' + urlencoded
4604
+ payloadString += '#' + method + '#' + payload + '#' + self.rawencode(self.keysort(query))
4605
+ else:
4606
+ payloadString += '#' + method + '#' + payload
4607
+ else:
4608
+ payloadString += '#' + method + '#' + payload + '#' + body
4609
+ headers['xt-validate-algorithms'] = 'HmacSHA256'
4610
+ headers['xt-validate-recvwindow'] = recvWindow
4611
+ else:
4612
+ payloadString = 'xt-validate-appkey=' + self.apiKey + '&xt-validate-t' + 'imestamp=' + timestamp # we can't glue timestamp, breaks in php
4613
+ if method == 'GET':
4614
+ if urlencoded:
4615
+ url += '?' + urlencoded
4616
+ payloadString += '#' + payload + '#' + urlencoded
4617
+ else:
4618
+ payloadString += '#' + payload
4619
+ else:
4620
+ payloadString += '#' + payload + '#' + body
4621
+ signature = self.hmac(self.encode(payloadString), self.encode(self.secret), hashlib.sha256)
4622
+ headers['xt-validate-appkey'] = self.apiKey
4623
+ headers['xt-validate-timestamp'] = timestamp
4624
+ headers['xt-validate-signature'] = signature
4625
+ else:
4626
+ if urlencoded:
4627
+ url += '?' + urlencoded
4628
+ return {'url': url, 'method': method, 'body': body, 'headers': headers}