ccxt 4.2.77__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 +24 -0
  44. ccxt/abstract/kucoinfutures.py +34 -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 +3030 -1087
  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 +3104 -880
  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 +238 -49
  89. ccxt/async_support/bitget.py +1513 -563
  90. ccxt/async_support/bithumb.py +199 -65
  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 +392 -148
  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 +2231 -1193
  107. ccxt/async_support/cex.py +1409 -1329
  108. ccxt/async_support/coinbase.py +1454 -287
  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 +404 -109
  125. ccxt/async_support/deribit.py +557 -323
  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 +1472 -463
  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 +1633 -268
  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 +917 -357
  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 +1776 -454
  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 +1137 -296
  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 +1722 -480
  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 +3030 -1087
  187. ccxt/binancecoinm.py +2 -1
  188. ccxt/binanceus.py +12 -1
  189. ccxt/binanceusdm.py +3 -1
  190. ccxt/bingx.py +3104 -880
  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 +238 -49
  197. ccxt/bitget.py +1513 -563
  198. ccxt/bithumb.py +198 -65
  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 +392 -148
  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 +2231 -1193
  215. ccxt/cex.py +1408 -1329
  216. ccxt/coinbase.py +1454 -287
  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 +404 -109
  233. ccxt/deribit.py +557 -323
  234. ccxt/digifinex.py +340 -223
  235. ccxt/ellipx.py +1826 -0
  236. ccxt/exmo.py +259 -128
  237. ccxt/gate.py +1472 -463
  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 +1632 -268
  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 +917 -357
  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 +1776 -454
  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 +62 -14
  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 +203 -81
  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 +965 -665
  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 +167 -31
  309. ccxt/pro/exmo.py +252 -20
  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 +92 -33
  336. ccxt/pro/poloniex.py +128 -49
  337. ccxt/pro/poloniexfutures.py +53 -32
  338. ccxt/pro/probit.py +92 -85
  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 +437 -65
  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} +456 -391
  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} +456 -393
  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 +1137 -296
  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.77.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.77.dist-info/METADATA +0 -626
  545. ccxt-4.2.77.dist-info/RECORD +0 -534
  546. {ccxt-4.2.77.dist-info → ccxt-4.4.48.dist-info}/top_level.txt +0 -0
ccxt/pro/coinex.py CHANGED
@@ -4,17 +4,18 @@
4
4
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
5
 
6
6
  import ccxt.async_support
7
- from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
7
+ from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById
8
+ import hashlib
8
9
  from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Strings, Ticker, Tickers, Trade
9
10
  from ccxt.async_support.base.ws.client import Client
10
11
  from typing import List
11
12
  from ccxt.base.errors import ExchangeError
13
+ from ccxt.base.errors import AuthenticationError
12
14
  from ccxt.base.errors import BadRequest
13
15
  from ccxt.base.errors import NotSupported
16
+ from ccxt.base.errors import RateLimitExceeded
14
17
  from ccxt.base.errors import ExchangeNotAvailable
15
18
  from ccxt.base.errors import RequestTimeout
16
- from ccxt.base.errors import AuthenticationError
17
- from ccxt.base.precise import Precise
18
19
 
19
20
 
20
21
  class coinex(ccxt.async_support.coinex):
@@ -24,25 +25,30 @@ class coinex(ccxt.async_support.coinex):
24
25
  'has': {
25
26
  'ws': True,
26
27
  'watchBalance': True,
28
+ 'watchBidsAsks': True,
27
29
  'watchTicker': True,
28
30
  'watchTickers': True,
29
31
  'watchTrades': True,
30
- 'watchMyTrades': False, # can query but can't subscribe
32
+ 'watchTradesForSymbols': True,
33
+ 'watchMyTrades': True,
31
34
  'watchOrders': True,
32
35
  'watchOrderBook': True,
33
- 'watchOHLCV': True, # only for swap markets
34
- 'fetchOHLCVWs': True,
36
+ 'watchOrderBookForSymbols': True,
37
+ 'watchOHLCV': False,
38
+ 'fetchOHLCVWs': False,
35
39
  },
36
40
  'urls': {
37
41
  'api': {
38
42
  'ws': {
39
- 'spot': 'wss://socket.coinex.com/',
40
- 'swap': 'wss://perpetual.coinex.com/',
43
+ 'spot': 'wss://socket.coinex.com/v2/spot/',
44
+ 'swap': 'wss://socket.coinex.com/v2/futures/',
41
45
  },
42
46
  },
43
47
  },
44
48
  'options': {
45
- 'watchOHLCVWarning': True,
49
+ 'ws': {
50
+ 'gunzip': True,
51
+ },
46
52
  'timeframes': {
47
53
  '1m': 60,
48
54
  '3m': 180,
@@ -62,21 +68,32 @@ class coinex(ccxt.async_support.coinex):
62
68
  'watchOrderBook': {
63
69
  'limits': [5, 10, 20, 50],
64
70
  'defaultLimit': 50,
65
- 'aggregations': ['10', '1', '0', '0.1', '0.01'],
71
+ 'aggregations': ['1000', '100', '10', '1', '0', '0.1', '0.01', '0.001', '0.0001', '0.00001', '0.000001', '0.0000001', '0.00000001', '0.000000001', '0.0000000001', '0.00000000001'],
66
72
  'defaultAggregation': '0',
67
73
  },
68
74
  },
69
75
  'streaming': {
70
76
  },
71
77
  'exceptions': {
72
- 'codes': {
73
- '1': BadRequest, # Parameter error
74
- '2': ExchangeError, # Internal error
75
- '3': ExchangeNotAvailable, # Service unavailable
76
- '4': NotSupported, # Method unavailable
77
- '5': RequestTimeout, # Service timeout
78
- '6': AuthenticationError, # Permission denied
78
+ 'exact': {
79
+ '20001': BadRequest, # Invalid argument
80
+ '20002': NotSupported, # Method unavailable
81
+ '21001': AuthenticationError, # Authentication required
82
+ '21002': AuthenticationError, # Incorrect signature
83
+ '23001': RequestTimeout, # Request service timeout
84
+ '23002': RateLimitExceeded, # Requests too frequently
85
+ '24001': ExchangeError, # Internal error
86
+ '24002': ExchangeNotAvailable, # Service unavailable temporarily
87
+ '30001': BadRequest, # Invalid argument
88
+ '30002': NotSupported, # Method unavailable
89
+ '31001': AuthenticationError, # Authentication required
90
+ '31002': AuthenticationError, # Incorrect signature
91
+ '33001': RequestTimeout, # Request service timeout
92
+ '33002': RateLimitExceeded, # Requests too frequently
93
+ '34001': ExchangeError, # Internal error
94
+ '34002': ExchangeNotAvailable, # Service unavailable temporarily
79
95
  },
96
+ 'broad': {},
80
97
  },
81
98
  })
82
99
 
@@ -91,61 +108,66 @@ class coinex(ccxt.async_support.coinex):
91
108
  #
92
109
  # {
93
110
  # "method": "state.update",
94
- # "params": [{
95
- # "BTCUSDT": {
96
- # "last": "31577.89",
97
- # "open": "29318.36",
98
- # "close": "31577.89",
99
- # "high": "32222.19",
100
- # "low": "29317.21",
101
- # "volume": "630.43024965",
102
- # "sell_total": "13.66143951",
103
- # "buy_total": "2.76410939",
104
- # "period": 86400,
105
- # "deal": "19457487.84611409070000000000"
106
- # }
107
- # }]
111
+ # "data": {
112
+ # "state_list": [
113
+ # {
114
+ # "market": "LATUSDT",
115
+ # "last": "0.008157",
116
+ # "open": "0.008286",
117
+ # "close": "0.008157",
118
+ # "high": "0.008390",
119
+ # "low": "0.008106",
120
+ # "volume": "807714.49139758",
121
+ # "volume_sell": "286170.69645599",
122
+ # "volume_buy": "266161.23236408",
123
+ # "value": "6689.21644207",
124
+ # "period": 86400
125
+ # },
126
+ # ]
127
+ # },
128
+ # "id": null
108
129
  # }
109
130
  #
110
131
  # swap
111
132
  #
112
133
  # {
113
134
  # "method": "state.update",
114
- # "params": [{
115
- # "BTCUSDT": {
116
- # "period": 86400,
117
- # "funding_time": 422,
118
- # "position_amount": "285.6246",
119
- # "funding_rate_last": "-0.00097933",
120
- # "funding_rate_next": "0.00022519",
121
- # "funding_rate_predict": "0.00075190",
122
- # "insurance": "17474289.49925859030905338270",
123
- # "last": "31570.08",
124
- # "sign_price": "31568.09",
125
- # "index_price": "31561.85000000",
126
- # "open": "29296.11",
127
- # "close": "31570.08",
128
- # "high": "32463.40",
129
- # "low": "29296.11",
130
- # "volume": "8774.7318",
131
- # "deal": "270675177.827928219109030017258398",
132
- # "sell_total": "19.2230",
133
- # "buy_total": "25.7814"
134
- # }
135
- # }]
135
+ # "data": {
136
+ # "state_list": [
137
+ # {
138
+ # "market": "ETHUSD_SIGNPRICE",
139
+ # "last": "1892.29",
140
+ # "open": "1884.62",
141
+ # "close": "1892.29",
142
+ # "high": "1894.09",
143
+ # "low": "1863.72",
144
+ # "volume": "0",
145
+ # "value": "0",
146
+ # "volume_sell": "0",
147
+ # "volume_buy": "0",
148
+ # "open_interest_size": "0",
149
+ # "insurance_fund_size": "0",
150
+ # "latest_funding_rate": "0",
151
+ # "next_funding_rate": "0",
152
+ # "latest_funding_time": 0,
153
+ # "next_funding_time": 0,
154
+ # "period": 86400
155
+ # },
156
+ # ]
157
+ # ],
158
+ # "id": null
136
159
  # }
137
160
  #
138
161
  defaultType = self.safe_string(self.options, 'defaultType')
139
- params = self.safe_value(message, 'params', [])
140
- rawTickers = self.safe_value(params, 0, {})
141
- keys = list(rawTickers.keys())
162
+ data = self.safe_dict(message, 'data', {})
163
+ rawTickers = self.safe_list(data, 'state_list', [])
142
164
  newTickers = []
143
- for i in range(0, len(keys)):
144
- marketId = keys[i]
145
- rawTicker = rawTickers[marketId]
165
+ for i in range(0, len(rawTickers)):
166
+ entry = rawTickers[i]
167
+ marketId = self.safe_string(entry, 'market')
146
168
  symbol = self.safe_symbol(marketId, None, None, defaultType)
147
169
  market = self.safe_market(marketId, None, None, defaultType)
148
- parsedTicker = self.parse_ws_ticker(rawTicker, market)
170
+ parsedTicker = self.parse_ws_ticker(entry, market)
149
171
  self.tickers[symbol] = parsedTicker
150
172
  newTickers.append(parsedTicker)
151
173
  messageHashes = self.find_message_hashes(client, 'tickers::')
@@ -166,52 +188,53 @@ class coinex(ccxt.async_support.coinex):
166
188
  # spot
167
189
  #
168
190
  # {
169
- # "last": "31577.89",
170
- # "open": "29318.36",
171
- # "close": "31577.89",
172
- # "high": "32222.19",
173
- # "low": "29317.21",
174
- # "volume": "630.43024965",
175
- # "sell_total": "13.66143951",
176
- # "buy_total": "2.76410939",
177
- # "period": 86400,
178
- # "deal": "19457487.84611409070000000000"
191
+ # "market": "LATUSDT",
192
+ # "last": "0.008157",
193
+ # "open": "0.008286",
194
+ # "close": "0.008157",
195
+ # "high": "0.008390",
196
+ # "low": "0.008106",
197
+ # "volume": "807714.49139758",
198
+ # "volume_sell": "286170.69645599",
199
+ # "volume_buy": "266161.23236408",
200
+ # "value": "6689.21644207",
201
+ # "period": 86400
179
202
  # }
180
203
  #
181
204
  # swap
182
205
  #
183
206
  # {
184
- # "period": 86400,
185
- # "funding_time": 422,
186
- # "position_amount": "285.6246",
187
- # "funding_rate_last": "-0.00097933",
188
- # "funding_rate_next": "0.00022519",
189
- # "funding_rate_predict": "0.00075190",
190
- # "insurance": "17474289.49925859030905338270",
191
- # "last": "31570.08",
192
- # "sign_price": "31568.09",
193
- # "index_price": "31561.85000000",
194
- # "open": "29296.11",
195
- # "close": "31570.08",
196
- # "high": "32463.40",
197
- # "low": "29296.11",
198
- # "volume": "8774.7318",
199
- # "deal": "270675177.827928219109030017258398",
200
- # "sell_total": "19.2230",
201
- # "buy_total": "25.7814"
207
+ # "market": "ETHUSD_SIGNPRICE",
208
+ # "last": "1892.29",
209
+ # "open": "1884.62",
210
+ # "close": "1892.29",
211
+ # "high": "1894.09",
212
+ # "low": "1863.72",
213
+ # "volume": "0",
214
+ # "value": "0",
215
+ # "volume_sell": "0",
216
+ # "volume_buy": "0",
217
+ # "open_interest_size": "0",
218
+ # "insurance_fund_size": "0",
219
+ # "latest_funding_rate": "0",
220
+ # "next_funding_rate": "0",
221
+ # "latest_funding_time": 0,
222
+ # "next_funding_time": 0,
223
+ # "period": 86400
202
224
  # }
203
225
  #
204
226
  defaultType = self.safe_string(self.options, 'defaultType')
227
+ marketId = self.safe_string(ticker, 'market')
205
228
  return self.safe_ticker({
206
- 'symbol': self.safe_symbol(None, market, None, defaultType),
229
+ 'symbol': self.safe_symbol(marketId, market, None, defaultType),
207
230
  'timestamp': None,
208
231
  'datetime': None,
209
232
  'high': self.safe_string(ticker, 'high'),
210
233
  'low': self.safe_string(ticker, 'low'),
211
234
  'bid': None,
212
- 'bidVolume': self.safe_string(ticker, 'buy_total'),
235
+ 'bidVolume': self.safe_string(ticker, 'volume_buy'),
213
236
  'ask': None,
214
- 'askVolume': self.safe_string(ticker, 'sell_total'),
237
+ 'askVolume': self.safe_string(ticker, 'volume_sell'),
215
238
  'vwap': None,
216
239
  'open': self.safe_string(ticker, 'open'),
217
240
  'close': self.safe_string(ticker, 'close'),
@@ -221,84 +244,278 @@ class coinex(ccxt.async_support.coinex):
221
244
  'percentage': None,
222
245
  'average': None,
223
246
  'baseVolume': self.safe_string(ticker, 'volume'),
224
- 'quoteVolume': self.safe_string(ticker, 'deal'),
247
+ 'quoteVolume': self.safe_string(ticker, 'value'),
225
248
  'info': ticker,
226
249
  }, market)
227
250
 
228
251
  async def watch_balance(self, params={}) -> Balances:
229
252
  """
230
253
  watch balance and get the amount of funds available for trading or funds locked in orders
254
+
255
+ https://docs.coinex.com/api/v2/assets/balance/ws/spot_balance
256
+ https://docs.coinex.com/api/v2/assets/balance/ws/futures_balance
257
+
231
258
  :param dict [params]: extra parameters specific to the exchange API endpoint
232
259
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
233
260
  """
234
261
  await self.load_markets()
235
- await self.authenticate(params)
236
- messageHash = 'balance'
237
262
  type = None
238
- type, params = self.handle_market_type_and_params('watchBalance', None, params)
263
+ type, params = self.handle_market_type_and_params('watchBalance', None, params, 'spot')
264
+ await self.authenticate(type)
239
265
  url = self.urls['api']['ws'][type]
240
266
  currencies = list(self.currencies_by_id.keys())
241
- subscribe = {
242
- 'method': 'asset.subscribe',
243
- 'params': currencies,
267
+ if currencies is None:
268
+ currencies = []
269
+ messageHash = 'balances'
270
+ if type == 'spot':
271
+ messageHash += ':spot'
272
+ else:
273
+ messageHash += ':swap'
274
+ subscribe: dict = {
275
+ 'method': 'balance.subscribe',
276
+ 'params': {'ccy_list': currencies},
244
277
  'id': self.request_id(),
245
278
  }
246
279
  request = self.deep_extend(subscribe, params)
247
280
  return await self.watch(url, messageHash, request, messageHash)
248
281
 
249
282
  def handle_balance(self, client: Client, message):
283
+ #
284
+ # spot
250
285
  #
251
286
  # {
252
- # "method": "asset.update",
253
- # "params": [
254
- # {
255
- # "BTC": {
256
- # "available": "250",
257
- # "frozen": "10",
258
- # }
259
- # }
260
- # ],
287
+ # "method": "balance.update",
288
+ # "data": {
289
+ # "balance_list": [
290
+ # {
291
+ # "margin_market": "BTCUSDT",
292
+ # "ccy": "BTC",
293
+ # "available": "44.62207740",
294
+ # "frozen": "0.00000000",
295
+ # "updated_at": 1689152421692
296
+ # },
297
+ # ]
298
+ # },
261
299
  # "id": null
262
300
  # }
263
301
  #
264
- params = self.safe_value(message, 'params', [])
265
- first = self.safe_value(params, 0, {})
266
- self.balance['info'] = first
267
- currencies = list(first.keys())
268
- for i in range(0, len(currencies)):
269
- currencyId = currencies[i]
270
- code = self.safe_currency_code(currencyId)
271
- available = self.safe_string(first[currencyId], 'available')
272
- frozen = self.safe_string(first[currencyId], 'frozen')
273
- account = self.account()
274
- account['free'] = available
275
- account['used'] = frozen
302
+ # swap
303
+ #
304
+ # {
305
+ # "method": "balance.update",
306
+ # "data": {
307
+ # "balance_list": [
308
+ # {
309
+ # "ccy": "USDT",
310
+ # "available": "97.92470982756335000001",
311
+ # "frozen": "0.00000000000000000000",
312
+ # "margin": "0.61442700000000000000",
313
+ # "transferrable": "97.92470982756335000001",
314
+ # "unrealized_pnl": "-0.00807000000000000000",
315
+ # "equity": "97.92470982756335000001"
316
+ # },
317
+ # ]
318
+ # },
319
+ # "id": null
320
+ # }
321
+ #
322
+ if self.balance is None:
323
+ self.balance = {}
324
+ data = self.safe_dict(message, 'data', {})
325
+ balances = self.safe_list(data, 'balance_list', [])
326
+ firstEntry = balances[0]
327
+ updated = self.safe_integer(firstEntry, 'updated_at')
328
+ unrealizedPnl = self.safe_string(firstEntry, 'unrealized_pnl')
329
+ isSpot = (updated is not None)
330
+ isSwap = (unrealizedPnl is not None)
331
+ info = None
332
+ account = None
333
+ rawBalances = []
334
+ if isSpot:
335
+ account = 'spot'
336
+ for i in range(0, len(balances)):
337
+ rawBalances = self.array_concat(rawBalances, balances)
338
+ info = rawBalances
339
+ if isSwap:
340
+ account = 'swap'
341
+ for i in range(0, len(balances)):
342
+ rawBalances = self.array_concat(rawBalances, balances)
343
+ info = rawBalances
344
+ for i in range(0, len(rawBalances)):
345
+ entry = rawBalances[i]
346
+ self.parse_ws_balance(entry, account)
347
+ messageHash = None
348
+ if account is not None:
349
+ if self.safe_value(self.balance, account) is None:
350
+ self.balance[account] = {}
351
+ self.balance[account]['info'] = info
352
+ self.balance[account] = self.safe_balance(self.balance[account])
353
+ messageHash = 'balances:' + account
354
+ client.resolve(self.balance[account], messageHash)
355
+
356
+ def parse_ws_balance(self, balance, accountType=None):
357
+ #
358
+ # spot
359
+ #
360
+ # {
361
+ # "margin_market": "BTCUSDT",
362
+ # "ccy": "BTC",
363
+ # "available": "44.62207740",
364
+ # "frozen": "0.00000000",
365
+ # "updated_at": 1689152421692
366
+ # }
367
+ #
368
+ # swap
369
+ #
370
+ # {
371
+ # "ccy": "USDT",
372
+ # "available": "97.92470982756335000001",
373
+ # "frozen": "0.00000000000000000000",
374
+ # "margin": "0.61442700000000000000",
375
+ # "transferrable": "97.92470982756335000001",
376
+ # "unrealized_pnl": "-0.00807000000000000000",
377
+ # "equity": "97.92470982756335000001"
378
+ # }
379
+ #
380
+ account = self.account()
381
+ currencyId = self.safe_string(balance, 'ccy')
382
+ code = self.safe_currency_code(currencyId)
383
+ account['free'] = self.safe_string(balance, 'available')
384
+ account['used'] = self.safe_string(balance, 'frozen')
385
+ if accountType is not None:
386
+ if self.safe_value(self.balance, accountType) is None:
387
+ self.balance[accountType] = {}
388
+ self.balance[accountType][code] = account
389
+ else:
276
390
  self.balance[code] = account
277
- self.balance = self.safe_balance(self.balance)
278
- messageHash = 'balance'
279
- client.resolve(self.balance, messageHash)
391
+
392
+ async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
393
+ """
394
+ watches information on multiple trades made by the user
395
+
396
+ https://docs.coinex.com/api/v2/spot/deal/ws/user-deals
397
+ https://docs.coinex.com/api/v2/futures/deal/ws/user-deals
398
+
399
+ :param str [symbol]: unified symbol of the market the trades were made in
400
+ :param int [since]: the earliest time in ms to watch trades
401
+ :param int [limit]: the maximum number of trade structures to retrieve
402
+ :param dict [params]: extra parameters specific to the exchange API endpoint
403
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
404
+ """
405
+ await self.load_markets()
406
+ market = None
407
+ if symbol is not None:
408
+ market = self.market(symbol)
409
+ symbol = market['symbol']
410
+ type = None
411
+ type, params = self.handle_market_type_and_params('watchMyTrades', market, params, 'spot')
412
+ await self.authenticate(type)
413
+ url = self.urls['api']['ws'][type]
414
+ subscribedSymbols = []
415
+ messageHash = 'myTrades'
416
+ if market is not None:
417
+ messageHash += ':' + symbol
418
+ subscribedSymbols.append(market['id'])
419
+ else:
420
+ if type == 'spot':
421
+ messageHash += ':spot'
422
+ else:
423
+ messageHash += ':swap'
424
+ message: dict = {
425
+ 'method': 'user_deals.subscribe',
426
+ 'params': {'market_list': subscribedSymbols},
427
+ 'id': self.request_id(),
428
+ }
429
+ request = self.deep_extend(message, params)
430
+ trades = await self.watch(url, messageHash, request, messageHash)
431
+ if self.newUpdates:
432
+ limit = trades.getLimit(symbol, limit)
433
+ return self.filter_by_symbol_since_limit(trades, symbol, since, limit, True)
434
+
435
+ def handle_my_trades(self, client: Client, message):
436
+ #
437
+ # {
438
+ # "method": "user_deals.update",
439
+ # "data": {
440
+ # "deal_id": 3514376759,
441
+ # "created_at": 1689152421692,
442
+ # "market": "BTCUSDT",
443
+ # "side": "buy",
444
+ # "order_id": 8678890,
445
+ # "margin_market": "BTCUSDT",
446
+ # "price": "30718.42",
447
+ # "amount": "0.00000325",
448
+ # "role": "taker",
449
+ # "fee": "0.0299",
450
+ # "fee_ccy": "USDT"
451
+ # },
452
+ # "id": null
453
+ # }
454
+ #
455
+ data = self.safe_dict(message, 'data', {})
456
+ marketId = self.safe_string(data, 'market')
457
+ isSpot = client.url.find('spot') > -1
458
+ defaultType = 'spot' if isSpot else 'swap'
459
+ market = self.safe_market(marketId, None, None, defaultType)
460
+ symbol = market['symbol']
461
+ messageHash = 'myTrades:' + symbol
462
+ messageWithType = 'myTrades:' + market['type']
463
+ stored = self.safe_value(self.trades, symbol)
464
+ if stored is None:
465
+ limit = self.safe_integer(self.options, 'tradesLimit', 1000)
466
+ stored = ArrayCache(limit)
467
+ self.trades[symbol] = stored
468
+ parsed = self.parse_ws_trade(data, market)
469
+ stored.append(parsed)
470
+ self.trades[symbol] = stored
471
+ client.resolve(self.trades[symbol], messageWithType)
472
+ client.resolve(self.trades[symbol], messageHash)
280
473
 
281
474
  def handle_trades(self, client: Client, message):
475
+ #
476
+ # spot
282
477
  #
283
478
  # {
284
479
  # "method": "deals.update",
285
- # "params": [
286
- # "BTCUSD",
287
- # [{
288
- # "type": "sell",
289
- # "time": 1496458040.059284,
290
- # "price ": "46444.74",
291
- # "id": 29433,
292
- # "amount": "0.00120000"
293
- # }]
294
- # ],
480
+ # "data": {
481
+ # "market": "BTCUSDT",
482
+ # "deal_list": [
483
+ # {
484
+ # "deal_id": 3514376759,
485
+ # "created_at": 1689152421692,
486
+ # "side": "buy",
487
+ # "price": "30718.42",
488
+ # "amount": "0.00000325"
489
+ # },
490
+ # ]
491
+ # },
295
492
  # "id": null
296
493
  # }
297
494
  #
298
- params = self.safe_value(message, 'params', [])
299
- marketId = self.safe_string(params, 0)
300
- trades = self.safe_value(params, 1, [])
301
- defaultType = self.safe_string(self.options, 'defaultType')
495
+ # swap
496
+ #
497
+ # {
498
+ # "method": "deals.update",
499
+ # "data": {
500
+ # "market": "BTCUSDT",
501
+ # "deal_list": [
502
+ # {
503
+ # "deal_id": 3514376759,
504
+ # "created_at": 1689152421692,
505
+ # "side": "buy",
506
+ # "price": "30718.42",
507
+ # "amount": "0.00000325"
508
+ # },
509
+ # ]
510
+ # },
511
+ # "id": null
512
+ # }
513
+ #
514
+ data = self.safe_dict(message, 'data', {})
515
+ trades = self.safe_list(data, 'deal_list', [])
516
+ marketId = self.safe_string(data, 'market')
517
+ isSpot = client.url.find('spot') > -1
518
+ defaultType = 'spot' if isSpot else 'swap'
302
519
  market = self.safe_market(marketId, None, None, defaultType)
303
520
  symbol = market['symbol']
304
521
  messageHash = 'trades:' + symbol
@@ -315,289 +532,251 @@ class coinex(ccxt.async_support.coinex):
315
532
  client.resolve(self.trades[symbol], messageHash)
316
533
 
317
534
  def parse_ws_trade(self, trade, market=None):
535
+ #
536
+ # spot watchTrades
318
537
  #
319
538
  # {
320
- # "type": "sell",
321
- # "time": 1496458040.059284,
322
- # "price ": "46444.74",
323
- # "id": 29433,
324
- # "amount": "0.00120000"
539
+ # "deal_id": 3514376759,
540
+ # "created_at": 1689152421692,
541
+ # "side": "buy",
542
+ # "price": "30718.42",
543
+ # "amount": "0.00000325"
325
544
  # }
326
545
  #
327
- timestamp = self.safe_timestamp(trade, 'time')
328
- defaultType = self.safe_string(self.options, 'defaultType')
546
+ # swap watchTrades
547
+ #
548
+ # {
549
+ # "deal_id": 3514376759,
550
+ # "created_at": 1689152421692,
551
+ # "side": "buy",
552
+ # "price": "30718.42",
553
+ # "amount": "0.00000325"
554
+ # }
555
+ #
556
+ # spot and swap watchMyTrades
557
+ #
558
+ # {
559
+ # "deal_id": 3514376759,
560
+ # "created_at": 1689152421692,
561
+ # "market": "BTCUSDT",
562
+ # "side": "buy",
563
+ # "order_id": 8678890,
564
+ # "margin_market": "BTCUSDT",
565
+ # "price": "30718.42",
566
+ # "amount": "0.00000325",
567
+ # "role": "taker",
568
+ # "fee": "0.0299",
569
+ # "fee_ccy": "USDT"
570
+ # }
571
+ #
572
+ timestamp = self.safe_integer(trade, 'created_at')
573
+ isSpot = ('margin_market' in trade)
574
+ defaultType = 'spot' if isSpot else 'swap'
575
+ marketId = self.safe_string(trade, 'market')
576
+ market = self.safe_market(marketId, market, None, defaultType)
577
+ fee: dict = {}
578
+ feeCost = self.omit_zero(self.safe_string(trade, 'fee'))
579
+ if feeCost is not None:
580
+ feeCurrencyId = self.safe_string(trade, 'fee_ccy', market['quote'])
581
+ fee = {
582
+ 'currency': self.safe_currency_code(feeCurrencyId),
583
+ 'cost': feeCost,
584
+ }
329
585
  return self.safe_trade({
330
- 'id': self.safe_string(trade, 'id'),
586
+ 'id': self.safe_string(trade, 'deal_id'),
331
587
  'info': trade,
332
588
  'timestamp': timestamp,
333
589
  'datetime': self.iso8601(timestamp),
334
- 'symbol': self.safe_symbol(None, market, None, defaultType),
335
- 'order': None,
590
+ 'symbol': self.safe_symbol(marketId, market, None, defaultType),
591
+ 'order': self.safe_string(trade, 'order_id'),
336
592
  'type': None,
337
- 'side': self.safe_string(trade, 'type'),
338
- 'takerOrMaker': None,
593
+ 'side': self.safe_string(trade, 'side'),
594
+ 'takerOrMaker': self.safe_string(trade, 'role'),
339
595
  'price': self.safe_string(trade, 'price'),
340
596
  'amount': self.safe_string(trade, 'amount'),
341
597
  'cost': None,
342
- 'fee': None,
598
+ 'fee': fee,
343
599
  }, market)
344
600
 
345
- def handle_ohlcv(self, client: Client, message):
346
- #
347
- # spot
348
- # {
349
- # "error": null,
350
- # "result": [
351
- # [
352
- # 1673846940,
353
- # "21148.74",
354
- # "21148.38",
355
- # "21148.75",
356
- # "21138.66",
357
- # "1.57060173",
358
- # "33214.9138778914"
359
- # ],
360
- # ]
361
- # "id": 1,
362
- # }
363
- # swap
364
- # {
365
- # "method": "kline.update",
366
- # "params": [
367
- # [
368
- # 1654019640, # timestamp
369
- # "32061.99", # open
370
- # "32061.28", # close
371
- # "32061.99", # high
372
- # "32061.28", # low
373
- # "0.1285", # amount base
374
- # "4119.943736" # amount quote
375
- # ]
376
- # ],
377
- # "id": null
378
- # }
379
- #
380
- candles = self.safe_value_2(message, 'params', 'result', [])
381
- messageHash = 'ohlcv'
382
- id = self.safe_string(message, 'id')
383
- ohlcvs = self.parse_ohlcvs(candles)
384
- if id is not None:
385
- # spot subscription response
386
- client.resolve(ohlcvs, messageHash)
387
- return
388
- keys = list(self.ohlcvs.keys())
389
- keysLength = len(keys)
390
- if keysLength == 0:
391
- self.ohlcvs['unknown'] = {}
392
- limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
393
- stored = ArrayCacheByTimestamp(limit)
394
- self.ohlcvs['unknown']['unknown'] = stored
395
- ohlcv = self.ohlcvs['unknown']['unknown']
396
- for i in range(0, len(ohlcvs)):
397
- candle = ohlcvs[i]
398
- ohlcv.append(candle)
399
- client.resolve(ohlcv, messageHash)
400
-
401
601
  async def watch_ticker(self, symbol: str, params={}) -> Ticker:
402
602
  """
403
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot004_websocket007_state_subscribe
404
603
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
604
+
605
+ https://docs.coinex.com/api/v2/spot/market/ws/market
606
+ https://docs.coinex.com/api/v2/futures/market/ws/market-state
607
+
405
608
  :param str symbol: unified symbol of the market to fetch the ticker for
406
609
  :param dict [params]: extra parameters specific to the exchange API endpoint
407
610
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
408
611
  """
612
+ await self.load_markets()
613
+ market = self.market(symbol)
409
614
  tickers = await self.watch_tickers([symbol], params)
410
- return self.safe_value(tickers, symbol)
615
+ return tickers[market['symbol']]
411
616
 
412
617
  async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
413
618
  """
414
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot004_websocket007_state_subscribe
415
619
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
620
+
621
+ https://docs.coinex.com/api/v2/spot/market/ws/market
622
+ https://docs.coinex.com/api/v2/futures/market/ws/market-state
623
+
416
624
  :param str[] symbols: unified symbol of the market to fetch the ticker for
417
625
  :param dict [params]: extra parameters specific to the exchange API endpoint
418
626
  :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
419
627
  """
420
628
  await self.load_markets()
421
- symbols = self.market_symbols(symbols)
629
+ marketIds = self.market_ids(symbols)
630
+ market = None
631
+ messageHashes = []
632
+ symbolsDefined = (symbols is not None)
633
+ if symbolsDefined:
634
+ for i in range(0, len(symbols)):
635
+ symbol = symbols[i]
636
+ market = self.market(symbol)
637
+ messageHashes.append('tickers::' + market['symbol'])
638
+ else:
639
+ messageHashes.append('tickers')
422
640
  type = None
423
- type, params = self.handle_market_type_and_params('watchTickers', None, params)
641
+ type, params = self.handle_market_type_and_params('watchTickers', market, params)
424
642
  url = self.urls['api']['ws'][type]
425
- messageHash = 'tickers'
426
- if symbols is not None:
427
- messageHash = 'tickers::' + ','.join(symbols)
428
- subscribe = {
643
+ subscriptionHashes = ['all@ticker']
644
+ subscribe: dict = {
429
645
  'method': 'state.subscribe',
646
+ 'params': {'market_list': marketIds},
430
647
  'id': self.request_id(),
431
- 'params': [],
432
648
  }
433
- request = self.deep_extend(subscribe, params)
434
- newTickers = await self.watch(url, messageHash, request, messageHash)
649
+ result = await self.watch_multiple(url, messageHashes, self.deep_extend(subscribe, params), subscriptionHashes)
435
650
  if self.newUpdates:
436
- return newTickers
651
+ return result
437
652
  return self.filter_by_array(self.tickers, 'symbol', symbols)
438
653
 
439
654
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
440
655
  """
441
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot004_websocket012_deal_subcribe
442
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures002_websocket019_deal_subcribe
443
656
  get the list of most recent trades for a particular symbol
657
+
658
+ https://docs.coinex.com/api/v2/spot/market/ws/market-deals
659
+ https://docs.coinex.com/api/v2/futures/market/ws/market-deals
660
+
444
661
  :param str symbol: unified symbol of the market to fetch trades for
445
662
  :param int [since]: timestamp in ms of the earliest trade to fetch
446
663
  :param int [limit]: the maximum amount of trades to fetch
447
664
  :param dict [params]: extra parameters specific to the exchange API endpoint
448
665
  :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
449
666
  """
667
+ params['callerMethodName'] = 'watchTrades'
668
+ return await self.watch_trades_for_symbols([symbol], since, limit, params)
669
+
670
+ async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
671
+ """
672
+ watch the most recent trades for a list of symbols
673
+
674
+ https://docs.coinex.com/api/v2/spot/market/ws/market-deals
675
+ https://docs.coinex.com/api/v2/futures/market/ws/market-deals
676
+
677
+ :param str[] symbols: unified symbols of the markets to fetch trades for
678
+ :param int [since]: timestamp in ms of the earliest trade to fetch
679
+ :param int [limit]: the maximum amount of trades to fetch
680
+ :param dict [params]: extra parameters specific to the exchange API endpoint
681
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
682
+ """
450
683
  await self.load_markets()
451
- market = self.market(symbol)
684
+ subscribedSymbols = []
685
+ messageHashes = []
686
+ market = None
687
+ callerMethodName = None
688
+ callerMethodName, params = self.handle_param_string(params, 'callerMethodName', 'watchTradesForSymbols')
689
+ symbolsDefined = (symbols is not None)
690
+ if symbolsDefined:
691
+ for i in range(0, len(symbols)):
692
+ symbol = symbols[i]
693
+ market = self.market(symbol)
694
+ subscribedSymbols.append(market['id'])
695
+ messageHashes.append('trades:' + market['symbol'])
696
+ else:
697
+ messageHashes.append('trades')
452
698
  type = None
453
- type, params = self.handle_market_type_and_params('watchTrades', market, params)
699
+ type, params = self.handle_market_type_and_params(callerMethodName, market, params)
454
700
  url = self.urls['api']['ws'][type]
455
- messageHash = 'trades:' + symbol
456
- subscriptionHash = 'trades'
457
- subscribedSymbols = self.safe_value(self.options, 'watchTradesSubscriptions', [])
458
- subscribedSymbols.append(market['id'])
459
- message = {
701
+ subscriptionHashes = ['trades']
702
+ subscribe: dict = {
460
703
  'method': 'deals.subscribe',
461
- 'params': subscribedSymbols,
704
+ 'params': {'market_list': subscribedSymbols},
462
705
  'id': self.request_id(),
463
706
  }
464
- self.options['watchTradesSubscriptions'] = subscribedSymbols
465
- request = self.deep_extend(message, params)
466
- trades = await self.watch(url, messageHash, request, subscriptionHash)
707
+ trades = await self.watch_multiple(url, messageHashes, self.deep_extend(subscribe, params), subscriptionHashes)
708
+ if self.newUpdates:
709
+ return trades
467
710
  return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
468
711
 
469
- async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
712
+ async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
470
713
  """
471
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot004_websocket017_depth_subscribe_multi
472
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures002_websocket011_depth_subscribe_multi
473
714
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
474
- :param str symbol: unified symbol of the market to fetch the order book for
715
+
716
+ https://docs.coinex.com/api/v2/spot/market/ws/market-depth
717
+ https://docs.coinex.com/api/v2/futures/market/ws/market-depth
718
+
719
+ :param str[] symbols: unified array of symbols
475
720
  :param int [limit]: the maximum amount of order book entries to return
476
721
  :param dict [params]: extra parameters specific to the exchange API endpoint
477
722
  :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
478
723
  """
479
724
  await self.load_markets()
480
- market = self.market(symbol)
481
- symbol = market['symbol']
725
+ watchOrderBookSubscriptions: dict = {}
726
+ messageHashes = []
727
+ market = None
482
728
  type = None
483
- type, params = self.handle_market_type_and_params('watchOrderBook', market, params)
484
- url = self.urls['api']['ws'][type]
485
- name = 'orderbook'
486
- messageHash = name + ':' + symbol
487
- options = self.safe_value(self.options, 'watchOrderBook', {})
488
- limits = self.safe_value(options, 'limits', [])
729
+ callerMethodName = None
730
+ callerMethodName, params = self.handle_param_string(params, 'callerMethodName', 'watchOrderBookForSymbols')
731
+ type, params = self.handle_market_type_and_params(callerMethodName, None, params)
732
+ options = self.safe_dict(self.options, 'watchOrderBook', {})
733
+ limits = self.safe_list(options, 'limits', [])
489
734
  if limit is None:
490
- limit = self.safe_value(options, 'defaultLimit', 50)
735
+ limit = self.safe_integer(options, 'defaultLimit', 50)
491
736
  if not self.in_array(limit, limits):
492
- raise NotSupported(self.id + ' watchOrderBook() limit must be one of ' + ', '.join(limits))
737
+ raise NotSupported(self.id + ' watchOrderBookForSymbols() limit must be one of ' + ', '.join(limits))
493
738
  defaultAggregation = self.safe_string(options, 'defaultAggregation', '0')
494
- aggregations = self.safe_value(options, 'aggregations', [])
739
+ aggregations = self.safe_list(options, 'aggregations', [])
495
740
  aggregation = self.safe_string(params, 'aggregation', defaultAggregation)
496
741
  if not self.in_array(aggregation, aggregations):
497
- raise NotSupported(self.id + ' watchOrderBook() aggregation must be one of ' + ', '.join(aggregations))
742
+ raise NotSupported(self.id + ' watchOrderBookForSymbols() aggregation must be one of ' + ', '.join(aggregations))
498
743
  params = self.omit(params, 'aggregation')
499
- watchOrderBookSubscriptions = self.safe_value(self.options, 'watchOrderBookSubscriptions', {})
500
- watchOrderBookSubscriptions[symbol] = [market['id'], limit, aggregation, True]
501
- subscribe = {
502
- 'method': 'depth.subscribe_multi',
744
+ symbolsDefined = (symbols is not None)
745
+ if symbolsDefined:
746
+ for i in range(0, len(symbols)):
747
+ symbol = symbols[i]
748
+ market = self.market(symbol)
749
+ messageHashes.append('orderbook:' + market['symbol'])
750
+ watchOrderBookSubscriptions[symbol] = [market['id'], limit, aggregation, True]
751
+ else:
752
+ messageHashes.append('orderbook')
753
+ marketList = list(watchOrderBookSubscriptions.values())
754
+ subscribe: dict = {
755
+ 'method': 'depth.subscribe',
756
+ 'params': {'market_list': marketList},
503
757
  'id': self.request_id(),
504
- 'params': list(watchOrderBookSubscriptions.values()),
505
758
  }
506
- self.options['watchOrderBookSubscriptions'] = watchOrderBookSubscriptions
507
- subscriptionHash = self.hash(self.encode(self.json(watchOrderBookSubscriptions)), 'sha256')
508
- request = self.deep_extend(subscribe, params)
509
- orderbook = await self.watch(url, messageHash, request, subscriptionHash, request)
510
- return orderbook.limit()
511
-
512
- async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
513
- """
514
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures002_websocket023_kline_subscribe
515
- watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
516
- :param str symbol: unified symbol of the market to fetch OHLCV data for
517
- :param str timeframe: the length of time each candle represents
518
- :param int [since]: timestamp in ms of the earliest candle to fetch
519
- :param int [limit]: the maximum amount of candles to fetch
520
- :param dict [params]: extra parameters specific to the exchange API endpoint
521
- :returns int[][]: A list of candles ordered, open, high, low, close, volume
522
- """
523
- await self.load_markets()
524
- market = self.market(symbol)
525
- symbol = market['symbol']
526
- type = None
527
- type, params = self.handle_market_type_and_params('watchOHLCV', market, params)
528
- if type != 'swap':
529
- raise NotSupported(self.id + ' watchOHLCV() is only supported for swap markets. Try using fetchOHLCV() instead')
759
+ subscriptionHashes = self.hash(self.encode(self.json(watchOrderBookSubscriptions)), 'sha256')
530
760
  url = self.urls['api']['ws'][type]
531
- messageHash = 'ohlcv'
532
- watchOHLCVWarning = self.safe_bool(self.options, 'watchOHLCVWarning', True)
533
- client = self.safe_value(self.clients, url, {})
534
- clientSub = self.safe_value(client, 'subscriptions', {})
535
- existingSubscription = self.safe_value(clientSub, messageHash)
536
- subSymbol = self.safe_string(existingSubscription, 'symbol')
537
- subTimeframe = self.safe_string(existingSubscription, 'timeframe')
538
- # due to nature of coinex response can only watch one symbol at a time
539
- if watchOHLCVWarning and existingSubscription is not None and (subSymbol != symbol or subTimeframe != timeframe):
540
- raise ExchangeError(self.id + ' watchOHLCV() can only watch one symbol and timeframe at a time. To supress self warning set watchOHLCVWarning to False in options')
541
- timeframes = self.safe_value(self.options, 'timeframes', {})
542
- subscribe = {
543
- 'method': 'kline.subscribe',
544
- 'id': self.request_id(),
545
- 'params': [
546
- market['id'],
547
- self.safe_integer(timeframes, timeframe),
548
- ],
549
- }
550
- subscription = {
551
- 'symbol': symbol,
552
- 'timeframe': timeframe,
553
- }
554
- request = self.deep_extend(subscribe, params)
555
- ohlcvs = await self.watch(url, messageHash, request, messageHash, subscription)
761
+ orderbooks = await self.watch_multiple(url, messageHashes, self.deep_extend(subscribe, params), subscriptionHashes)
556
762
  if self.newUpdates:
557
- limit = ohlcvs.getLimit(symbol, limit)
558
- return self.filter_by_since_limit(ohlcvs, since, limit, 0)
763
+ return orderbooks
764
+ return orderbooks.limit()
559
765
 
560
- async def fetch_ohlcv_ws(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
766
+ async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
561
767
  """
562
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot004_websocket005_kline_query
563
- query historical candlestick data containing the open, high, low, and close price, and the volume of a market
564
- :param str symbol: unified symbol of the market to query OHLCV data for
565
- :param str timeframe: the length of time each candle represents
566
- :param int|None since: timestamp in ms of the earliest candle to fetch
567
- :param int|None limit: the maximum amount of candles to fetch
568
- :param dict params: extra parameters specific to the exchange API endpoint
569
- :param int|None params['end']: the end time for spot markets, self.seconds() is set
570
- :returns int[][]: A list of candles ordered, open, high, low, close, volume
768
+ watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
769
+
770
+ https://docs.coinex.com/api/v2/spot/market/ws/market-depth
771
+ https://docs.coinex.com/api/v2/futures/market/ws/market-depth
772
+
773
+ :param str symbol: unified symbol of the market to fetch the order book for
774
+ :param int [limit]: the maximum amount of order book entries to return
775
+ :param dict [params]: extra parameters specific to the exchange API endpoint
776
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
571
777
  """
572
- await self.load_markets()
573
- market = self.market(symbol)
574
- type, query = self.handle_market_type_and_params('fetchOHLCV', market, params)
575
- url = self.urls['api']['ws'][type]
576
- symbol = market['symbol']
577
- messageHash = 'ohlcv'
578
- timeframes = self.safe_value(self.options, 'timeframes', {})
579
- timeframe = self.safe_string(timeframes, timeframe, timeframe)
580
- if since is None:
581
- since = 1640995200 # January 1, 2022
582
- id = self.request_id()
583
- subscribe = {
584
- 'method': 'kline.query',
585
- 'params': [
586
- market['id'],
587
- self.parse_to_int(since / 1000),
588
- self.safe_integer(params, 'end', self.seconds()),
589
- self.parse_to_int(timeframe),
590
- ],
591
- 'id': id,
592
- }
593
- subscription = {
594
- 'id': id,
595
- 'future': messageHash,
596
- }
597
- subscriptionHash = id
598
- request = self.deep_extend(subscribe, query)
599
- ohlcvs = await self.watch(url, messageHash, request, subscriptionHash, subscription)
600
- return self.filter_by_since_limit(ohlcvs, since, limit, 0)
778
+ params['callerMethodName'] = 'watchOrderBook'
779
+ return await self.watch_order_book_for_symbols([symbol], limit, params)
601
780
 
602
781
  def handle_delta(self, bookside, delta):
603
782
  bidAsk = self.parse_bid_ask(delta, 0, 1)
@@ -611,48 +790,51 @@ class coinex(ccxt.async_support.coinex):
611
790
  #
612
791
  # {
613
792
  # "method": "depth.update",
614
- # "params": [
615
- # False,
616
- # {
793
+ # "data": {
794
+ # "market": "BTCUSDT",
795
+ # "is_full": True,
796
+ # "depth": {
617
797
  # "asks": [
618
- # ["46350.52", "1.07871851"],
619
- # ...
798
+ # [
799
+ # "30740.00",
800
+ # "0.31763545"
801
+ # ],
620
802
  # ],
621
803
  # "bids": [
622
- # ["46349.61", "0.04000000"],
623
- # ...
804
+ # [
805
+ # "30736.00",
806
+ # "0.04857373"
807
+ # ],
624
808
  # ],
625
- # "last": "46349.93",
626
- # "time": 1639987469166,
627
- # "checksum": 1533284725
628
- # },
629
- # "BTCUSDT"
630
- # ],
809
+ # "last": "30746.28",
810
+ # "updated_at": 1689152421692,
811
+ # "checksum": 2578768879
812
+ # }
813
+ # },
631
814
  # "id": null
632
815
  # }
633
816
  #
634
- params = self.safe_value(message, 'params', [])
635
- fullOrderBook = self.safe_value(params, 0)
636
- orderbook = self.safe_value(params, 1)
637
- marketId = self.safe_string(params, 2)
638
817
  defaultType = self.safe_string(self.options, 'defaultType')
818
+ data = self.safe_dict(message, 'data', {})
819
+ depth = self.safe_dict(data, 'depth', {})
820
+ marketId = self.safe_string(data, 'market')
639
821
  market = self.safe_market(marketId, None, None, defaultType)
640
822
  symbol = market['symbol']
641
823
  name = 'orderbook'
642
824
  messageHash = name + ':' + symbol
643
- timestamp = self.safe_integer(orderbook, 'time')
825
+ timestamp = self.safe_integer(depth, 'updated_at')
644
826
  currentOrderBook = self.safe_value(self.orderbooks, symbol)
827
+ fullOrderBook = self.safe_bool(data, 'is_full', False)
645
828
  if fullOrderBook:
646
- snapshot = self.parse_order_book(orderbook, symbol, timestamp)
829
+ snapshot = self.parse_order_book(depth, symbol, timestamp)
647
830
  if currentOrderBook is None:
648
- orderbook = self.order_book(snapshot)
649
- self.orderbooks[symbol] = orderbook
831
+ self.orderbooks[symbol] = self.order_book(snapshot)
650
832
  else:
651
833
  orderbook = self.orderbooks[symbol]
652
834
  orderbook.reset(snapshot)
653
835
  else:
654
- asks = self.safe_value(orderbook, 'asks', [])
655
- bids = self.safe_value(orderbook, 'bids', [])
836
+ asks = self.safe_list(depth, 'asks', [])
837
+ bids = self.safe_list(depth, 'bids', [])
656
838
  self.handle_deltas(currentOrderBook['asks'], asks)
657
839
  self.handle_deltas(currentOrderBook['bids'], bids)
658
840
  currentOrderBook['nonce'] = timestamp
@@ -663,24 +845,52 @@ class coinex(ccxt.async_support.coinex):
663
845
  client.resolve(self.orderbooks[symbol], messageHash)
664
846
 
665
847
  async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
848
+ """
849
+ watches information on multiple orders made by the user
850
+
851
+ https://docs.coinex.com/api/v2/spot/order/ws/user-order
852
+ https://docs.coinex.com/api/v2/futures/order/ws/user-order
853
+
854
+ :param str symbol: unified market symbol of the market orders were made in
855
+ :param int [since]: the earliest time in ms to fetch orders for
856
+ :param int [limit]: the maximum number of order structures to retrieve
857
+ :param dict [params]: extra parameters specific to the exchange API endpoint
858
+ :param bool [params.trigger]: if the orders to watch are trigger orders or not
859
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
860
+ """
666
861
  await self.load_markets()
667
- await self.authenticate(params)
862
+ trigger = self.safe_bool_2(params, 'trigger', 'stop')
863
+ params = self.omit(params, ['trigger', 'stop'])
668
864
  messageHash = 'orders'
669
865
  market = None
670
- type, query = self.handle_market_type_and_params('watchOrders', market, params)
671
- message = {
672
- 'method': 'order.subscribe',
673
- 'id': self.request_id(),
674
- }
866
+ marketList = None
675
867
  if symbol is not None:
676
868
  market = self.market(symbol)
677
869
  symbol = market['symbol']
678
- message['params'] = [market['id']]
870
+ type = None
871
+ type, params = self.handle_market_type_and_params('watchOrders', market, params, 'spot')
872
+ await self.authenticate(type)
873
+ if symbol is not None:
874
+ marketList = [market['id']]
679
875
  messageHash += ':' + symbol
680
876
  else:
681
- message['params'] = []
877
+ marketList = []
878
+ if type == 'spot':
879
+ messageHash += ':spot'
880
+ else:
881
+ messageHash += ':swap'
882
+ method = None
883
+ if trigger:
884
+ method = 'stop.subscribe'
885
+ else:
886
+ method = 'order.subscribe'
887
+ message: dict = {
888
+ 'method': method,
889
+ 'params': {'market_list': marketList},
890
+ 'id': self.request_id(),
891
+ }
682
892
  url = self.urls['api']['ws'][type]
683
- request = self.deep_extend(message, query)
893
+ request = self.deep_extend(message, params)
684
894
  orders = await self.watch(url, messageHash, request, messageHash, request)
685
895
  if self.newUpdates:
686
896
  limit = orders.getLimit(symbol, limit)
@@ -688,280 +898,372 @@ class coinex(ccxt.async_support.coinex):
688
898
 
689
899
  def handle_orders(self, client: Client, message):
690
900
  #
691
- # spot
901
+ # spot
692
902
  #
693
- # {
694
- # "method": "order.update",
695
- # "params": [
696
- # 1,
697
- # {
698
- # "id": 77782469357,
699
- # "type": 1,
700
- # "side": 2,
701
- # "user": 1849116,
702
- # "account": 0,
703
- # "option": 2,
704
- # "ctime": 1653961043.048967,
705
- # "mtime": 1653961043.048967,
706
- # "market": "BTCUSDT",
707
- # "source": "web",
708
- # "client_id": '',
709
- # "price": "1.00",
710
- # "amount": "1.00000000",
711
- # "taker_fee": "0.0020",
712
- # "maker_fee": "0.0020",
713
- # "left": "1.00000000",
714
- # "deal_stock": "0",
715
- # "deal_money": "0",
716
- # "money_fee": "0",
717
- # "stock_fee": "0",
718
- # "asset_fee": "0",
719
- # "fee_discount": "1",
720
- # "last_deal_amount": "0",
721
- # "last_deal_price": "0",
722
- # "last_deal_time": 0,
723
- # "last_deal_id": 0,
724
- # "last_role": 0,
725
- # "fee_asset": null,
726
- # "stop_id": 0
727
- # }
728
- # ],
729
- # "id": null
730
- # }
903
+ # {
904
+ # "method": "order.update",
905
+ # "data": {
906
+ # "event": "put",
907
+ # "order": {
908
+ # "order_id": 12750,
909
+ # "market": "BTCUSDT",
910
+ # "margin_market": "BTCUSDT",
911
+ # "type": "limit",
912
+ # "side": "buy",
913
+ # "price": "5999.00",
914
+ # "amount": "1.50000000",
915
+ # "unfill_amount": "1.50000000",
916
+ # "fill_value": "1.50000000",
917
+ # "taker_fee_rate": "0.0001",
918
+ # "maker_fee_rate": "0.0001",
919
+ # "base_ccy_fee": "0.0001",
920
+ # "quote_ccy_fee": "0.0001",
921
+ # "discount_ccy_fee": "0.0001",
922
+ # "last_fill_amount": "0",
923
+ # "last_fill_price": "0",
924
+ # "client_id": "buy1_1234",
925
+ # "created_at": 1689152421692,
926
+ # "updated_at": 1689152421692,
927
+ # }
928
+ # },
929
+ # "id": null
930
+ # }
731
931
  #
732
- # swap
932
+ # spot stop
933
+ #
934
+ # {
935
+ # "method": "stop.update",
936
+ # "data": {
937
+ # "event": 1,
938
+ # "stop": {
939
+ # "stop_id": 102067022299,
940
+ # "market": "BTCUSDT",
941
+ # "margin_market": "BTCUSDT",
942
+ # "type": "limit",
943
+ # "side": "buy",
944
+ # "price": "20000.00",
945
+ # "amount": "0.10000000",
946
+ # "trigger_price": "20000.00",
947
+ # "trigger_direction": "lower",
948
+ # "taker_fee_rate": "0.0016",
949
+ # "maker_fee_rate": "0.0016",
950
+ # "status": "active_success",
951
+ # "client_id": "",
952
+ # "created_at": 1689152996689,
953
+ # "updated_at": 1689152996689,
954
+ # }
955
+ # },
956
+ # "id": null
957
+ # }
958
+ #
959
+ # swap
960
+ #
961
+ # {
962
+ # "method": "order.update",
963
+ # "data": {
964
+ # "event": "put",
965
+ # "order": {
966
+ # "order_id": 98388656341,
967
+ # "stop_id": 0,
968
+ # "market": "BTCUSDT",
969
+ # "side": "buy",
970
+ # "type": "limit",
971
+ # "amount": "0.0010",
972
+ # "price": "50000.00",
973
+ # "unfilled_amount": "0.0010",
974
+ # "filled_amount": "0",
975
+ # "filled_value": "0",
976
+ # "fee": "0",
977
+ # "fee_ccy": "USDT",
978
+ # "taker_fee_rate": "0.00046",
979
+ # "maker_fee_rate": "0.00000000000000000000",
980
+ # "client_id": "",
981
+ # "last_filled_amount": "0.0010",
982
+ # "last_filled_price": "30721.35",
983
+ # "created_at": 1689145715129,
984
+ # "updated_at": 1689145715129
985
+ # }
986
+ # },
987
+ # "id": null
988
+ # }
733
989
  #
734
- # {
735
- # "method": "order.update",
736
- # "params": [
737
- # 1,
738
- # {
739
- # "order_id": 23423462821,
740
- # "position_id": 0,
741
- # "stop_id": 0,
742
- # "market": "BTCUSDT",
743
- # "type": 1,
744
- # "side": 2,
745
- # "target": 0,
746
- # "effect_type": 1,
747
- # "user_id": 1849116,
748
- # "create_time": 1653961509.25049,
749
- # "update_time": 1653961509.25049,
750
- # "source": "web",
751
- # "price": "1.00",
752
- # "amount": "1.0000",
753
- # "taker_fee": "0.00050",
754
- # "maker_fee": "0.00030",
755
- # "left": "1.0000",
756
- # "deal_stock": "0.00000000000000000000",
757
- # "deal_fee": "0.00000000000000000000",
758
- # "deal_profit": "0.00000000000000000000",
759
- # "last_deal_amount": "0.00000000000000000000",
760
- # "last_deal_price": "0.00000000000000000000",
761
- # "last_deal_time": 0,
762
- # "last_deal_id": 0,
763
- # "last_deal_type": 0,
764
- # "last_deal_role": 0,
765
- # "client_id": '',
766
- # "fee_asset": '',
767
- # "fee_discount": "0.00000000000000000000",
768
- # "deal_asset_fee": "0.00000000000000000000",
769
- # "leverage": "3",
770
- # "position_type": 2
771
- # }
772
- # ],
773
- # "id": null
774
- # }
775
- #
776
- params = self.safe_value(message, 'params', [])
777
- order = self.safe_value(params, 1, {})
990
+ # swap stop
991
+ #
992
+ # {
993
+ # "method": "stop.update",
994
+ # "data": {
995
+ # "event": "put",
996
+ # "stop": {
997
+ # "stop_id": 98389557871,
998
+ # "market": "BTCUSDT",
999
+ # "side": "sell",
1000
+ # "type": "limit",
1001
+ # "price": "20000.00",
1002
+ # "amount": "0.0100",
1003
+ # "trigger_price": "20000.00",
1004
+ # "trigger_direction": "higer",
1005
+ # "trigger_price_type": "index_price",
1006
+ # "taker_fee_rate": "0.00046",
1007
+ # "maker_fee_rate": "0.00026",
1008
+ # "client_id": "",
1009
+ # "created_at": 1689146382674,
1010
+ # "updated_at": 1689146382674
1011
+ # }
1012
+ # },
1013
+ # "id": null
1014
+ # }
1015
+ #
1016
+ data = self.safe_dict(message, 'data', {})
1017
+ order = self.safe_dict_2(data, 'order', 'stop', {})
778
1018
  parsedOrder = self.parse_ws_order(order)
1019
+ symbol = parsedOrder['symbol']
1020
+ market = self.market(symbol)
779
1021
  if self.orders is None:
780
1022
  limit = self.safe_integer(self.options, 'ordersLimit', 1000)
781
1023
  self.orders = ArrayCacheBySymbolById(limit)
782
1024
  orders = self.orders
783
1025
  orders.append(parsedOrder)
784
1026
  messageHash = 'orders'
785
- client.resolve(self.orders, messageHash)
786
- messageHash += ':' + parsedOrder['symbol']
1027
+ messageWithType = messageHash + ':' + market['type']
1028
+ client.resolve(self.orders, messageWithType)
1029
+ messageHash += ':' + symbol
787
1030
  client.resolve(self.orders, messageHash)
788
1031
 
789
1032
  def parse_ws_order(self, order, market=None):
790
1033
  #
791
- # spot
1034
+ # spot
792
1035
  #
793
- # {
794
- # "id": 77782469357,
795
- # "type": 1,
796
- # "side": 2,
797
- # "user": 1849116,
798
- # "account": 0,
799
- # "option": 2,
800
- # "ctime": 1653961043.048967,
801
- # "mtime": 1653961043.048967,
802
- # "market": "BTCUSDT",
803
- # "source": "web",
804
- # "client_id": '',
805
- # "price": "1.00",
806
- # "amount": "1.00000000",
807
- # "taker_fee": "0.0020",
808
- # "maker_fee": "0.0020",
809
- # "left": "1.00000000",
810
- # "deal_stock": "0",
811
- # "deal_money": "0",
812
- # "money_fee": "0",
813
- # "stock_fee": "0",
814
- # "asset_fee": "0",
815
- # "fee_discount": "1",
816
- # "last_deal_amount": "0",
817
- # "last_deal_price": "0",
818
- # "last_deal_time": 0,
819
- # "last_deal_id": 0,
820
- # "last_role": 0,
821
- # "fee_asset": null,
822
- # "stop_id": 0
823
- # }
1036
+ # {
1037
+ # "order_id": 12750,
1038
+ # "market": "BTCUSDT",
1039
+ # "margin_market": "BTCUSDT",
1040
+ # "type": "limit",
1041
+ # "side": "buy",
1042
+ # "price": "5999.00",
1043
+ # "amount": "1.50000000",
1044
+ # "unfill_amount": "1.50000000",
1045
+ # "fill_value": "1.50000000",
1046
+ # "taker_fee_rate": "0.0001",
1047
+ # "maker_fee_rate": "0.0001",
1048
+ # "base_ccy_fee": "0.0001",
1049
+ # "quote_ccy_fee": "0.0001",
1050
+ # "discount_ccy_fee": "0.0001",
1051
+ # "last_fill_amount": "0",
1052
+ # "last_fill_price": "0",
1053
+ # "client_id": "buy1_1234",
1054
+ # "created_at": 1689152421692,
1055
+ # "updated_at": 1689152421692,
1056
+ # }
824
1057
  #
825
- # swap
1058
+ # spot stop
1059
+ #
1060
+ # {
1061
+ # "stop_id": 102067022299,
1062
+ # "market": "BTCUSDT",
1063
+ # "margin_market": "BTCUSDT",
1064
+ # "type": "limit",
1065
+ # "side": "buy",
1066
+ # "price": "20000.00",
1067
+ # "amount": "0.10000000",
1068
+ # "trigger_price": "20000.00",
1069
+ # "trigger_direction": "lower",
1070
+ # "taker_fee_rate": "0.0016",
1071
+ # "maker_fee_rate": "0.0016",
1072
+ # "status": "active_success",
1073
+ # "client_id": "",
1074
+ # "created_at": 1689152996689,
1075
+ # "updated_at": 1689152996689,
1076
+ # }
1077
+ #
1078
+ # swap
1079
+ #
1080
+ # {
1081
+ # "order_id": 98388656341,
1082
+ # "stop_id": 0,
1083
+ # "market": "BTCUSDT",
1084
+ # "side": "buy",
1085
+ # "type": "limit",
1086
+ # "amount": "0.0010",
1087
+ # "price": "50000.00",
1088
+ # "unfilled_amount": "0.0010",
1089
+ # "filled_amount": "0",
1090
+ # "filled_value": "0",
1091
+ # "fee": "0",
1092
+ # "fee_ccy": "USDT",
1093
+ # "taker_fee_rate": "0.00046",
1094
+ # "maker_fee_rate": "0.00000000000000000000",
1095
+ # "client_id": "",
1096
+ # "last_filled_amount": "0.0010",
1097
+ # "last_filled_price": "30721.35",
1098
+ # "created_at": 1689145715129,
1099
+ # "updated_at": 1689145715129
1100
+ # }
1101
+ #
1102
+ # swap stop
826
1103
  #
827
- # {
828
- # "order_id": 23423462821,
829
- # "position_id": 0,
830
- # "stop_id": 0,
831
- # "market": "BTCUSDT",
832
- # "type": 1,
833
- # "side": 2,
834
- # "target": 0,
835
- # "effect_type": 1,
836
- # "user_id": 1849116,
837
- # "create_time": 1653961509.25049,
838
- # "update_time": 1653961509.25049,
839
- # "source": "web",
840
- # "price": "1.00",
841
- # "amount": "1.0000",
842
- # "taker_fee": "0.00050",
843
- # "maker_fee": "0.00030",
844
- # "left": "1.0000",
845
- # "deal_stock": "0.00000000000000000000",
846
- # "deal_fee": "0.00000000000000000000",
847
- # "deal_profit": "0.00000000000000000000",
848
- # "last_deal_amount": "0.00000000000000000000",
849
- # "last_deal_price": "0.00000000000000000000",
850
- # "last_deal_time": 0,
851
- # "last_deal_id": 0,
852
- # "last_deal_type": 0,
853
- # "last_deal_role": 0,
854
- # "client_id": '',
855
- # "fee_asset": '',
856
- # "fee_discount": "0.00000000000000000000",
857
- # "deal_asset_fee": "0.00000000000000000000",
858
- # "leverage": "3",
859
- # "position_type": 2
860
- # }
861
- #
862
- # order.update_stop
863
- #
864
- # {
865
- # "id": 78006745870,
866
- # "type": 1,
867
- # "side": 2,
868
- # "user": 1849116,
869
- # "account": 1,
870
- # "option": 70,
871
- # "direction": 1,
872
- # "ctime": 1654171725.131976,
873
- # "mtime": 1654171725.131976,
874
- # "market": "BTCUSDT",
875
- # "source": "web",
876
- # "client_id": '',
877
- # "stop_price": "1.00",
878
- # "price": "1.00",
879
- # "amount": "1.00000000",
880
- # "taker_fee": "0.0020",
881
- # "maker_fee": "0.0020",
882
- # "fee_discount": "1",
883
- # "fee_asset": null,
884
- # "status": 0
885
- # }
886
- #
887
- timestamp = self.safe_timestamp_2(order, 'update_time', 'mtime')
1104
+ # {
1105
+ # "stop_id": 98389557871,
1106
+ # "market": "BTCUSDT",
1107
+ # "side": "sell",
1108
+ # "type": "limit",
1109
+ # "price": "20000.00",
1110
+ # "amount": "0.0100",
1111
+ # "trigger_price": "20000.00",
1112
+ # "trigger_direction": "higer",
1113
+ # "trigger_price_type": "index_price",
1114
+ # "taker_fee_rate": "0.00046",
1115
+ # "maker_fee_rate": "0.00026",
1116
+ # "client_id": "",
1117
+ # "created_at": 1689146382674,
1118
+ # "updated_at": 1689146382674
1119
+ # }
1120
+ #
1121
+ timestamp = self.safe_integer(order, 'created_at')
888
1122
  marketId = self.safe_string(order, 'market')
889
- typeCode = self.safe_string(order, 'type')
890
- type = self.safe_string({
891
- '1': 'limit',
892
- '2': 'market',
893
- }, typeCode)
894
- sideCode = self.safe_string(order, 'side')
895
- side = self.safe_string({
896
- '1': 'sell',
897
- '2': 'buy',
898
- }, sideCode)
899
- remaining = self.safe_string(order, 'left')
900
- amount = self.safe_string(order, 'amount')
901
1123
  status = self.safe_string(order, 'status')
902
- defaultType = self.safe_string(self.options, 'defaultType')
1124
+ isSpot = ('margin_market' in order)
1125
+ defaultType = 'spot' if isSpot else 'swap'
903
1126
  market = self.safe_market(marketId, market, None, defaultType)
904
- cost = self.safe_string(order, 'deal_money')
905
- filled = self.safe_string(order, 'deal_stock')
906
- average = None
907
- if market['swap']:
908
- leverage = self.safe_string(order, 'leverage')
909
- cost = Precise.string_div(filled, leverage)
910
- average = Precise.string_div(filled, amount)
911
- filled = None
912
1127
  fee = None
913
- feeCost = self.omit_zero(self.safe_string(order, 'money_fee'))
1128
+ feeCost = self.omit_zero(self.safe_string_2(order, 'fee', 'quote_ccy_fee'))
914
1129
  if feeCost is not None:
915
- feeCurrencyId = self.safe_string(order, 'fee_asset', market['quote'])
1130
+ feeCurrencyId = self.safe_string(order, 'fee_ccy', market['quote'])
916
1131
  fee = {
917
1132
  'currency': self.safe_currency_code(feeCurrencyId),
918
1133
  'cost': feeCost,
919
1134
  }
920
1135
  return self.safe_order({
921
1136
  'info': order,
922
- 'id': self.safe_string_2(order, 'order_id', 'id'),
1137
+ 'id': self.safe_string_2(order, 'order_id', 'stop_id'),
923
1138
  'clientOrderId': self.safe_string(order, 'client_id'),
924
1139
  'datetime': self.iso8601(timestamp),
925
1140
  'timestamp': timestamp,
926
- 'lastTradeTimestamp': self.safe_timestamp(order, 'last_deal_time'),
1141
+ 'lastTradeTimestamp': self.safe_integer(order, 'updated_at'),
927
1142
  'symbol': market['symbol'],
928
- 'type': type,
1143
+ 'type': self.safe_string(order, 'type'),
929
1144
  'timeInForce': None,
930
1145
  'postOnly': None,
931
- 'side': side,
1146
+ 'side': self.safe_string(order, 'side'),
932
1147
  'price': self.safe_string(order, 'price'),
933
- 'stopPrice': self.safe_string(order, 'stop_price'),
934
- 'triggerPrice': self.safe_string(order, 'stop_price'),
935
- 'amount': amount,
936
- 'filled': filled,
937
- 'remaining': remaining,
938
- 'cost': cost,
939
- 'average': average,
1148
+ 'stopPrice': self.safe_string(order, 'trigger_price'),
1149
+ 'triggerPrice': self.safe_string(order, 'trigger_price'),
1150
+ 'amount': self.safe_string(order, 'amount'),
1151
+ 'filled': self.safe_string_2(order, 'filled_amount', 'fill_value'),
1152
+ 'remaining': self.safe_string_2(order, 'unfilled_amount', 'unfill_amount'),
1153
+ 'cost': None,
1154
+ 'average': None,
940
1155
  'status': self.parse_ws_order_status(status),
941
1156
  'fee': fee,
942
1157
  'trades': None,
943
1158
  }, market)
944
1159
 
945
1160
  def parse_ws_order_status(self, status):
946
- statuses = {
947
- '0': 'pending',
948
- '1': 'ok',
1161
+ statuses: dict = {
1162
+ 'active_success': 'open',
1163
+ 'active_fail': 'canceled',
1164
+ 'cancel': 'canceled',
949
1165
  }
950
1166
  return self.safe_string(statuses, status, status)
951
1167
 
1168
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
1169
+ """
1170
+ watches best bid & ask for symbols
1171
+
1172
+ https://docs.coinex.com/api/v2/spot/market/ws/market-bbo
1173
+ https://docs.coinex.com/api/v2/futures/market/ws/market-bbo
1174
+
1175
+ :param str[] [symbols]: unified symbol of the market to fetch the ticker for
1176
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1177
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1178
+ """
1179
+ await self.load_markets()
1180
+ marketIds = self.market_ids(symbols)
1181
+ messageHashes = []
1182
+ market = None
1183
+ symbolsDefined = (symbols is not None)
1184
+ if symbolsDefined:
1185
+ for i in range(0, len(symbols)):
1186
+ symbol = symbols[i]
1187
+ market = self.market(symbol)
1188
+ messageHashes.append('bidsasks:' + market['symbol'])
1189
+ else:
1190
+ messageHashes.append('bidsasks')
1191
+ type = None
1192
+ type, params = self.handle_market_type_and_params('watchBidsAsks', market, params)
1193
+ url = self.urls['api']['ws'][type]
1194
+ subscriptionHashes = ['all@bidsasks']
1195
+ subscribe: dict = {
1196
+ 'method': 'bbo.subscribe',
1197
+ 'params': {'market_list': marketIds},
1198
+ 'id': self.request_id(),
1199
+ }
1200
+ result = await self.watch_multiple(url, messageHashes, self.deep_extend(subscribe, params), subscriptionHashes)
1201
+ if self.newUpdates:
1202
+ return result
1203
+ return self.filter_by_array(self.bidsasks, 'symbol', symbols)
1204
+
1205
+ def handle_bid_ask(self, client: Client, message):
1206
+ #
1207
+ # {
1208
+ # "method": "bbo.update",
1209
+ # "data": {
1210
+ # "market": "BTCUSDT",
1211
+ # "updated_at": 1656660154,
1212
+ # "best_bid_price": "20000",
1213
+ # "best_bid_size": "0.1",
1214
+ # "best_ask_price": "20001",
1215
+ # "best_ask_size": "0.15"
1216
+ # },
1217
+ # "id": null
1218
+ # }
1219
+ #
1220
+ data = self.safe_dict(message, 'data', {})
1221
+ parsedTicker = self.parse_ws_bid_ask(data)
1222
+ symbol = parsedTicker['symbol']
1223
+ self.bidsasks[symbol] = parsedTicker
1224
+ messageHash = 'bidsasks:' + symbol
1225
+ client.resolve(parsedTicker, messageHash)
1226
+
1227
+ def parse_ws_bid_ask(self, ticker, market=None):
1228
+ #
1229
+ # {
1230
+ # "market": "BTCUSDT",
1231
+ # "updated_at": 1656660154,
1232
+ # "best_bid_price": "20000",
1233
+ # "best_bid_size": "0.1",
1234
+ # "best_ask_price": "20001",
1235
+ # "best_ask_size": "0.15"
1236
+ # }
1237
+ #
1238
+ defaultType = self.safe_string(self.options, 'defaultType')
1239
+ marketId = self.safe_string(ticker, 'market')
1240
+ market = self.safe_market(marketId, market, None, defaultType)
1241
+ timestamp = self.safe_integer(ticker, 'updated_at')
1242
+ return self.safe_ticker({
1243
+ 'symbol': self.safe_symbol(marketId, market, None, defaultType),
1244
+ 'timestamp': timestamp,
1245
+ 'datetime': self.iso8601(timestamp),
1246
+ 'ask': self.safe_number(ticker, 'best_ask_price'),
1247
+ 'askVolume': self.safe_number(ticker, 'best_ask_size'),
1248
+ 'bid': self.safe_number(ticker, 'best_bid_price'),
1249
+ 'bidVolume': self.safe_number(ticker, 'best_bid_size'),
1250
+ 'info': ticker,
1251
+ }, market)
1252
+
952
1253
  def handle_message(self, client: Client, message):
953
- error = self.safe_value(message, 'error')
954
- if error is not None:
955
- raise ExchangeError(self.id + ' ' + self.json(error))
956
1254
  method = self.safe_string(message, 'method')
957
- handlers = {
1255
+ error = self.safe_string(message, 'message')
1256
+ if error is not None:
1257
+ self.handle_errors(None, None, client.url, method, None, self.json(error), message, None, None)
1258
+ handlers: dict = {
958
1259
  'state.update': self.handle_ticker,
959
- 'asset.update': self.handle_balance,
1260
+ 'balance.update': self.handle_balance,
960
1261
  'deals.update': self.handle_trades,
1262
+ 'user_deals.update': self.handle_my_trades,
961
1263
  'depth.update': self.handle_order_book,
962
1264
  'order.update': self.handle_orders,
963
- 'kline.update': self.handle_ohlcv,
964
- 'order.update_stop': self.handle_orders,
1265
+ 'stop.update': self.handle_orders,
1266
+ 'bbo.update': self.handle_bid_ask,
965
1267
  }
966
1268
  handler = self.safe_value(handlers, method)
967
1269
  if handler is not None:
@@ -969,92 +1271,90 @@ class coinex(ccxt.async_support.coinex):
969
1271
  return
970
1272
  self.handle_subscription_status(client, message)
971
1273
 
1274
+ def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
1275
+ if response is None:
1276
+ return None
1277
+ #
1278
+ # {"id": 1, "code": 20001, "message": "invalid argument"}
1279
+ # {"id": 2, "code": 21001, "message": "require auth"}
1280
+ # {"id": 1, "code": 21002, "message": "Signature Incorrect"}
1281
+ #
1282
+ message = self.safe_string_lower(response, 'message')
1283
+ isErrorMessage = (message is not None) and (message != 'ok')
1284
+ errorCode = self.safe_string(response, 'code')
1285
+ isErrorCode = (errorCode is not None) and (errorCode != '0')
1286
+ if isErrorCode or isErrorMessage:
1287
+ feedback = self.id + ' ' + body
1288
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
1289
+ self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
1290
+ raise ExchangeError(feedback)
1291
+ return None
1292
+
972
1293
  def handle_authentication_message(self, client: Client, message):
1294
+ #
1295
+ # success
973
1296
  #
974
1297
  # {
975
- # "error": null,
976
- # "result": {
977
- # "status": "success"
978
- # },
979
- # "id": 1
1298
+ # "id": 1,
1299
+ # "code": 0,
1300
+ # "message": "OK"
1301
+ # }
1302
+ #
1303
+ # fail
1304
+ #
1305
+ # {
1306
+ # "id": 1,
1307
+ # "code": 21002,
1308
+ # "message": ""
980
1309
  # }
981
1310
  #
982
- messageHashSpot = 'authenticated:spot'
983
- messageHashSwap = 'authenticated:swap'
984
- # client.resolve(message, messageHashSpot)
985
- # client.resolve(message, messageHashSwap)
986
- spotFuture = self.safe_value(client.futures, messageHashSpot)
987
- spotFuture.resolve(True)
988
- swapFutures = self.safe_value(client.futures, messageHashSwap)
989
- swapFutures.resolve(True)
990
- return message
1311
+ status = self.safe_string_lower(message, 'message')
1312
+ errorCode = self.safe_string(message, 'code')
1313
+ messageHash = 'authenticated'
1314
+ if (status == 'ok') or (errorCode == '0'):
1315
+ future = self.safe_value(client.futures, messageHash)
1316
+ future.resolve(True)
1317
+ else:
1318
+ error = AuthenticationError(self.json(message))
1319
+ client.reject(error, messageHash)
1320
+ if messageHash in client.subscriptions:
1321
+ del client.subscriptions[messageHash]
991
1322
 
992
1323
  def handle_subscription_status(self, client: Client, message):
993
1324
  id = self.safe_integer(message, 'id')
994
1325
  subscription = self.safe_value(client.subscriptions, id)
995
1326
  if subscription is not None:
996
1327
  futureIndex = self.safe_string(subscription, 'future')
997
- if futureIndex == 'ohlcv':
998
- self.handle_ohlcv(client, message)
999
- return
1000
1328
  future = self.safe_value(client.futures, futureIndex)
1001
1329
  if future is not None:
1002
1330
  future.resolve(True)
1003
1331
  del client.subscriptions[id]
1004
1332
 
1005
- async def authenticate(self, params={}):
1006
- type = None
1007
- type, params = self.handle_market_type_and_params('authenticate', None, params)
1333
+ async def authenticate(self, type: str):
1008
1334
  url = self.urls['api']['ws'][type]
1009
1335
  client = self.client(url)
1010
1336
  time = self.milliseconds()
1011
- isSpot = (type == 'spot')
1012
- spotMessageHash = 'authenticated:spot'
1013
- swapMessageHash = 'authenticated:swap'
1014
- messageHash = spotMessageHash if isSpot else swapMessageHash
1337
+ timestamp = str(time)
1338
+ messageHash = 'authenticated'
1015
1339
  future = client.future(messageHash)
1016
1340
  authenticated = self.safe_value(client.subscriptions, messageHash)
1017
- if type == 'spot':
1018
- if authenticated is not None:
1019
- return await future
1020
- requestId = self.request_id()
1021
- subscribe = {
1022
- 'id': requestId,
1023
- 'future': spotMessageHash,
1024
- }
1025
- signData = 'access_id=' + self.apiKey + '&tonce=' + self.number_to_string(time) + '&secret_key=' + self.secret
1026
- hash = self.hash(self.encode(signData), 'md5')
1027
- request = {
1028
- 'method': 'server.sign',
1029
- 'params': [
1030
- self.apiKey,
1031
- hash.upper(),
1032
- time,
1033
- ],
1034
- 'id': requestId,
1035
- }
1036
- self.watch(url, messageHash, request, requestId, subscribe)
1037
- client.subscriptions[messageHash] = True
1038
- return await future
1039
- else:
1040
- if authenticated is not None:
1041
- return await future
1042
- requestId = self.request_id()
1043
- subscribe = {
1044
- 'id': requestId,
1045
- 'future': swapMessageHash,
1046
- }
1047
- signData = 'access_id=' + self.apiKey + '&timestamp=' + self.number_to_string(time) + '&secret_key=' + self.secret
1048
- hash = self.hash(self.encode(signData), 'sha256', 'hex')
1049
- request = {
1050
- 'method': 'server.sign',
1051
- 'params': [
1052
- self.apiKey,
1053
- hash.lower(),
1054
- time,
1055
- ],
1056
- 'id': requestId,
1057
- }
1058
- self.watch(url, messageHash, request, requestId, subscribe)
1059
- client.subscriptions[messageHash] = True
1341
+ if authenticated is not None:
1060
1342
  return await future
1343
+ requestId = self.request_id()
1344
+ subscribe: dict = {
1345
+ 'id': requestId,
1346
+ 'future': messageHash,
1347
+ }
1348
+ hmac = self.hmac(self.encode(timestamp), self.encode(self.secret), hashlib.sha256, 'hex')
1349
+ request: dict = {
1350
+ 'id': requestId,
1351
+ 'method': 'server.sign',
1352
+ 'params': {
1353
+ 'access_id': self.apiKey,
1354
+ 'signed_str': hmac.lower(),
1355
+ 'timestamp': time,
1356
+ },
1357
+ }
1358
+ self.watch(url, messageHash, request, requestId, subscribe)
1359
+ client.subscriptions[messageHash] = True
1360
+ return await future