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