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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (546) hide show
  1. ccxt/__init__.py +36 -14
  2. ccxt/abstract/alpaca.py +4 -0
  3. ccxt/abstract/bigone.py +1 -1
  4. ccxt/abstract/binance.py +112 -48
  5. ccxt/abstract/binancecoinm.py +112 -48
  6. ccxt/abstract/binanceus.py +147 -83
  7. ccxt/abstract/binanceusdm.py +112 -48
  8. ccxt/abstract/bingx.py +133 -78
  9. ccxt/abstract/bitbank.py +5 -0
  10. ccxt/abstract/bitfinex.py +136 -65
  11. ccxt/abstract/bitfinex1.py +69 -0
  12. ccxt/abstract/bitflyer.py +1 -0
  13. ccxt/abstract/bitget.py +8 -1
  14. ccxt/abstract/bitmart.py +13 -1
  15. ccxt/abstract/bitopro.py +1 -0
  16. ccxt/abstract/bitpanda.py +0 -12
  17. ccxt/abstract/bitrue.py +3 -3
  18. ccxt/abstract/bitstamp.py +26 -3
  19. ccxt/abstract/blofin.py +24 -0
  20. ccxt/abstract/btcbox.py +1 -0
  21. ccxt/abstract/bybit.py +29 -14
  22. ccxt/abstract/cex.py +28 -29
  23. ccxt/abstract/coinbase.py +6 -0
  24. ccxt/abstract/coinbaseadvanced.py +94 -0
  25. ccxt/abstract/{coinbasepro.py → coinbaseexchange.py} +1 -0
  26. ccxt/abstract/coinbaseinternational.py +1 -1
  27. ccxt/abstract/coincatch.py +94 -0
  28. ccxt/abstract/coinex.py +233 -123
  29. ccxt/abstract/coinmetro.py +1 -0
  30. ccxt/abstract/cryptocom.py +14 -0
  31. ccxt/abstract/defx.py +69 -0
  32. ccxt/abstract/deribit.py +1 -0
  33. ccxt/abstract/digifinex.py +1 -0
  34. ccxt/abstract/ellipx.py +25 -0
  35. ccxt/abstract/gate.py +20 -0
  36. ccxt/abstract/gateio.py +20 -0
  37. ccxt/abstract/gemini.py +1 -0
  38. ccxt/abstract/hashkey.py +67 -0
  39. ccxt/abstract/hyperliquid.py +1 -1
  40. ccxt/abstract/independentreserve.py +6 -0
  41. ccxt/abstract/kraken.py +4 -3
  42. ccxt/abstract/krakenfutures.py +4 -0
  43. ccxt/abstract/kucoin.py +24 -0
  44. ccxt/abstract/kucoinfutures.py +34 -0
  45. ccxt/abstract/luno.py +2 -0
  46. ccxt/abstract/mexc.py +4 -0
  47. ccxt/abstract/myokx.py +340 -0
  48. ccxt/abstract/oceanex.py +5 -0
  49. ccxt/abstract/okx.py +30 -0
  50. ccxt/abstract/onetrading.py +0 -12
  51. ccxt/abstract/oxfun.py +34 -0
  52. ccxt/abstract/paradex.py +40 -0
  53. ccxt/abstract/phemex.py +1 -0
  54. ccxt/abstract/upbit.py +4 -0
  55. ccxt/abstract/vertex.py +19 -0
  56. ccxt/abstract/whitebit.py +31 -1
  57. ccxt/abstract/woo.py +6 -2
  58. ccxt/abstract/woofipro.py +119 -0
  59. ccxt/abstract/xt.py +153 -0
  60. ccxt/abstract/zonda.py +6 -0
  61. ccxt/ace.py +164 -60
  62. ccxt/alpaca.py +727 -63
  63. ccxt/ascendex.py +395 -249
  64. ccxt/async_support/__init__.py +36 -14
  65. ccxt/async_support/ace.py +164 -60
  66. ccxt/async_support/alpaca.py +727 -63
  67. ccxt/async_support/ascendex.py +396 -249
  68. ccxt/async_support/base/exchange.py +531 -155
  69. ccxt/async_support/base/ws/aiohttp_client.py +28 -5
  70. ccxt/async_support/base/ws/cache.py +3 -2
  71. ccxt/async_support/base/ws/client.py +26 -5
  72. ccxt/async_support/base/ws/fast_client.py +4 -3
  73. ccxt/async_support/base/ws/functions.py +1 -1
  74. ccxt/async_support/base/ws/future.py +40 -31
  75. ccxt/async_support/base/ws/order_book_side.py +3 -0
  76. ccxt/async_support/bequant.py +1 -1
  77. ccxt/async_support/bigone.py +329 -202
  78. ccxt/async_support/binance.py +3030 -1087
  79. ccxt/async_support/binancecoinm.py +2 -1
  80. ccxt/async_support/binanceus.py +12 -1
  81. ccxt/async_support/binanceusdm.py +3 -1
  82. ccxt/async_support/bingx.py +3104 -880
  83. ccxt/async_support/bit2c.py +119 -38
  84. ccxt/async_support/bitbank.py +215 -76
  85. ccxt/async_support/bitbns.py +124 -53
  86. ccxt/async_support/bitfinex.py +3236 -1078
  87. ccxt/async_support/bitfinex1.py +1711 -0
  88. ccxt/async_support/bitflyer.py +238 -49
  89. ccxt/async_support/bitget.py +1513 -563
  90. ccxt/async_support/bithumb.py +199 -65
  91. ccxt/async_support/bitmart.py +1320 -435
  92. ccxt/async_support/bitmex.py +308 -111
  93. ccxt/async_support/bitopro.py +256 -96
  94. ccxt/async_support/bitrue.py +365 -233
  95. ccxt/async_support/bitso.py +201 -89
  96. ccxt/async_support/bitstamp.py +438 -269
  97. ccxt/async_support/bitteam.py +179 -73
  98. ccxt/async_support/bitvavo.py +180 -70
  99. ccxt/async_support/bl3p.py +92 -25
  100. ccxt/async_support/blockchaincom.py +193 -79
  101. ccxt/async_support/blofin.py +392 -148
  102. ccxt/async_support/btcalpha.py +161 -55
  103. ccxt/async_support/btcbox.py +250 -34
  104. ccxt/async_support/btcmarkets.py +232 -85
  105. ccxt/async_support/btcturk.py +159 -60
  106. ccxt/async_support/bybit.py +2231 -1193
  107. ccxt/async_support/cex.py +1409 -1329
  108. ccxt/async_support/coinbase.py +1454 -287
  109. ccxt/async_support/coinbaseadvanced.py +17 -0
  110. ccxt/async_support/{coinbasepro.py → coinbaseexchange.py} +233 -99
  111. ccxt/async_support/coinbaseinternational.py +428 -88
  112. ccxt/async_support/coincatch.py +5152 -0
  113. ccxt/async_support/coincheck.py +121 -38
  114. ccxt/async_support/coinex.py +4020 -3339
  115. ccxt/async_support/coinlist.py +273 -116
  116. ccxt/async_support/coinmate.py +204 -97
  117. ccxt/async_support/coinmetro.py +203 -110
  118. ccxt/async_support/coinone.py +142 -68
  119. ccxt/async_support/coinsph.py +206 -89
  120. ccxt/async_support/coinspot.py +137 -62
  121. ccxt/async_support/cryptocom.py +515 -185
  122. ccxt/async_support/currencycom.py +203 -85
  123. ccxt/async_support/defx.py +2066 -0
  124. ccxt/async_support/delta.py +404 -109
  125. ccxt/async_support/deribit.py +557 -323
  126. ccxt/async_support/digifinex.py +340 -223
  127. ccxt/async_support/ellipx.py +1826 -0
  128. ccxt/async_support/exmo.py +259 -128
  129. ccxt/async_support/gate.py +1472 -463
  130. ccxt/async_support/gemini.py +206 -84
  131. ccxt/async_support/hashkey.py +4164 -0
  132. ccxt/async_support/hitbtc.py +334 -178
  133. ccxt/async_support/hollaex.py +134 -83
  134. ccxt/async_support/htx.py +1095 -563
  135. ccxt/async_support/huobijp.py +105 -56
  136. ccxt/async_support/hyperliquid.py +1633 -268
  137. ccxt/async_support/idex.py +148 -95
  138. ccxt/async_support/independentreserve.py +236 -31
  139. ccxt/async_support/indodax.py +165 -62
  140. ccxt/async_support/kraken.py +871 -354
  141. ccxt/async_support/krakenfutures.py +324 -100
  142. ccxt/async_support/kucoin.py +917 -357
  143. ccxt/async_support/kucoinfutures.py +1004 -149
  144. ccxt/async_support/kuna.py +138 -106
  145. ccxt/async_support/latoken.py +135 -79
  146. ccxt/async_support/lbank.py +290 -113
  147. ccxt/async_support/luno.py +112 -62
  148. ccxt/async_support/lykke.py +104 -55
  149. ccxt/async_support/mercado.py +36 -29
  150. ccxt/async_support/mexc.py +995 -429
  151. ccxt/async_support/myokx.py +43 -0
  152. ccxt/async_support/ndax.py +163 -82
  153. ccxt/async_support/novadax.py +121 -75
  154. ccxt/async_support/oceanex.py +175 -59
  155. ccxt/async_support/okcoin.py +222 -163
  156. ccxt/async_support/okx.py +1776 -454
  157. ccxt/async_support/onetrading.py +132 -414
  158. ccxt/async_support/oxfun.py +2832 -0
  159. ccxt/async_support/p2b.py +79 -51
  160. ccxt/async_support/paradex.py +2017 -0
  161. ccxt/async_support/paymium.py +56 -32
  162. ccxt/async_support/phemex.py +572 -196
  163. ccxt/async_support/poloniex.py +218 -95
  164. ccxt/async_support/poloniexfutures.py +260 -92
  165. ccxt/async_support/probit.py +143 -110
  166. ccxt/async_support/timex.py +123 -70
  167. ccxt/async_support/tokocrypto.py +129 -93
  168. ccxt/async_support/tradeogre.py +39 -25
  169. ccxt/async_support/upbit.py +322 -113
  170. ccxt/async_support/vertex.py +2983 -0
  171. ccxt/async_support/wavesexchange.py +227 -173
  172. ccxt/async_support/wazirx.py +145 -65
  173. ccxt/async_support/whitebit.py +533 -138
  174. ccxt/async_support/woo.py +1137 -296
  175. ccxt/async_support/woofipro.py +2716 -0
  176. ccxt/async_support/xt.py +4628 -0
  177. ccxt/async_support/yobit.py +160 -92
  178. ccxt/async_support/zaif.py +80 -33
  179. ccxt/async_support/zonda.py +140 -69
  180. ccxt/base/errors.py +51 -20
  181. ccxt/base/exchange.py +1722 -480
  182. ccxt/base/precise.py +10 -0
  183. ccxt/base/types.py +223 -4
  184. ccxt/bequant.py +1 -1
  185. ccxt/bigone.py +329 -202
  186. ccxt/binance.py +3030 -1087
  187. ccxt/binancecoinm.py +2 -1
  188. ccxt/binanceus.py +12 -1
  189. ccxt/binanceusdm.py +3 -1
  190. ccxt/bingx.py +3104 -880
  191. ccxt/bit2c.py +119 -38
  192. ccxt/bitbank.py +215 -76
  193. ccxt/bitbns.py +124 -53
  194. ccxt/bitfinex.py +3235 -1078
  195. ccxt/bitfinex1.py +1710 -0
  196. ccxt/bitflyer.py +238 -49
  197. ccxt/bitget.py +1513 -563
  198. ccxt/bithumb.py +198 -65
  199. ccxt/bitmart.py +1320 -435
  200. ccxt/bitmex.py +308 -111
  201. ccxt/bitopro.py +256 -96
  202. ccxt/bitrue.py +365 -233
  203. ccxt/bitso.py +201 -89
  204. ccxt/bitstamp.py +438 -269
  205. ccxt/bitteam.py +179 -73
  206. ccxt/bitvavo.py +180 -70
  207. ccxt/bl3p.py +92 -25
  208. ccxt/blockchaincom.py +193 -79
  209. ccxt/blofin.py +392 -148
  210. ccxt/btcalpha.py +161 -55
  211. ccxt/btcbox.py +250 -34
  212. ccxt/btcmarkets.py +232 -85
  213. ccxt/btcturk.py +159 -60
  214. ccxt/bybit.py +2231 -1193
  215. ccxt/cex.py +1408 -1329
  216. ccxt/coinbase.py +1454 -287
  217. ccxt/coinbaseadvanced.py +17 -0
  218. ccxt/{coinbasepro.py → coinbaseexchange.py} +233 -99
  219. ccxt/coinbaseinternational.py +428 -88
  220. ccxt/coincatch.py +5152 -0
  221. ccxt/coincheck.py +121 -38
  222. ccxt/coinex.py +4020 -3339
  223. ccxt/coinlist.py +273 -116
  224. ccxt/coinmate.py +204 -97
  225. ccxt/coinmetro.py +203 -110
  226. ccxt/coinone.py +142 -68
  227. ccxt/coinsph.py +206 -89
  228. ccxt/coinspot.py +137 -62
  229. ccxt/cryptocom.py +515 -185
  230. ccxt/currencycom.py +203 -85
  231. ccxt/defx.py +2065 -0
  232. ccxt/delta.py +404 -109
  233. ccxt/deribit.py +557 -323
  234. ccxt/digifinex.py +340 -223
  235. ccxt/ellipx.py +1826 -0
  236. ccxt/exmo.py +259 -128
  237. ccxt/gate.py +1472 -463
  238. ccxt/gemini.py +206 -84
  239. ccxt/hashkey.py +4164 -0
  240. ccxt/hitbtc.py +334 -178
  241. ccxt/hollaex.py +134 -83
  242. ccxt/htx.py +1095 -563
  243. ccxt/huobijp.py +105 -56
  244. ccxt/hyperliquid.py +1632 -268
  245. ccxt/idex.py +148 -95
  246. ccxt/independentreserve.py +235 -31
  247. ccxt/indodax.py +165 -62
  248. ccxt/kraken.py +871 -354
  249. ccxt/krakenfutures.py +324 -100
  250. ccxt/kucoin.py +917 -357
  251. ccxt/kucoinfutures.py +1004 -149
  252. ccxt/kuna.py +138 -106
  253. ccxt/latoken.py +135 -79
  254. ccxt/lbank.py +290 -113
  255. ccxt/luno.py +112 -62
  256. ccxt/lykke.py +104 -55
  257. ccxt/mercado.py +36 -29
  258. ccxt/mexc.py +994 -429
  259. ccxt/myokx.py +43 -0
  260. ccxt/ndax.py +163 -82
  261. ccxt/novadax.py +121 -75
  262. ccxt/oceanex.py +175 -59
  263. ccxt/okcoin.py +222 -163
  264. ccxt/okx.py +1776 -454
  265. ccxt/onetrading.py +132 -414
  266. ccxt/oxfun.py +2831 -0
  267. ccxt/p2b.py +79 -51
  268. ccxt/paradex.py +2017 -0
  269. ccxt/paymium.py +56 -32
  270. ccxt/phemex.py +572 -196
  271. ccxt/poloniex.py +218 -95
  272. ccxt/poloniexfutures.py +260 -92
  273. ccxt/pro/__init__.py +29 -5
  274. ccxt/pro/alpaca.py +32 -17
  275. ccxt/pro/ascendex.py +62 -14
  276. ccxt/pro/bequant.py +4 -0
  277. ccxt/pro/binance.py +1596 -329
  278. ccxt/pro/binancecoinm.py +1 -0
  279. ccxt/pro/binanceus.py +2 -9
  280. ccxt/pro/binanceusdm.py +2 -0
  281. ccxt/pro/bingx.py +527 -134
  282. ccxt/pro/bitcoincom.py +4 -1
  283. ccxt/pro/bitfinex.py +731 -266
  284. ccxt/pro/bitfinex1.py +635 -0
  285. ccxt/pro/bitget.py +726 -357
  286. ccxt/pro/bithumb.py +380 -0
  287. ccxt/pro/bitmart.py +138 -39
  288. ccxt/pro/bitmex.py +199 -40
  289. ccxt/pro/bitopro.py +25 -13
  290. ccxt/pro/bitrue.py +31 -32
  291. ccxt/pro/bitstamp.py +7 -6
  292. ccxt/pro/bitvavo.py +203 -81
  293. ccxt/pro/blockchaincom.py +30 -17
  294. ccxt/pro/blofin.py +692 -0
  295. ccxt/pro/bybit.py +791 -82
  296. ccxt/pro/cex.py +99 -51
  297. ccxt/pro/coinbase.py +220 -30
  298. ccxt/{async_support/hitbtc3.py → pro/coinbaseadvanced.py} +5 -5
  299. ccxt/pro/{coinbasepro.py → coinbaseexchange.py} +19 -19
  300. ccxt/pro/coinbaseinternational.py +193 -30
  301. ccxt/pro/coincatch.py +1464 -0
  302. ccxt/pro/coincheck.py +11 -6
  303. ccxt/pro/coinex.py +965 -665
  304. ccxt/pro/coinone.py +17 -10
  305. ccxt/pro/cryptocom.py +446 -66
  306. ccxt/pro/currencycom.py +11 -10
  307. ccxt/pro/defx.py +832 -0
  308. ccxt/pro/deribit.py +167 -31
  309. ccxt/pro/exmo.py +252 -20
  310. ccxt/pro/gate.py +729 -64
  311. ccxt/pro/gemini.py +44 -26
  312. ccxt/pro/hashkey.py +802 -0
  313. ccxt/pro/hitbtc.py +208 -103
  314. ccxt/pro/hollaex.py +25 -9
  315. ccxt/pro/htx.py +83 -39
  316. ccxt/pro/huobijp.py +17 -16
  317. ccxt/pro/hyperliquid.py +502 -31
  318. ccxt/pro/idex.py +28 -13
  319. ccxt/pro/independentreserve.py +21 -16
  320. ccxt/pro/kraken.py +298 -51
  321. ccxt/pro/krakenfutures.py +166 -75
  322. ccxt/pro/kucoin.py +395 -77
  323. ccxt/pro/kucoinfutures.py +400 -99
  324. ccxt/pro/lbank.py +52 -31
  325. ccxt/pro/luno.py +12 -10
  326. ccxt/pro/mexc.py +400 -50
  327. ccxt/pro/myokx.py +28 -0
  328. ccxt/pro/ndax.py +25 -12
  329. ccxt/pro/okcoin.py +28 -9
  330. ccxt/pro/okx.py +935 -124
  331. ccxt/pro/onetrading.py +41 -24
  332. ccxt/pro/oxfun.py +1054 -0
  333. ccxt/pro/p2b.py +100 -24
  334. ccxt/pro/paradex.py +352 -0
  335. ccxt/pro/phemex.py +92 -33
  336. ccxt/pro/poloniex.py +128 -49
  337. ccxt/pro/poloniexfutures.py +53 -32
  338. ccxt/pro/probit.py +92 -85
  339. ccxt/pro/upbit.py +401 -8
  340. ccxt/pro/vertex.py +943 -0
  341. ccxt/pro/wazirx.py +46 -28
  342. ccxt/pro/whitebit.py +65 -12
  343. ccxt/pro/woo.py +437 -65
  344. ccxt/pro/woofipro.py +1271 -0
  345. ccxt/pro/xt.py +1067 -0
  346. ccxt/probit.py +143 -110
  347. ccxt/static_dependencies/__init__.py +1 -1
  348. ccxt/static_dependencies/lark/__init__.py +38 -0
  349. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  350. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  351. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  352. ccxt/static_dependencies/lark/common.py +86 -0
  353. ccxt/static_dependencies/lark/exceptions.py +292 -0
  354. ccxt/static_dependencies/lark/grammar.py +130 -0
  355. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  356. ccxt/static_dependencies/lark/indenter.py +143 -0
  357. ccxt/static_dependencies/lark/lark.py +658 -0
  358. ccxt/static_dependencies/lark/lexer.py +678 -0
  359. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  360. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  361. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  362. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  363. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  364. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  365. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  366. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  367. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  368. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  369. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  370. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  371. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  372. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  373. ccxt/static_dependencies/lark/py.typed +0 -0
  374. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  375. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  376. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  377. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  378. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  379. ccxt/static_dependencies/lark/tree.py +267 -0
  380. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  381. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  382. ccxt/static_dependencies/lark/utils.py +343 -0
  383. ccxt/static_dependencies/lark/visitors.py +596 -0
  384. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  385. ccxt/static_dependencies/marshmallow/base.py +65 -0
  386. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  387. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  388. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  389. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  390. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  391. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  392. ccxt/static_dependencies/marshmallow/py.typed +0 -0
  393. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  394. ccxt/static_dependencies/marshmallow/types.py +12 -0
  395. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  396. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  397. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  398. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  399. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  400. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  401. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  402. ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
  403. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  404. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  405. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  406. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  407. ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
  408. ccxt/static_dependencies/starknet/__init__.py +0 -0
  409. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  410. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  411. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  412. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  413. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  414. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  415. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  416. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  417. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  418. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  419. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  420. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  421. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  422. ccxt/static_dependencies/starknet/common.py +15 -0
  423. ccxt/static_dependencies/starknet/constants.py +39 -0
  424. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  425. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  426. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  427. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  428. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  429. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  430. ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  431. ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  432. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  433. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  434. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  435. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  436. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  437. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  438. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  439. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  440. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  441. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  442. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  443. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  444. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  445. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  446. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  447. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  448. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  449. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  450. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  451. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  452. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  453. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  454. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  455. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  456. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  457. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  458. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  459. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  460. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  461. ccxt/static_dependencies/starkware/__init__.py +0 -0
  462. ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  463. ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  464. ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  465. ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  466. ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  467. ccxt/static_dependencies/sympy/__init__.py +0 -0
  468. ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  469. ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  470. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  471. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  472. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  473. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  474. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  475. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  476. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  477. ccxt/test/{test_async.py → tests_async.py} +456 -391
  478. ccxt/test/tests_helpers.py +285 -0
  479. ccxt/test/tests_init.py +39 -0
  480. ccxt/test/{test_sync.py → tests_sync.py} +456 -393
  481. ccxt/timex.py +123 -70
  482. ccxt/tokocrypto.py +129 -93
  483. ccxt/tradeogre.py +39 -25
  484. ccxt/upbit.py +322 -113
  485. ccxt/vertex.py +2983 -0
  486. ccxt/wavesexchange.py +227 -173
  487. ccxt/wazirx.py +145 -65
  488. ccxt/whitebit.py +533 -138
  489. ccxt/woo.py +1137 -296
  490. ccxt/woofipro.py +2716 -0
  491. ccxt/xt.py +4627 -0
  492. ccxt/yobit.py +159 -92
  493. ccxt/zaif.py +80 -33
  494. ccxt/zonda.py +140 -69
  495. ccxt-4.4.48.dist-info/LICENSE.txt +21 -0
  496. ccxt-4.4.48.dist-info/METADATA +646 -0
  497. ccxt-4.4.48.dist-info/RECORD +669 -0
  498. {ccxt-4.2.77.dist-info → ccxt-4.4.48.dist-info}/WHEEL +1 -1
  499. ccxt/abstract/bitbay.py +0 -47
  500. ccxt/abstract/bitfinex2.py +0 -139
  501. ccxt/abstract/hitbtc3.py +0 -115
  502. ccxt/async_support/bitbay.py +0 -17
  503. ccxt/async_support/bitfinex2.py +0 -3496
  504. ccxt/async_support/flowbtc.py +0 -34
  505. ccxt/bitbay.py +0 -17
  506. ccxt/bitfinex2.py +0 -3496
  507. ccxt/flowbtc.py +0 -34
  508. ccxt/hitbtc3.py +0 -16
  509. ccxt/pro/bitfinex2.py +0 -1081
  510. ccxt/test/base/__init__.py +0 -28
  511. ccxt/test/base/test_account.py +0 -26
  512. ccxt/test/base/test_balance.py +0 -56
  513. ccxt/test/base/test_borrow_interest.py +0 -35
  514. ccxt/test/base/test_borrow_rate.py +0 -32
  515. ccxt/test/base/test_calculate_fee.py +0 -51
  516. ccxt/test/base/test_crypto.py +0 -127
  517. ccxt/test/base/test_currency.py +0 -76
  518. ccxt/test/base/test_datetime.py +0 -103
  519. ccxt/test/base/test_decimal_to_precision.py +0 -392
  520. ccxt/test/base/test_deep_extend.py +0 -68
  521. ccxt/test/base/test_deposit_withdrawal.py +0 -50
  522. ccxt/test/base/test_exchange_datetime_functions.py +0 -76
  523. ccxt/test/base/test_funding_rate_history.py +0 -29
  524. ccxt/test/base/test_last_price.py +0 -32
  525. ccxt/test/base/test_ledger_entry.py +0 -45
  526. ccxt/test/base/test_ledger_item.py +0 -48
  527. ccxt/test/base/test_leverage_tier.py +0 -33
  528. ccxt/test/base/test_margin_mode.py +0 -24
  529. ccxt/test/base/test_margin_modification.py +0 -35
  530. ccxt/test/base/test_market.py +0 -190
  531. ccxt/test/base/test_number.py +0 -411
  532. ccxt/test/base/test_ohlcv.py +0 -32
  533. ccxt/test/base/test_open_interest.py +0 -32
  534. ccxt/test/base/test_order.py +0 -64
  535. ccxt/test/base/test_order_book.py +0 -63
  536. ccxt/test/base/test_position.py +0 -60
  537. ccxt/test/base/test_shared_methods.py +0 -345
  538. ccxt/test/base/test_status.py +0 -24
  539. ccxt/test/base/test_throttle.py +0 -126
  540. ccxt/test/base/test_ticker.py +0 -86
  541. ccxt/test/base/test_trade.py +0 -47
  542. ccxt/test/base/test_trading_fee.py +0 -26
  543. ccxt/test/base/test_transaction.py +0 -39
  544. ccxt-4.2.77.dist-info/METADATA +0 -626
  545. ccxt-4.2.77.dist-info/RECORD +0 -534
  546. {ccxt-4.2.77.dist-info → ccxt-4.4.48.dist-info}/top_level.txt +0 -0
ccxt/pro/bybit.py CHANGED
@@ -7,13 +7,14 @@ import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp
8
8
  import asyncio
9
9
  import hashlib
10
- from ccxt.base.types import Balances, Int, Order, OrderBook, Position, Str, Strings, Ticker, Tickers, Trade
10
+ from ccxt.base.types import Balances, Int, Liquidation, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade
11
11
  from ccxt.async_support.base.ws.client import Client
12
12
  from typing import List
13
+ from typing import Any
13
14
  from ccxt.base.errors import ExchangeError
15
+ from ccxt.base.errors import AuthenticationError
14
16
  from ccxt.base.errors import ArgumentsRequired
15
17
  from ccxt.base.errors import BadRequest
16
- from ccxt.base.errors import AuthenticationError
17
18
 
18
19
 
19
20
  class bybit(ccxt.async_support.bybit):
@@ -22,19 +23,24 @@ class bybit(ccxt.async_support.bybit):
22
23
  return self.deep_extend(super(bybit, self).describe(), {
23
24
  'has': {
24
25
  'ws': True,
25
- 'createOrderWs': False,
26
- 'editOrderWs': False,
26
+ 'createOrderWs': True,
27
+ 'editOrderWs': True,
27
28
  'fetchOpenOrdersWs': False,
28
29
  'fetchOrderWs': False,
29
- 'cancelOrderWs': False,
30
+ 'cancelOrderWs': True,
30
31
  'cancelOrdersWs': False,
31
32
  'cancelAllOrdersWs': False,
32
33
  'fetchTradesWs': False,
33
34
  'fetchBalanceWs': False,
34
35
  'watchBalance': True,
36
+ 'watchBidsAsks': True,
37
+ 'watchLiquidations': True,
38
+ 'watchLiquidationsForSymbols': False,
39
+ 'watchMyLiquidations': False,
40
+ 'watchMyLiquidationsForSymbols': False,
35
41
  'watchMyTrades': True,
36
42
  'watchOHLCV': True,
37
- 'watchOHLCVForSymbols': False,
43
+ 'watchOHLCVForSymbols': True,
38
44
  'watchOrderBook': True,
39
45
  'watchOrderBookForSymbols': True,
40
46
  'watchOrders': True,
@@ -60,6 +66,7 @@ class bybit(ccxt.async_support.bybit):
60
66
  },
61
67
  'contract': 'wss://stream.{hostname}/v5/private',
62
68
  'usdc': 'wss://stream.{hostname}/trade/option/usdc/private/v1',
69
+ 'trade': 'wss://stream.bybit.com/v5/trade',
63
70
  },
64
71
  },
65
72
  },
@@ -78,6 +85,26 @@ class bybit(ccxt.async_support.bybit):
78
85
  },
79
86
  'contract': 'wss://stream-testnet.{hostname}/v5/private',
80
87
  'usdc': 'wss://stream-testnet.{hostname}/trade/option/usdc/private/v1',
88
+ 'trade': 'wss://stream-testnet.bybit.com/v5/trade',
89
+ },
90
+ },
91
+ },
92
+ 'demotrading': {
93
+ 'ws': {
94
+ 'public': {
95
+ 'spot': 'wss://stream.{hostname}/v5/public/spot',
96
+ 'inverse': 'wss://stream.{hostname}/v5/public/inverse',
97
+ 'option': 'wss://stream.{hostname}/v5/public/option',
98
+ 'linear': 'wss://stream.{hostname}/v5/public/linear',
99
+ },
100
+ 'private': {
101
+ 'spot': {
102
+ 'unified': 'wss://stream-demo.{hostname}/v5/private',
103
+ 'nonUnified': 'wss://stream-demo.{hostname}/spot/private/v3',
104
+ },
105
+ 'contract': 'wss://stream-demo.{hostname}/v5/private',
106
+ 'usdc': 'wss://stream-demo.{hostname}/trade/option/usdc/private/v1',
107
+ 'trade': 'wss://stream-demo.bybit.com/v5/trade',
81
108
  },
82
109
  },
83
110
  },
@@ -90,6 +117,12 @@ class bybit(ccxt.async_support.bybit):
90
117
  'fetchPositionsSnapshot': True, # or False
91
118
  'awaitPositionsSnapshot': True, # whether to wait for the positions snapshot before providing updates
92
119
  },
120
+ 'watchMyTrades': {
121
+ # filter execType: https://bybit-exchange.github.io/docs/api-explorer/v5/position/execution
122
+ 'filterExecTypes': [
123
+ 'Trade', 'AdlTrade', 'BustTrade', 'Settle',
124
+ ],
125
+ },
93
126
  'spot': {
94
127
  'timeframes': {
95
128
  '1m': '1m',
@@ -127,7 +160,7 @@ class bybit(ccxt.async_support.bybit):
127
160
  },
128
161
  'streaming': {
129
162
  'ping': self.ping,
130
- 'keepAlive': 20000,
163
+ 'keepAlive': 18000,
131
164
  },
132
165
  })
133
166
 
@@ -136,7 +169,7 @@ class bybit(ccxt.async_support.bybit):
136
169
  self.options['requestId'] = requestId
137
170
  return requestId
138
171
 
139
- def get_url_by_market_type(self, symbol: Str = None, isPrivate=False, method: Str = None, params={}):
172
+ async def get_url_by_market_type(self, symbol: Str = None, isPrivate=False, method: Str = None, params={}):
140
173
  accessibility = 'private' if isPrivate else 'public'
141
174
  isUsdcSettled = None
142
175
  isSpot = None
@@ -154,11 +187,17 @@ class bybit(ccxt.async_support.bybit):
154
187
  isUsdcSettled = (defaultSettle == 'USDC')
155
188
  isSpot = (type == 'spot')
156
189
  if isPrivate:
157
- url = url[accessibility]['usdc'] if (isUsdcSettled) else url[accessibility]['contract']
190
+ unified = await self.isUnifiedEnabled()
191
+ isUnifiedMargin = self.safe_bool(unified, 0, False)
192
+ isUnifiedAccount = self.safe_bool(unified, 1, False)
193
+ if isUsdcSettled and not isUnifiedMargin and not isUnifiedAccount:
194
+ url = url[accessibility]['usdc']
195
+ else:
196
+ url = url[accessibility]['contract']
158
197
  else:
159
198
  if isSpot:
160
199
  url = url[accessibility]['spot']
161
- elif type == 'swap':
200
+ elif (type == 'swap') or (type == 'future'):
162
201
  subType = None
163
202
  subType, params = self.handle_sub_type_and_params(method, market, params, 'linear')
164
203
  url = url[accessibility][subType]
@@ -172,11 +211,141 @@ class bybit(ccxt.async_support.bybit):
172
211
  params = self.omit(params, ['type', 'subType', 'settle', 'defaultSettle', 'unifiedMargin'])
173
212
  return params
174
213
 
214
+ async def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
215
+ """
216
+ create a trade order
217
+
218
+ https://bybit-exchange.github.io/docs/v5/order/create-order
219
+ https://bybit-exchange.github.io/docs/v5/websocket/trade/guideline#createamendcancel-order
220
+
221
+ :param str symbol: unified symbol of the market to create an order in
222
+ :param str type: 'market' or 'limit'
223
+ :param str side: 'buy' or 'sell'
224
+ :param float amount: how much of currency you want to trade in units of base currency
225
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
226
+ :param dict [params]: extra parameters specific to the exchange API endpoint
227
+ :param str [params.timeInForce]: "GTC", "IOC", "FOK"
228
+ :param bool [params.postOnly]: True or False whether the order is post-only
229
+ :param bool [params.reduceOnly]: True or False whether the order is reduce-only
230
+ :param str [params.positionIdx]: *contracts only* 0 for one-way mode, 1 buy side of hedged mode, 2 sell side of hedged mode
231
+ :param boolean [params.isLeverage]: *unified spot only* False then spot trading True then margin trading
232
+ :param str [params.tpslMode]: *contract only* 'full' or 'partial'
233
+ :param str [params.mmp]: *option only* market maker protection
234
+ :param str [params.triggerDirection]: *contract only* the direction for trigger orders, 'above' or 'below'
235
+ :param float [params.triggerPrice]: The price at which a trigger order is triggered at
236
+ :param float [params.stopLossPrice]: The price at which a stop loss order is triggered at
237
+ :param float [params.takeProfitPrice]: The price at which a take profit order is triggered at
238
+ :param dict [params.takeProfit]: *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered
239
+ :param float [params.takeProfit.triggerPrice]: take profit trigger price
240
+ :param dict [params.stopLoss]: *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered
241
+ :param float [params.stopLoss.triggerPrice]: stop loss trigger price
242
+ :param str [params.trailingAmount]: the quote amount to trail away from the current market price
243
+ :param str [params.trailingTriggerPrice]: the price to trigger a trailing order, default uses the price argument
244
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
245
+ """
246
+ await self.load_markets()
247
+ orderRequest = self.create_order_request(symbol, type, side, amount, price, params, True)
248
+ url = self.urls['api']['ws']['private']['trade']
249
+ await self.authenticate(url)
250
+ requestId = str(self.request_id())
251
+ request: dict = {
252
+ 'op': 'order.create',
253
+ 'reqId': requestId,
254
+ 'args': [
255
+ orderRequest,
256
+ ],
257
+ 'header': {
258
+ 'X-BAPI-TIMESTAMP': str(self.milliseconds()),
259
+ 'X-BAPI-RECV-WINDOW': str(self.options['recvWindow']),
260
+ },
261
+ }
262
+ return await self.watch(url, requestId, request, requestId, True)
263
+
264
+ async def edit_order_ws(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
265
+ """
266
+ edit a trade order
267
+
268
+ https://bybit-exchange.github.io/docs/v5/order/amend-order
269
+ https://bybit-exchange.github.io/docs/v5/websocket/trade/guideline#createamendcancel-order
270
+
271
+ :param str id: cancel order id
272
+ :param str symbol: unified symbol of the market to create an order in
273
+ :param str type: 'market' or 'limit'
274
+ :param str side: 'buy' or 'sell'
275
+ :param float amount: how much of currency you want to trade in units of base currency
276
+ :param float price: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
277
+ :param dict [params]: extra parameters specific to the exchange API endpoint
278
+ :param float [params.triggerPrice]: The price that a trigger order is triggered at
279
+ :param float [params.stopLossPrice]: The price that a stop loss order is triggered at
280
+ :param float [params.takeProfitPrice]: The price that a take profit order is triggered at
281
+ :param dict [params.takeProfit]: *takeProfit object in params* containing the triggerPrice that the attached take profit order will be triggered
282
+ :param float [params.takeProfit.triggerPrice]: take profit trigger price
283
+ :param dict [params.stopLoss]: *stopLoss object in params* containing the triggerPrice that the attached stop loss order will be triggered
284
+ :param float [params.stopLoss.triggerPrice]: stop loss trigger price
285
+ :param str [params.triggerBy]: 'IndexPrice', 'MarkPrice' or 'LastPrice', default is 'LastPrice', required if no initial value for triggerPrice
286
+ :param str [params.slTriggerBy]: 'IndexPrice', 'MarkPrice' or 'LastPrice', default is 'LastPrice', required if no initial value for stopLoss
287
+ :param str [params.tpTriggerby]: 'IndexPrice', 'MarkPrice' or 'LastPrice', default is 'LastPrice', required if no initial value for takeProfit
288
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
289
+ """
290
+ await self.load_markets()
291
+ orderRequest = self.edit_order_request(id, symbol, type, side, amount, price, params)
292
+ url = self.urls['api']['ws']['private']['trade']
293
+ await self.authenticate(url)
294
+ requestId = str(self.request_id())
295
+ request: dict = {
296
+ 'op': 'order.amend',
297
+ 'reqId': requestId,
298
+ 'args': [
299
+ orderRequest,
300
+ ],
301
+ 'header': {
302
+ 'X-BAPI-TIMESTAMP': str(self.milliseconds()),
303
+ 'X-BAPI-RECV-WINDOW': str(self.options['recvWindow']),
304
+ },
305
+ }
306
+ return await self.watch(url, requestId, request, requestId, True)
307
+
308
+ async def cancel_order_ws(self, id: str, symbol: Str = None, params={}):
309
+ """
310
+ cancels an open order
311
+
312
+ https://bybit-exchange.github.io/docs/v5/order/cancel-order
313
+ https://bybit-exchange.github.io/docs/v5/websocket/trade/guideline#createamendcancel-order
314
+
315
+ :param str id: order id
316
+ :param str symbol: unified symbol of the market the order was made in
317
+ :param dict [params]: extra parameters specific to the exchange API endpoint
318
+ :param boolean [params.trigger]: *spot only* whether the order is a trigger order
319
+ :param str [params.orderFilter]: *spot only* 'Order' or 'StopOrder' or 'tpslOrder'
320
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
321
+ """
322
+ await self.load_markets()
323
+ orderRequest = self.cancel_order_request(id, symbol, params)
324
+ url = self.urls['api']['ws']['private']['trade']
325
+ await self.authenticate(url)
326
+ requestId = str(self.request_id())
327
+ if 'orderFilter' in orderRequest:
328
+ del orderRequest['orderFilter']
329
+ request: dict = {
330
+ 'op': 'order.cancel',
331
+ 'reqId': requestId,
332
+ 'args': [
333
+ orderRequest,
334
+ ],
335
+ 'header': {
336
+ 'X-BAPI-TIMESTAMP': str(self.milliseconds()),
337
+ 'X-BAPI-RECV-WINDOW': str(self.options['recvWindow']),
338
+ },
339
+ }
340
+ return await self.watch(url, requestId, request, requestId, True)
341
+
175
342
  async def watch_ticker(self, symbol: str, params={}) -> Ticker:
176
343
  """
177
344
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
178
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/ticker
179
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/etp-ticker
345
+
346
+ https://bybit-exchange.github.io/docs/v5/websocket/public/ticker
347
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-ticker
348
+
180
349
  :param str symbol: unified symbol of the market to fetch the ticker for
181
350
  :param dict [params]: extra parameters specific to the exchange API endpoint
182
351
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -185,7 +354,7 @@ class bybit(ccxt.async_support.bybit):
185
354
  market = self.market(symbol)
186
355
  symbol = market['symbol']
187
356
  messageHash = 'ticker:' + symbol
188
- url = self.get_url_by_market_type(symbol, False, 'watchTicker', params)
357
+ url = await self.get_url_by_market_type(symbol, False, 'watchTicker', params)
189
358
  params = self.clean_params(params)
190
359
  options = self.safe_value(self.options, 'watchTicker', {})
191
360
  topic = self.safe_string(options, 'name', 'tickers')
@@ -197,9 +366,11 @@ class bybit(ccxt.async_support.bybit):
197
366
 
198
367
  async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
199
368
  """
200
- n watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
201
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/ticker
202
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/etp-ticker
369
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
370
+
371
+ https://bybit-exchange.github.io/docs/v5/websocket/public/ticker
372
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-ticker
373
+
203
374
  :param str[] symbols: unified symbol of the market to fetch the ticker for
204
375
  :param dict [params]: extra parameters specific to the exchange API endpoint
205
376
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -207,7 +378,7 @@ class bybit(ccxt.async_support.bybit):
207
378
  await self.load_markets()
208
379
  symbols = self.market_symbols(symbols, None, False)
209
380
  messageHashes = []
210
- url = self.get_url_by_market_type(symbols[0], False, 'watchTickers', params)
381
+ url = await self.get_url_by_market_type(symbols[0], False, 'watchTickers', params)
211
382
  params = self.clean_params(params)
212
383
  options = self.safe_value(self.options, 'watchTickers', {})
213
384
  topic = self.safe_string(options, 'name', 'tickers')
@@ -219,11 +390,53 @@ class bybit(ccxt.async_support.bybit):
219
390
  messageHashes.append('ticker:' + symbols[i])
220
391
  ticker = await self.watch_topics(url, messageHashes, topics, params)
221
392
  if self.newUpdates:
222
- result = {}
393
+ result: dict = {}
223
394
  result[ticker['symbol']] = ticker
224
395
  return result
225
396
  return self.filter_by_array(self.tickers, 'symbol', symbols)
226
397
 
398
+ async def un_watch_tickers(self, symbols: Strings = None, params={}) -> Any:
399
+ """
400
+ unWatches a price ticker
401
+
402
+ https://bybit-exchange.github.io/docs/v5/websocket/public/ticker
403
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-ticker
404
+
405
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
406
+ :param dict [params]: extra parameters specific to the exchange API endpoint
407
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
408
+ """
409
+ await self.load_markets()
410
+ symbols = self.market_symbols(symbols, None, False)
411
+ options = self.safe_value(self.options, 'watchTickers', {})
412
+ topic = self.safe_string(options, 'name', 'tickers')
413
+ messageHashes = []
414
+ subMessageHashes = []
415
+ marketIds = self.market_ids(symbols)
416
+ topics = []
417
+ for i in range(0, len(marketIds)):
418
+ marketId = marketIds[i]
419
+ symbol = symbols[i]
420
+ topics.append(topic + '.' + marketId)
421
+ subMessageHashes.append('ticker:' + symbol)
422
+ messageHashes.append('unsubscribe:ticker:' + symbol)
423
+ url = await self.get_url_by_market_type(symbols[0], False, 'watchTickers', params)
424
+ return await self.un_watch_topics(url, 'ticker', symbols, messageHashes, subMessageHashes, topics, params)
425
+
426
+ async def un_watch_ticker(self, symbols: str, params={}) -> Any:
427
+ """
428
+ unWatches a price ticker
429
+
430
+ https://bybit-exchange.github.io/docs/v5/websocket/public/ticker
431
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-ticker
432
+
433
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
434
+ :param dict [params]: extra parameters specific to the exchange API endpoint
435
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
436
+ """
437
+ await self.load_markets()
438
+ return await self.un_watch_tickers([symbols], params)
439
+
227
440
  def handle_ticker(self, client: Client, message):
228
441
  #
229
442
  # linear
@@ -367,11 +580,57 @@ class bybit(ccxt.async_support.bybit):
367
580
  messageHash = 'ticker:' + symbol
368
581
  client.resolve(self.tickers[symbol], messageHash)
369
582
 
583
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
584
+ """
585
+ watches best bid & ask for symbols
586
+
587
+ https://bybit-exchange.github.io/docs/v5/websocket/public/orderbook
588
+
589
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
590
+ :param dict [params]: extra parameters specific to the exchange API endpoint
591
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
592
+ """
593
+ await self.load_markets()
594
+ symbols = self.market_symbols(symbols, None, False)
595
+ messageHashes = []
596
+ url = await self.get_url_by_market_type(symbols[0], False, 'watchBidsAsks', params)
597
+ params = self.clean_params(params)
598
+ marketIds = self.market_ids(symbols)
599
+ topics = []
600
+ for i in range(0, len(marketIds)):
601
+ marketId = marketIds[i]
602
+ topic = 'orderbook.1.' + marketId
603
+ topics.append(topic)
604
+ messageHashes.append('bidask:' + symbols[i])
605
+ ticker = await self.watch_topics(url, messageHashes, topics, params)
606
+ if self.newUpdates:
607
+ return ticker
608
+ return self.filter_by_array(self.bidsasks, 'symbol', symbols)
609
+
610
+ def parse_ws_bid_ask(self, orderbook, market=None):
611
+ timestamp = self.safe_integer(orderbook, 'timestamp')
612
+ bids = self.sort_by(self.aggregate(orderbook['bids']), 0)
613
+ asks = self.sort_by(self.aggregate(orderbook['asks']), 0)
614
+ bestBid = self.safe_list(bids, 0, [])
615
+ bestAsk = self.safe_list(asks, 0, [])
616
+ return self.safe_ticker({
617
+ 'symbol': market['symbol'],
618
+ 'timestamp': timestamp,
619
+ 'datetime': self.iso8601(timestamp),
620
+ 'ask': self.safe_number(bestAsk, 0),
621
+ 'askVolume': self.safe_number(bestAsk, 1),
622
+ 'bid': self.safe_number(bestBid, 0),
623
+ 'bidVolume': self.safe_number(bestBid, 1),
624
+ 'info': orderbook,
625
+ }, market)
626
+
370
627
  async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
371
628
  """
372
629
  watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
373
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/kline
374
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
630
+
631
+ https://bybit-exchange.github.io/docs/v5/websocket/public/kline
632
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
633
+
375
634
  :param str symbol: unified symbol of the market to fetch OHLCV data for
376
635
  :param str timeframe: the length of time each candle represents
377
636
  :param int [since]: timestamp in ms of the earliest candle to fetch
@@ -379,19 +638,93 @@ class bybit(ccxt.async_support.bybit):
379
638
  :param dict [params]: extra parameters specific to the exchange API endpoint
380
639
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
381
640
  """
641
+ params['callerMethodName'] = 'watchOHLCV'
642
+ result = await self.watch_ohlcv_for_symbols([[symbol, timeframe]], since, limit, params)
643
+ return result[symbol][timeframe]
644
+
645
+ async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}):
646
+ """
647
+ watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
648
+
649
+ https://bybit-exchange.github.io/docs/v5/websocket/public/kline
650
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
651
+
652
+ :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
653
+ :param int [since]: timestamp in ms of the earliest candle to fetch
654
+ :param int [limit]: the maximum amount of candles to fetch
655
+ :param dict [params]: extra parameters specific to the exchange API endpoint
656
+ :returns dict: A list of candles ordered, open, high, low, close, volume
657
+ """
382
658
  await self.load_markets()
383
- market = self.market(symbol)
384
- symbol = market['symbol']
385
- url = self.get_url_by_market_type(symbol, False, 'watchOHLCV', params)
386
- params = self.clean_params(params)
387
- ohlcv = None
388
- timeframeId = self.safe_string(self.timeframes, timeframe, timeframe)
389
- topics = ['kline.' + timeframeId + '.' + market['id']]
390
- messageHash = 'kline' + ':' + timeframeId + ':' + symbol
391
- ohlcv = await self.watch_topics(url, [messageHash], topics, params)
659
+ symbols = self.get_list_from_object_values(symbolsAndTimeframes, 0)
660
+ marketSymbols = self.market_symbols(symbols, None, False, True, True)
661
+ firstSymbol = marketSymbols[0]
662
+ url = await self.get_url_by_market_type(firstSymbol, False, 'watchOHLCVForSymbols', params)
663
+ rawHashes = []
664
+ messageHashes = []
665
+ for i in range(0, len(symbolsAndTimeframes)):
666
+ data = symbolsAndTimeframes[i]
667
+ symbolString = self.safe_string(data, 0)
668
+ market = self.market(symbolString)
669
+ symbolString = market['symbol']
670
+ unfiedTimeframe = self.safe_string(data, 1)
671
+ timeframeId = self.safe_string(self.timeframes, unfiedTimeframe, unfiedTimeframe)
672
+ rawHashes.append('kline.' + timeframeId + '.' + market['id'])
673
+ messageHashes.append('ohlcv::' + symbolString + '::' + unfiedTimeframe)
674
+ symbol, timeframe, stored = await self.watch_topics(url, messageHashes, rawHashes, params)
392
675
  if self.newUpdates:
393
- limit = ohlcv.getLimit(symbol, limit)
394
- return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
676
+ limit = stored.getLimit(symbol, limit)
677
+ filtered = self.filter_by_since_limit(stored, since, limit, 0, True)
678
+ return self.create_ohlcv_object(symbol, timeframe, filtered)
679
+
680
+ async def un_watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], params={}) -> Any:
681
+ """
682
+ unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
683
+
684
+ https://bybit-exchange.github.io/docs/v5/websocket/public/kline
685
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
686
+
687
+ :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
688
+ :param dict [params]: extra parameters specific to the exchange API endpoint
689
+ :returns dict: A list of candles ordered, open, high, low, close, volume
690
+ """
691
+ await self.load_markets()
692
+ symbols = self.get_list_from_object_values(symbolsAndTimeframes, 0)
693
+ marketSymbols = self.market_symbols(symbols, None, False, True, True)
694
+ firstSymbol = marketSymbols[0]
695
+ url = await self.get_url_by_market_type(firstSymbol, False, 'watchOHLCVForSymbols', params)
696
+ rawHashes = []
697
+ subMessageHashes = []
698
+ messageHashes = []
699
+ for i in range(0, len(symbolsAndTimeframes)):
700
+ data = symbolsAndTimeframes[i]
701
+ symbolString = self.safe_string(data, 0)
702
+ market = self.market(symbolString)
703
+ symbolString = market['symbol']
704
+ unfiedTimeframe = self.safe_string(data, 1)
705
+ timeframeId = self.safe_string(self.timeframes, unfiedTimeframe, unfiedTimeframe)
706
+ rawHashes.append('kline.' + timeframeId + '.' + market['id'])
707
+ subMessageHashes.append('ohlcv::' + symbolString + '::' + unfiedTimeframe)
708
+ messageHashes.append('unsubscribe::ohlcv::' + symbolString + '::' + unfiedTimeframe)
709
+ subExtension = {
710
+ 'symbolsAndTimeframes': symbolsAndTimeframes,
711
+ }
712
+ return await self.un_watch_topics(url, 'ohlcv', symbols, messageHashes, subMessageHashes, rawHashes, params, subExtension)
713
+
714
+ async def un_watch_ohlcv(self, symbol: str, timeframe='1m', params={}) -> Any:
715
+ """
716
+ unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
717
+
718
+ https://bybit-exchange.github.io/docs/v5/websocket/public/kline
719
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
720
+
721
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
722
+ :param str timeframe: the length of time each candle represents
723
+ :param dict [params]: extra parameters specific to the exchange API endpoint
724
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
725
+ """
726
+ params['callerMethodName'] = 'watchOHLCV'
727
+ return await self.un_watch_ohlcv_for_symbols([[symbol, timeframe]], params)
395
728
 
396
729
  def handle_ohlcv(self, client: Client, message):
397
730
  #
@@ -430,16 +763,16 @@ class bybit(ccxt.async_support.bybit):
430
763
  ohlcvsByTimeframe = self.safe_value(self.ohlcvs, symbol)
431
764
  if ohlcvsByTimeframe is None:
432
765
  self.ohlcvs[symbol] = {}
433
- stored = self.safe_value(ohlcvsByTimeframe, timeframe)
434
- if stored is None:
766
+ if self.safe_value(ohlcvsByTimeframe, timeframe) is None:
435
767
  limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
436
- stored = ArrayCacheByTimestamp(limit)
437
- self.ohlcvs[symbol][timeframe] = stored
768
+ self.ohlcvs[symbol][timeframe] = ArrayCacheByTimestamp(limit)
769
+ stored = self.ohlcvs[symbol][timeframe]
438
770
  for i in range(0, len(data)):
439
771
  parsed = self.parse_ws_ohlcv(data[i])
440
772
  stored.append(parsed)
441
- messageHash = 'kline' + ':' + timeframeId + ':' + symbol
442
- client.resolve(stored, messageHash)
773
+ messageHash = 'ohlcv::' + symbol + '::' + timeframe
774
+ resolveData = [symbol, timeframe, stored]
775
+ client.resolve(resolveData, messageHash)
443
776
 
444
777
  def parse_ws_ohlcv(self, ohlcv, market=None) -> list:
445
778
  #
@@ -469,7 +802,9 @@ class bybit(ccxt.async_support.bybit):
469
802
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
470
803
  """
471
804
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
472
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/orderbook
805
+
806
+ https://bybit-exchange.github.io/docs/v5/websocket/public/orderbook
807
+
473
808
  :param str symbol: unified symbol of the market to fetch the order book for
474
809
  :param int [limit]: the maximum amount of order book entries to return.
475
810
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -480,7 +815,9 @@ class bybit(ccxt.async_support.bybit):
480
815
  async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
481
816
  """
482
817
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
483
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/orderbook
818
+
819
+ https://bybit-exchange.github.io/docs/v5/websocket/public/orderbook
820
+
484
821
  :param str[] symbols: unified array of symbols
485
822
  :param int [limit]: the maximum amount of order book entries to return.
486
823
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -491,7 +828,7 @@ class bybit(ccxt.async_support.bybit):
491
828
  if symbolsLength == 0:
492
829
  raise ArgumentsRequired(self.id + ' watchOrderBookForSymbols() requires a non-empty array of symbols')
493
830
  symbols = self.market_symbols(symbols)
494
- url = self.get_url_by_market_type(symbols[0], False, 'watchOrderBook', params)
831
+ url = await self.get_url_by_market_type(symbols[0], False, 'watchOrderBook', params)
495
832
  params = self.clean_params(params)
496
833
  market = self.market(symbols[0])
497
834
  if limit is None:
@@ -513,6 +850,55 @@ class bybit(ccxt.async_support.bybit):
513
850
  orderbook = await self.watch_topics(url, messageHashes, topics, params)
514
851
  return orderbook.limit()
515
852
 
853
+ async def un_watch_order_book_for_symbols(self, symbols: Strings, params={}) -> Any:
854
+ """
855
+ unsubscribe from the orderbook channel
856
+
857
+ https://bybit-exchange.github.io/docs/v5/websocket/public/orderbook
858
+
859
+ :param str[] symbols: unified symbol of the market to unwatch the trades for
860
+ :param dict [params]: extra parameters specific to the exchange API endpoint
861
+ :param int [params.limit]: orderbook limit, default is None
862
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
863
+ """
864
+ await self.load_markets()
865
+ symbols = self.market_symbols(symbols, None, False)
866
+ channel = 'orderbook.'
867
+ limit = self.safe_integer(params, 'limit')
868
+ if limit is not None:
869
+ params = self.omit(params, 'limit')
870
+ else:
871
+ firstMarket = self.market(symbols[0])
872
+ limit = 50 if firstMarket['spot'] else 500
873
+ channel += str(limit)
874
+ subMessageHashes = []
875
+ messageHashes = []
876
+ topics = []
877
+ for i in range(0, len(symbols)):
878
+ symbol = symbols[i]
879
+ market = self.market(symbol)
880
+ marketId = market['id']
881
+ topic = channel + '.' + marketId
882
+ messageHashes.append('unsubscribe:orderbook:' + symbol)
883
+ subMessageHashes.append('orderbook:' + symbol)
884
+ topics.append(topic)
885
+ url = await self.get_url_by_market_type(symbols[0], False, 'watchOrderBook', params)
886
+ return await self.un_watch_topics(url, 'orderbook', symbols, messageHashes, subMessageHashes, topics, params)
887
+
888
+ async def un_watch_order_book(self, symbol: str, params={}) -> Any:
889
+ """
890
+ unsubscribe from the orderbook channel
891
+
892
+ https://bybit-exchange.github.io/docs/v5/websocket/public/orderbook
893
+
894
+ :param str symbol: symbol of the market to unwatch the trades for
895
+ :param dict [params]: extra parameters specific to the exchange API endpoint
896
+ :param int [params.limit]: orderbook limit, default is None
897
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
898
+ """
899
+ await self.load_markets()
900
+ return await self.un_watch_order_book_for_symbols([symbol], params)
901
+
516
902
  def handle_order_book(self, client: Client, message):
517
903
  #
518
904
  # {
@@ -547,24 +933,26 @@ class bybit(ccxt.async_support.bybit):
547
933
  # }
548
934
  # }
549
935
  #
936
+ topic = self.safe_string(message, 'topic')
937
+ limit = topic.split('.')[1]
550
938
  isSpot = client.url.find('spot') >= 0
551
939
  type = self.safe_string(message, 'type')
552
940
  isSnapshot = (type == 'snapshot')
553
- data = self.safe_value(message, 'data', {})
941
+ data = self.safe_dict(message, 'data', {})
554
942
  marketId = self.safe_string(data, 's')
555
943
  marketType = 'spot' if isSpot else 'contract'
556
944
  market = self.safe_market(marketId, None, None, marketType)
557
945
  symbol = market['symbol']
558
946
  timestamp = self.safe_integer(message, 'ts')
559
- orderbook = self.safe_value(self.orderbooks, symbol)
560
- if orderbook is None:
561
- orderbook = self.order_book()
947
+ if not (symbol in self.orderbooks):
948
+ self.orderbooks[symbol] = self.order_book()
949
+ orderbook = self.orderbooks[symbol]
562
950
  if isSnapshot:
563
951
  snapshot = self.parse_order_book(data, symbol, timestamp, 'b', 'a')
564
952
  orderbook.reset(snapshot)
565
953
  else:
566
- asks = self.safe_value(data, 'a', [])
567
- bids = self.safe_value(data, 'b', [])
954
+ asks = self.safe_list(data, 'a', [])
955
+ bids = self.safe_list(data, 'b', [])
568
956
  self.handle_deltas(orderbook['asks'], asks)
569
957
  self.handle_deltas(orderbook['bids'], bids)
570
958
  orderbook['timestamp'] = timestamp
@@ -572,6 +960,12 @@ class bybit(ccxt.async_support.bybit):
572
960
  messageHash = 'orderbook' + ':' + symbol
573
961
  self.orderbooks[symbol] = orderbook
574
962
  client.resolve(orderbook, messageHash)
963
+ if limit == '1':
964
+ bidask = self.parse_ws_bid_ask(self.orderbooks[symbol], market)
965
+ newBidsAsks: dict = {}
966
+ newBidsAsks[symbol] = bidask
967
+ self.bidsasks[symbol] = bidask
968
+ client.resolve(newBidsAsks, 'bidask:' + symbol)
575
969
 
576
970
  def handle_delta(self, bookside, delta):
577
971
  bidAsk = self.parse_bid_ask(delta, 0, 1)
@@ -584,19 +978,23 @@ class bybit(ccxt.async_support.bybit):
584
978
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
585
979
  """
586
980
  watches information on multiple trades made in a market
587
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/trade
981
+
982
+ https://bybit-exchange.github.io/docs/v5/websocket/public/trade
983
+
588
984
  :param str symbol: unified market symbol of the market trades were made in
589
985
  :param int [since]: the earliest time in ms to fetch trades for
590
986
  :param int [limit]: the maximum number of trade structures to retrieve
591
987
  :param dict [params]: extra parameters specific to the exchange API endpoint
592
- :returns dict[]: a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure
988
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
593
989
  """
594
990
  return await self.watch_trades_for_symbols([symbol], since, limit, params)
595
991
 
596
992
  async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
597
993
  """
598
994
  get the list of most recent trades for a list of symbols
599
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/trade
995
+
996
+ https://bybit-exchange.github.io/docs/v5/websocket/public/trade
997
+
600
998
  :param str[] symbols: unified symbol of the market to fetch trades for
601
999
  :param int [since]: timestamp in ms of the earliest trade to fetch
602
1000
  :param int [limit]: the maximum amount of trades to fetch
@@ -609,7 +1007,7 @@ class bybit(ccxt.async_support.bybit):
609
1007
  if symbolsLength == 0:
610
1008
  raise ArgumentsRequired(self.id + ' watchTradesForSymbols() requires a non-empty array of symbols')
611
1009
  params = self.clean_params(params)
612
- url = self.get_url_by_market_type(symbols[0], False, 'watchTrades', params)
1010
+ url = await self.get_url_by_market_type(symbols[0], False, 'watchTrades', params)
613
1011
  topics = []
614
1012
  messageHashes = []
615
1013
  for i in range(0, len(symbols)):
@@ -626,6 +1024,45 @@ class bybit(ccxt.async_support.bybit):
626
1024
  limit = trades.getLimit(tradeSymbol, limit)
627
1025
  return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
628
1026
 
1027
+ async def un_watch_trades_for_symbols(self, symbols: Strings, params={}) -> Any:
1028
+ """
1029
+ unsubscribe from the trades channel
1030
+
1031
+ https://bybit-exchange.github.io/docs/v5/websocket/public/trade
1032
+
1033
+ :param str[] symbols: unified symbol of the market to unwatch the trades for
1034
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1035
+ :returns any: status of the unwatch request
1036
+ """
1037
+ await self.load_markets()
1038
+ symbols = self.market_symbols(symbols, None, False, True)
1039
+ url = await self.get_url_by_market_type(symbols[0], False, 'unWatchTradesForSymbols', params)
1040
+ messageHashes = []
1041
+ topics = []
1042
+ subMessageHashes = []
1043
+ for i in range(0, len(symbols)):
1044
+ symbol = symbols[i]
1045
+ market = self.market(symbol)
1046
+ topic = 'publicTrade.' + market['id']
1047
+ topics.append(topic)
1048
+ messageHash = 'unsubscribe:trade:' + symbol
1049
+ messageHashes.append(messageHash)
1050
+ subMessageHashes.append('trade:' + symbol)
1051
+ return await self.un_watch_topics(url, 'trades', symbols, messageHashes, subMessageHashes, topics, params)
1052
+
1053
+ async def un_watch_trades(self, symbol: str, params={}) -> Any:
1054
+ """
1055
+ unsubscribe from the trades channel
1056
+
1057
+ https://bybit-exchange.github.io/docs/v5/websocket/public/trade
1058
+
1059
+ :param str symbol: unified symbol of the market to unwatch the trades for
1060
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1061
+ :returns any: status of the unwatch request
1062
+ """
1063
+ await self.load_markets()
1064
+ return await self.un_watch_trades_for_symbols([symbol], params)
1065
+
629
1066
  def handle_trades(self, client: Client, message):
630
1067
  #
631
1068
  # {
@@ -745,13 +1182,15 @@ class bybit(ccxt.async_support.bybit):
745
1182
  async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
746
1183
  """
747
1184
  watches information on multiple trades made by the user
748
- :see: https://bybit-exchange.github.io/docs/v5/websocket/private/execution
1185
+
1186
+ https://bybit-exchange.github.io/docs/v5/websocket/private/execution
1187
+
749
1188
  :param str symbol: unified market symbol of the market orders were made in
750
1189
  :param int [since]: the earliest time in ms to fetch orders for
751
1190
  :param int [limit]: the maximum number of order structures to retrieve
752
1191
  :param dict [params]: extra parameters specific to the exchange API endpoint
753
1192
  :param boolean [params.unifiedMargin]: use unified margin account
754
- :returns dict[]: a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure
1193
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
755
1194
  """
756
1195
  method = 'watchMyTrades'
757
1196
  messageHash = 'myTrades'
@@ -759,9 +1198,9 @@ class bybit(ccxt.async_support.bybit):
759
1198
  if symbol is not None:
760
1199
  symbol = self.symbol(symbol)
761
1200
  messageHash += ':' + symbol
762
- url = self.get_url_by_market_type(symbol, True, method, params)
1201
+ url = await self.get_url_by_market_type(symbol, True, method, params)
763
1202
  await self.authenticate(url)
764
- topicByMarket = {
1203
+ topicByMarket: dict = {
765
1204
  'spot': 'ticketInfo',
766
1205
  'unified': 'execution',
767
1206
  'usdc': 'user.openapi.perp.trade',
@@ -772,6 +1211,34 @@ class bybit(ccxt.async_support.bybit):
772
1211
  limit = trades.getLimit(symbol, limit)
773
1212
  return self.filter_by_symbol_since_limit(trades, symbol, since, limit, True)
774
1213
 
1214
+ async def un_watch_my_trades(self, symbol: Str = None, params={}) -> Any:
1215
+ """
1216
+ unWatches information on multiple trades made by the user
1217
+
1218
+ https://bybit-exchange.github.io/docs/v5/websocket/private/execution
1219
+
1220
+ :param str symbol: unified market symbol of the market orders were made in
1221
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1222
+ :param boolean [params.unifiedMargin]: use unified margin account
1223
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1224
+ """
1225
+ method = 'watchMyTrades'
1226
+ messageHash = 'unsubscribe:myTrades'
1227
+ subHash = 'myTrades'
1228
+ await self.load_markets()
1229
+ if symbol is not None:
1230
+ symbol = self.symbol(symbol)
1231
+ subHash += ':' + symbol
1232
+ url = await self.get_url_by_market_type(symbol, True, method, params)
1233
+ await self.authenticate(url)
1234
+ topicByMarket: dict = {
1235
+ 'spot': 'ticketInfo',
1236
+ 'unified': 'execution',
1237
+ 'usdc': 'user.openapi.perp.trade',
1238
+ }
1239
+ topic = self.safe_value(topicByMarket, self.get_private_type(url))
1240
+ return await self.un_watch_topics(url, 'myTrades', [], [messageHash], [subHash], [topic], params)
1241
+
775
1242
  def handle_my_trades(self, client: Client, message):
776
1243
  #
777
1244
  # spot
@@ -844,13 +1311,18 @@ class bybit(ccxt.async_support.bybit):
844
1311
  limit = self.safe_integer(self.options, 'tradesLimit', 1000)
845
1312
  self.myTrades = ArrayCacheBySymbolById(limit)
846
1313
  trades = self.myTrades
847
- symbols = {}
1314
+ symbols: dict = {}
1315
+ filterExecTypes = self.handle_option('watchMyTrades', 'filterExecTypes', [])
848
1316
  for i in range(0, len(data)):
849
1317
  rawTrade = data[i]
850
1318
  parsed = None
851
1319
  if spot:
852
1320
  parsed = self.parse_ws_trade(rawTrade)
853
1321
  else:
1322
+ # filter unified trades
1323
+ execType = self.safe_string(rawTrade, 'execType', '')
1324
+ if not self.in_array(execType, filterExecTypes):
1325
+ continue
854
1326
  parsed = self.parse_trade(rawTrade)
855
1327
  symbol = parsed['symbol']
856
1328
  symbols[symbol] = True
@@ -865,9 +1337,13 @@ class bybit(ccxt.async_support.bybit):
865
1337
 
866
1338
  async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
867
1339
  """
868
- :see: https://bybit-exchange.github.io/docs/v5/websocket/private/position
1340
+
1341
+ https://bybit-exchange.github.io/docs/v5/websocket/private/position
1342
+
869
1343
  watch all open positions
870
1344
  :param str[] [symbols]: list of unified market symbols
1345
+ :param int [since]: the earliest time in ms to fetch positions for
1346
+ :param int [limit]: the maximum number of positions to retrieve
871
1347
  :param dict params: extra parameters specific to the exchange API endpoint
872
1348
  :returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
873
1349
  """
@@ -878,14 +1354,14 @@ class bybit(ccxt.async_support.bybit):
878
1354
  symbols = self.market_symbols(symbols)
879
1355
  messageHash = '::' + ','.join(symbols)
880
1356
  firstSymbol = self.safe_string(symbols, 0)
881
- url = self.get_url_by_market_type(firstSymbol, True, method, params)
1357
+ url = await self.get_url_by_market_type(firstSymbol, True, method, params)
882
1358
  messageHash = 'positions' + messageHash
883
1359
  client = self.client(url)
884
1360
  await self.authenticate(url)
885
1361
  self.set_positions_cache(client, symbols)
886
1362
  cache = self.positions
887
1363
  fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', True)
888
- awaitPositionsSnapshot = self.safe_bool('watchPositions', 'awaitPositionsSnapshot', True)
1364
+ awaitPositionsSnapshot = self.handle_option('watchPositions', 'awaitPositionsSnapshot', True)
889
1365
  if fetchPositionsSnapshot and awaitPositionsSnapshot and cache is None:
890
1366
  snapshot = await client.future('fetchPositionsSnapshot')
891
1367
  return self.filter_by_symbols_since_limit(snapshot, symbols, since, limit, True)
@@ -974,8 +1450,21 @@ class bybit(ccxt.async_support.bybit):
974
1450
  for i in range(0, len(rawPositions)):
975
1451
  rawPosition = rawPositions[i]
976
1452
  position = self.parse_position(rawPosition)
1453
+ side = self.safe_string(position, 'side')
1454
+ # hacky solution to handle closing positions
1455
+ # without crashing, we should handle self properly later
977
1456
  newPositions.append(position)
978
- cache.append(position)
1457
+ if side is None or side == '':
1458
+ # closing update, adding both sides to "reset" both sides
1459
+ # since we don't know which side is being closed
1460
+ position['side'] = 'long'
1461
+ cache.append(position)
1462
+ position['side'] = 'short'
1463
+ cache.append(position)
1464
+ position['side'] = None
1465
+ else:
1466
+ # regular update
1467
+ cache.append(position)
979
1468
  messageHashes = self.find_message_hashes(client, 'positions::')
980
1469
  for i in range(0, len(messageHashes)):
981
1470
  messageHash = messageHashes[i]
@@ -987,15 +1476,95 @@ class bybit(ccxt.async_support.bybit):
987
1476
  client.resolve(positions, messageHash)
988
1477
  client.resolve(newPositions, 'positions')
989
1478
 
1479
+ async def watch_liquidations(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
1480
+ """
1481
+ watch the public liquidations of a trading pair
1482
+
1483
+ https://bybit-exchange.github.io/docs/v5/websocket/public/liquidation
1484
+
1485
+ :param str symbol: unified CCXT market symbol
1486
+ :param int [since]: the earliest time in ms to fetch liquidations for
1487
+ :param int [limit]: the maximum number of liquidation structures to retrieve
1488
+ :param dict [params]: exchange specific parameters for the bitmex api endpoint
1489
+ :returns dict: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
1490
+ """
1491
+ await self.load_markets()
1492
+ market = self.market(symbol)
1493
+ symbol = market['symbol']
1494
+ url = await self.get_url_by_market_type(symbol, False, 'watchLiquidations', params)
1495
+ params = self.clean_params(params)
1496
+ messageHash = 'liquidations::' + symbol
1497
+ topic = 'liquidation.' + market['id']
1498
+ newLiquidation = await self.watch_topics(url, [messageHash], [topic], params)
1499
+ if self.newUpdates:
1500
+ return newLiquidation
1501
+ return self.filter_by_symbols_since_limit(self.liquidations, [symbol], since, limit, True)
1502
+
1503
+ def handle_liquidation(self, client: Client, message):
1504
+ #
1505
+ # {
1506
+ # "data": {
1507
+ # "price": "0.03803",
1508
+ # "side": "Buy",
1509
+ # "size": "1637",
1510
+ # "symbol": "GALAUSDT",
1511
+ # "updatedTime": 1673251091822
1512
+ # },
1513
+ # "topic": "liquidation.GALAUSDT",
1514
+ # "ts": 1673251091822,
1515
+ # "type": "snapshot"
1516
+ # }
1517
+ #
1518
+ rawLiquidation = self.safe_dict(message, 'data', {})
1519
+ marketId = self.safe_string(rawLiquidation, 'symbol')
1520
+ market = self.safe_market(marketId, None, '', 'contract')
1521
+ symbol = market['symbol']
1522
+ liquidation = self.parse_ws_liquidation(rawLiquidation, market)
1523
+ liquidations = self.safe_value(self.liquidations, symbol)
1524
+ if liquidations is None:
1525
+ limit = self.safe_integer(self.options, 'liquidationsLimit', 1000)
1526
+ liquidations = ArrayCache(limit)
1527
+ liquidations.append(liquidation)
1528
+ self.liquidations[symbol] = liquidations
1529
+ client.resolve([liquidation], 'liquidations')
1530
+ client.resolve([liquidation], 'liquidations::' + symbol)
1531
+
1532
+ def parse_ws_liquidation(self, liquidation, market=None):
1533
+ #
1534
+ # {
1535
+ # "price": "0.03803",
1536
+ # "side": "Buy",
1537
+ # "size": "1637",
1538
+ # "symbol": "GALAUSDT",
1539
+ # "updatedTime": 1673251091822
1540
+ # }
1541
+ #
1542
+ marketId = self.safe_string(liquidation, 'symbol')
1543
+ market = self.safe_market(marketId, market, '', 'contract')
1544
+ timestamp = self.safe_integer(liquidation, 'updatedTime')
1545
+ return self.safe_liquidation({
1546
+ 'info': liquidation,
1547
+ 'symbol': market['symbol'],
1548
+ 'contracts': self.safe_number(liquidation, 'size'),
1549
+ 'contractSize': self.safe_number(market, 'contractSize'),
1550
+ 'price': self.safe_number(liquidation, 'price'),
1551
+ 'baseValue': None,
1552
+ 'quoteValue': None,
1553
+ 'timestamp': timestamp,
1554
+ 'datetime': self.iso8601(timestamp),
1555
+ })
1556
+
990
1557
  async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
991
1558
  """
992
1559
  watches information on multiple orders made by the user
993
- :see: https://bybit-exchange.github.io/docs/v5/websocket/private/order
1560
+
1561
+ https://bybit-exchange.github.io/docs/v5/websocket/private/order
1562
+
994
1563
  :param str symbol: unified market symbol of the market orders were made in
995
1564
  :param int [since]: the earliest time in ms to fetch orders for
996
1565
  :param int [limit]: the maximum number of order structures to retrieve
997
1566
  :param dict [params]: extra parameters specific to the exchange API endpoint
998
- :returns dict[]: a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure
1567
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
999
1568
  """
1000
1569
  await self.load_markets()
1001
1570
  method = 'watchOrders'
@@ -1003,9 +1572,9 @@ class bybit(ccxt.async_support.bybit):
1003
1572
  if symbol is not None:
1004
1573
  symbol = self.symbol(symbol)
1005
1574
  messageHash += ':' + symbol
1006
- url = self.get_url_by_market_type(symbol, True, method, params)
1575
+ url = await self.get_url_by_market_type(symbol, True, method, params)
1007
1576
  await self.authenticate(url)
1008
- topicsByMarket = {
1577
+ topicsByMarket: dict = {
1009
1578
  'spot': ['order', 'stopOrder'],
1010
1579
  'unified': ['order'],
1011
1580
  'usdc': ['user.openapi.perp.order'],
@@ -1016,6 +1585,60 @@ class bybit(ccxt.async_support.bybit):
1016
1585
  limit = orders.getLimit(symbol, limit)
1017
1586
  return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
1018
1587
 
1588
+ async def un_watch_orders(self, symbol: Str = None, params={}) -> Any:
1589
+ """
1590
+ unWatches information on multiple orders made by the user
1591
+
1592
+ https://bybit-exchange.github.io/docs/v5/websocket/private/order
1593
+
1594
+ :param str symbol: unified market symbol of the market orders were made in
1595
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1596
+ :param boolean [params.unifiedMargin]: use unified margin account
1597
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1598
+ """
1599
+ await self.load_markets()
1600
+ method = 'watchOrders'
1601
+ messageHash = 'unsubscribe:orders'
1602
+ subHash = 'orders'
1603
+ if symbol is not None:
1604
+ symbol = self.symbol(symbol)
1605
+ subHash += ':' + symbol
1606
+ url = await self.get_url_by_market_type(symbol, True, method, params)
1607
+ await self.authenticate(url)
1608
+ topicsByMarket: dict = {
1609
+ 'spot': ['order', 'stopOrder'],
1610
+ 'unified': ['order'],
1611
+ 'usdc': ['user.openapi.perp.order'],
1612
+ }
1613
+ topics = self.safe_value(topicsByMarket, self.get_private_type(url))
1614
+ return await self.un_watch_topics(url, 'orders', [], [messageHash], [subHash], topics, params)
1615
+
1616
+ def handle_order_ws(self, client: Client, message):
1617
+ #
1618
+ # {
1619
+ # "reqId":"1",
1620
+ # "retCode":0,
1621
+ # "retMsg":"OK",
1622
+ # "op":"order.create",
1623
+ # "data":{
1624
+ # "orderId":"1673523595617593600",
1625
+ # "orderLinkId":"1673523595617593601"
1626
+ # },
1627
+ # "header":{
1628
+ # "X-Bapi-Limit":"20",
1629
+ # "X-Bapi-Limit-Status":"19",
1630
+ # "X-Bapi-Limit-Reset-Timestamp":"1714235558880",
1631
+ # "Traceid":"584a06d373f2fdcb3a4dfdd81d27df11",
1632
+ # "Timenow":"1714235558881"
1633
+ # },
1634
+ # "connId":"cojidqec0hv9fgvhtbt0-40e"
1635
+ # }
1636
+ #
1637
+ messageHash = self.safe_string(message, 'reqId')
1638
+ data = self.safe_dict(message, 'data')
1639
+ order = self.parse_order(data)
1640
+ client.resolve(order, messageHash)
1641
+
1019
1642
  def handle_order(self, client: Client, message):
1020
1643
  #
1021
1644
  # spot
@@ -1110,7 +1733,7 @@ class bybit(ccxt.async_support.bybit):
1110
1733
  isSpot = category == 'spot'
1111
1734
  if not isSpot:
1112
1735
  rawOrders = self.safe_value(rawOrders, 'result', rawOrders)
1113
- symbols = {}
1736
+ symbols: dict = {}
1114
1737
  for i in range(0, len(rawOrders)):
1115
1738
  parsed = None
1116
1739
  if isSpot:
@@ -1261,7 +1884,9 @@ class bybit(ccxt.async_support.bybit):
1261
1884
  async def watch_balance(self, params={}) -> Balances:
1262
1885
  """
1263
1886
  watch balance and get the amount of funds available for trading or funds locked in orders
1264
- :see: https://bybit-exchange.github.io/docs/v5/websocket/private/wallet
1887
+
1888
+ https://bybit-exchange.github.io/docs/v5/websocket/private/wallet
1889
+
1265
1890
  :param dict [params]: extra parameters specific to the exchange API endpoint
1266
1891
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1267
1892
  """
@@ -1275,9 +1900,9 @@ class bybit(ccxt.async_support.bybit):
1275
1900
  unified = await self.isUnifiedEnabled()
1276
1901
  isUnifiedMargin = self.safe_bool(unified, 0, False)
1277
1902
  isUnifiedAccount = self.safe_bool(unified, 1, False)
1278
- url = self.get_url_by_market_type(None, True, method, params)
1903
+ url = await self.get_url_by_market_type(None, True, method, params)
1279
1904
  await self.authenticate(url)
1280
- topicByMarket = {
1905
+ topicByMarket: dict = {
1281
1906
  'spot': 'outboundAccountInfo',
1282
1907
  'unified': 'wallet',
1283
1908
  }
@@ -1530,13 +2155,30 @@ class bybit(ccxt.async_support.bybit):
1530
2155
  self.balance[code] = account
1531
2156
 
1532
2157
  async def watch_topics(self, url, messageHashes, topics, params={}):
1533
- request = {
2158
+ request: dict = {
1534
2159
  'op': 'subscribe',
1535
2160
  'req_id': self.request_id(),
1536
2161
  'args': topics,
1537
2162
  }
1538
2163
  message = self.extend(request, params)
1539
- return await self.watch_multiple(url, messageHashes, message, topics)
2164
+ return await self.watch_multiple(url, messageHashes, message, messageHashes)
2165
+
2166
+ async def un_watch_topics(self, url: str, topic: str, symbols: List[str], messageHashes: List[str], subMessageHashes: List[str], topics, params={}, subExtension={}):
2167
+ reqId = self.request_id()
2168
+ request: dict = {
2169
+ 'op': 'unsubscribe',
2170
+ 'req_id': reqId,
2171
+ 'args': topics,
2172
+ }
2173
+ subscription = {
2174
+ 'id': reqId,
2175
+ 'topic': topic,
2176
+ 'messageHashes': messageHashes,
2177
+ 'subMessageHashes': subMessageHashes,
2178
+ 'symbols': symbols,
2179
+ }
2180
+ message = self.extend(request, params)
2181
+ return await self.watch_multiple(url, messageHashes, message, messageHashes, self.extend(subscription, subExtension))
1540
2182
 
1541
2183
  async def authenticate(self, url, params={}):
1542
2184
  self.check_required_credentials()
@@ -1550,7 +2192,7 @@ class bybit(ccxt.async_support.bybit):
1550
2192
  path = 'GET/realtime'
1551
2193
  auth = path + expires
1552
2194
  signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256, 'hex')
1553
- request = {
2195
+ request: dict = {
1554
2196
  'op': 'auth',
1555
2197
  'args': [
1556
2198
  self.apiKey, expires, signature,
@@ -1586,11 +2228,32 @@ class bybit(ccxt.async_support.bybit):
1586
2228
  #
1587
2229
  # {code: '-10009', desc: "Invalid period!"}
1588
2230
  #
1589
- code = self.safe_string_2(message, 'code', 'ret_code')
2231
+ # {
2232
+ # "reqId":"1",
2233
+ # "retCode":170131,
2234
+ # "retMsg":"Insufficient balance.",
2235
+ # "op":"order.create",
2236
+ # "data":{
2237
+ #
2238
+ # },
2239
+ # "header":{
2240
+ # "X-Bapi-Limit":"20",
2241
+ # "X-Bapi-Limit-Status":"19",
2242
+ # "X-Bapi-Limit-Reset-Timestamp":"1714236608944",
2243
+ # "Traceid":"3d7168a137bf32a947b7e5e6a575ac7f",
2244
+ # "Timenow":"1714236608946"
2245
+ # },
2246
+ # "connId":"cojifin88smerbj9t560-406"
2247
+ # }
2248
+ #
2249
+ code = self.safe_string_n(message, ['code', 'ret_code', 'retCode'])
1590
2250
  try:
1591
- if code is not None:
2251
+ if code is not None and code != '0':
1592
2252
  feedback = self.id + ' ' + self.json(message)
1593
2253
  self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
2254
+ msg = self.safe_string_2(message, 'retMsg', 'ret_msg')
2255
+ self.throw_broadly_matched_exception(self.exceptions['broad'], msg, feedback)
2256
+ raise ExchangeError(feedback)
1594
2257
  success = self.safe_value(message, 'success')
1595
2258
  if success is not None and not success:
1596
2259
  ret_msg = self.safe_string(message, 'ret_msg')
@@ -1608,7 +2271,8 @@ class bybit(ccxt.async_support.bybit):
1608
2271
  if messageHash in client.subscriptions:
1609
2272
  del client.subscriptions[messageHash]
1610
2273
  else:
1611
- client.reject(error)
2274
+ messageHash = self.safe_string(message, 'reqId')
2275
+ client.reject(error, messageHash)
1612
2276
  return True
1613
2277
 
1614
2278
  def handle_message(self, client: Client, message):
@@ -1625,16 +2289,12 @@ class bybit(ccxt.async_support.bybit):
1625
2289
  self.handle_pong(client, message)
1626
2290
  return
1627
2291
  # pong
1628
- op = self.safe_string(message, 'op')
1629
- if op == 'pong':
1630
- self.handle_pong(client, message)
1631
- return
1632
2292
  event = self.safe_string(message, 'event')
1633
2293
  if event == 'sub':
1634
2294
  self.handle_subscription_status(client, message)
1635
2295
  return
1636
- topic = self.safe_string(message, 'topic', '')
1637
- methods = {
2296
+ topic = self.safe_string_2(message, 'topic', 'op', '')
2297
+ methods: dict = {
1638
2298
  'orderbook': self.handle_order_book,
1639
2299
  'kline': self.handle_ohlcv,
1640
2300
  'order': self.handle_order,
@@ -1649,6 +2309,13 @@ class bybit(ccxt.async_support.bybit):
1649
2309
  'ticketInfo': self.handle_my_trades,
1650
2310
  'user.openapi.perp.trade': self.handle_my_trades,
1651
2311
  'position': self.handle_positions,
2312
+ 'liquidation': self.handle_liquidation,
2313
+ 'pong': self.handle_pong,
2314
+ 'order.create': self.handle_order_ws,
2315
+ 'order.amend': self.handle_order_ws,
2316
+ 'order.cancel': self.handle_order_ws,
2317
+ 'auth': self.handle_authenticate,
2318
+ 'unsubscribe': self.handle_un_subscribe,
1652
2319
  }
1653
2320
  exacMethod = self.safe_value(methods, topic)
1654
2321
  if exacMethod is not None:
@@ -1663,10 +2330,10 @@ class bybit(ccxt.async_support.bybit):
1663
2330
  return
1664
2331
  # unified auth acknowledgement
1665
2332
  type = self.safe_string(message, 'type')
1666
- if (op == 'auth') or (type == 'AUTH_RESP'):
2333
+ if type == 'AUTH_RESP':
1667
2334
  self.handle_authenticate(client, message)
1668
2335
 
1669
- def ping(self, client):
2336
+ def ping(self, client: Client):
1670
2337
  return {
1671
2338
  'req_id': self.request_id(),
1672
2339
  'op': 'ping',
@@ -1695,9 +2362,17 @@ class bybit(ccxt.async_support.bybit):
1695
2362
  # "conn_id": "ce3dpomvha7dha97tvp0-2xh"
1696
2363
  # }
1697
2364
  #
2365
+ # {
2366
+ # "retCode":0,
2367
+ # "retMsg":"OK",
2368
+ # "op":"auth",
2369
+ # "connId":"cojifin88smerbj9t560-404"
2370
+ # }
2371
+ #
1698
2372
  success = self.safe_value(message, 'success')
2373
+ code = self.safe_integer(message, 'retCode')
1699
2374
  messageHash = 'authenticated'
1700
- if success:
2375
+ if success or code == 0:
1701
2376
  future = self.safe_value(client.futures, messageHash)
1702
2377
  future.resolve(True)
1703
2378
  else:
@@ -1723,3 +2398,37 @@ class bybit(ccxt.async_support.bybit):
1723
2398
  # }
1724
2399
  #
1725
2400
  return message
2401
+
2402
+ def handle_un_subscribe(self, client: Client, message):
2403
+ #
2404
+ # {"success":true,"ret_msg":"","conn_id":"7188110e-6908-41e9-b863-6365127e92ad","req_id":"3","op":"unsubscribe"}
2405
+ #
2406
+ # client.subscription will be something like:
2407
+ # {
2408
+ # "publicTrade.LTCUSDT":true,
2409
+ # "publicTrade.ADAUSDT":true,
2410
+ # "unsubscribe:trade:LTC/USDT:USDT": {
2411
+ # "id":4,
2412
+ # "subHash": "trade:LTC/USDT"
2413
+ # },
2414
+ # }
2415
+ reqId = self.safe_string(message, 'req_id')
2416
+ keys = list(client.subscriptions.keys())
2417
+ for i in range(0, len(keys)):
2418
+ messageHash = keys[i]
2419
+ if not (messageHash in client.subscriptions):
2420
+ continue
2421
+ # the previous iteration can have deleted the messageHash from the subscriptions
2422
+ if messageHash.startswith('unsubscribe'):
2423
+ subscription = client.subscriptions[messageHash]
2424
+ subId = self.safe_string(subscription, 'id')
2425
+ if reqId != subId:
2426
+ continue
2427
+ messageHashes = self.safe_list(subscription, 'messageHashes', [])
2428
+ subMessageHashes = self.safe_list(subscription, 'subMessageHashes', [])
2429
+ for j in range(0, len(messageHashes)):
2430
+ unsubHash = messageHashes[j]
2431
+ subHash = subMessageHashes[j]
2432
+ self.clean_unsubscription(client, subHash, unsubHash)
2433
+ self.clean_cache(subscription)
2434
+ return message