ccxt 4.2.76__py2.py3-none-any.whl → 4.4.48__py2.py3-none-any.whl

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