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/bybit.py CHANGED
@@ -7,18 +7,19 @@ 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, Liquidation, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade
10
+ from ccxt.base.types import Any, Balances, Bool, 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
13
  from ccxt.base.errors import ExchangeError
14
14
  from ccxt.base.errors import AuthenticationError
15
15
  from ccxt.base.errors import ArgumentsRequired
16
16
  from ccxt.base.errors import BadRequest
17
+ from ccxt.base.errors import NotSupported
17
18
 
18
19
 
19
20
  class bybit(ccxt.async_support.bybit):
20
21
 
21
- def describe(self):
22
+ def describe(self) -> Any:
22
23
  return self.deep_extend(super(bybit, self).describe(), {
23
24
  'has': {
24
25
  'ws': True,
@@ -32,13 +33,14 @@ class bybit(ccxt.async_support.bybit):
32
33
  'fetchTradesWs': False,
33
34
  'fetchBalanceWs': False,
34
35
  'watchBalance': True,
36
+ 'watchBidsAsks': True,
35
37
  'watchLiquidations': True,
36
38
  'watchLiquidationsForSymbols': False,
37
39
  'watchMyLiquidations': False,
38
40
  'watchMyLiquidationsForSymbols': False,
39
41
  'watchMyTrades': True,
40
42
  'watchOHLCV': True,
41
- 'watchOHLCVForSymbols': False,
43
+ 'watchOHLCVForSymbols': True,
42
44
  'watchOrderBook': True,
43
45
  'watchOrderBookForSymbols': True,
44
46
  'watchOrders': True,
@@ -47,6 +49,17 @@ class bybit(ccxt.async_support.bybit):
47
49
  'watchTrades': True,
48
50
  'watchPositions': True,
49
51
  'watchTradesForSymbols': True,
52
+ 'unWatchTicker': True,
53
+ 'unWatchTickers': True,
54
+ 'unWatchOHLCV': True,
55
+ 'unWatchOHLCVForSymbols': True,
56
+ 'unWatchOrderBook': True,
57
+ 'unWatchOrderBookForSymbols': True,
58
+ 'unWatchTrades': True,
59
+ 'unWatchTradesForSymbols': True,
60
+ 'unWatchMyTrades': True,
61
+ 'unWatchOrders': True,
62
+ 'unWatchPositions': True,
50
63
  },
51
64
  'urls': {
52
65
  'api': {
@@ -87,6 +100,25 @@ class bybit(ccxt.async_support.bybit):
87
100
  },
88
101
  },
89
102
  },
103
+ 'demotrading': {
104
+ 'ws': {
105
+ 'public': {
106
+ 'spot': 'wss://stream.{hostname}/v5/public/spot',
107
+ 'inverse': 'wss://stream.{hostname}/v5/public/inverse',
108
+ 'option': 'wss://stream.{hostname}/v5/public/option',
109
+ 'linear': 'wss://stream.{hostname}/v5/public/linear',
110
+ },
111
+ 'private': {
112
+ 'spot': {
113
+ 'unified': 'wss://stream-demo.{hostname}/v5/private',
114
+ 'nonUnified': 'wss://stream-demo.{hostname}/spot/private/v3',
115
+ },
116
+ 'contract': 'wss://stream-demo.{hostname}/v5/private',
117
+ 'usdc': 'wss://stream-demo.{hostname}/trade/option/usdc/private/v1',
118
+ 'trade': 'wss://stream-demo.bybit.com/v5/trade',
119
+ },
120
+ },
121
+ },
90
122
  },
91
123
  'options': {
92
124
  'watchTicker': {
@@ -96,6 +128,12 @@ class bybit(ccxt.async_support.bybit):
96
128
  'fetchPositionsSnapshot': True, # or False
97
129
  'awaitPositionsSnapshot': True, # whether to wait for the positions snapshot before providing updates
98
130
  },
131
+ 'watchMyTrades': {
132
+ # filter execType: https://bybit-exchange.github.io/docs/api-explorer/v5/position/execution
133
+ 'filterExecTypes': [
134
+ 'Trade', 'AdlTrade', 'BustTrade', 'Settle',
135
+ ],
136
+ },
99
137
  'spot': {
100
138
  'timeframes': {
101
139
  '1m': '1m',
@@ -142,7 +180,7 @@ class bybit(ccxt.async_support.bybit):
142
180
  self.options['requestId'] = requestId
143
181
  return requestId
144
182
 
145
- def get_url_by_market_type(self, symbol: Str = None, isPrivate=False, method: Str = None, params={}):
183
+ async def get_url_by_market_type(self, symbol: Str = None, isPrivate=False, method: Str = None, params={}):
146
184
  accessibility = 'private' if isPrivate else 'public'
147
185
  isUsdcSettled = None
148
186
  isSpot = None
@@ -160,11 +198,17 @@ class bybit(ccxt.async_support.bybit):
160
198
  isUsdcSettled = (defaultSettle == 'USDC')
161
199
  isSpot = (type == 'spot')
162
200
  if isPrivate:
163
- url = url[accessibility]['usdc'] if (isUsdcSettled) else url[accessibility]['contract']
201
+ unified = await self.isUnifiedEnabled()
202
+ isUnifiedMargin = self.safe_bool(unified, 0, False)
203
+ isUnifiedAccount = self.safe_bool(unified, 1, False)
204
+ if isUsdcSettled and not isUnifiedMargin and not isUnifiedAccount:
205
+ url = url[accessibility]['usdc']
206
+ else:
207
+ url = url[accessibility]['contract']
164
208
  else:
165
209
  if isSpot:
166
210
  url = url[accessibility]['spot']
167
- elif type == 'swap':
211
+ elif (type == 'swap') or (type == 'future'):
168
212
  subType = None
169
213
  subType, params = self.handle_sub_type_and_params(method, market, params, 'linear')
170
214
  url = url[accessibility][subType]
@@ -181,13 +225,15 @@ class bybit(ccxt.async_support.bybit):
181
225
  async def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
182
226
  """
183
227
  create a trade order
184
- :see: https://bybit-exchange.github.io/docs/v5/order/create-order
185
- :see: https://bybit-exchange.github.io/docs/v5/websocket/trade/guideline#createamendcancel-order
228
+
229
+ https://bybit-exchange.github.io/docs/v5/order/create-order
230
+ https://bybit-exchange.github.io/docs/v5/websocket/trade/guideline#createamendcancel-order
231
+
186
232
  :param str symbol: unified symbol of the market to create an order in
187
233
  :param str type: 'market' or 'limit'
188
234
  :param str side: 'buy' or 'sell'
189
235
  :param float amount: how much of currency you want to trade in units of base currency
190
- :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
236
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
191
237
  :param dict [params]: extra parameters specific to the exchange API endpoint
192
238
  :param str [params.timeInForce]: "GTC", "IOC", "FOK"
193
239
  :param bool [params.postOnly]: True or False whether the order is post-only
@@ -229,14 +275,16 @@ class bybit(ccxt.async_support.bybit):
229
275
  async def edit_order_ws(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
230
276
  """
231
277
  edit a trade order
232
- :see: https://bybit-exchange.github.io/docs/v5/order/amend-order
233
- :see: https://bybit-exchange.github.io/docs/v5/websocket/trade/guideline#createamendcancel-order
278
+
279
+ https://bybit-exchange.github.io/docs/v5/order/amend-order
280
+ https://bybit-exchange.github.io/docs/v5/websocket/trade/guideline#createamendcancel-order
281
+
234
282
  :param str id: cancel order id
235
283
  :param str symbol: unified symbol of the market to create an order in
236
284
  :param str type: 'market' or 'limit'
237
285
  :param str side: 'buy' or 'sell'
238
286
  :param float amount: how much of currency you want to trade in units of base currency
239
- :param float price: the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders
287
+ :param float price: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
240
288
  :param dict [params]: extra parameters specific to the exchange API endpoint
241
289
  :param float [params.triggerPrice]: The price that a trigger order is triggered at
242
290
  :param float [params.stopLossPrice]: The price that a stop loss order is triggered at
@@ -271,12 +319,14 @@ class bybit(ccxt.async_support.bybit):
271
319
  async def cancel_order_ws(self, id: str, symbol: Str = None, params={}):
272
320
  """
273
321
  cancels an open order
274
- :see: https://bybit-exchange.github.io/docs/v5/order/cancel-order
275
- :see: https://bybit-exchange.github.io/docs/v5/websocket/trade/guideline#createamendcancel-order
322
+
323
+ https://bybit-exchange.github.io/docs/v5/order/cancel-order
324
+ https://bybit-exchange.github.io/docs/v5/websocket/trade/guideline#createamendcancel-order
325
+
276
326
  :param str id: order id
277
327
  :param str symbol: unified symbol of the market the order was made in
278
328
  :param dict [params]: extra parameters specific to the exchange API endpoint
279
- :param boolean [params.stop]: *spot only* whether the order is a stop order
329
+ :param boolean [params.trigger]: *spot only* whether the order is a trigger order
280
330
  :param str [params.orderFilter]: *spot only* 'Order' or 'StopOrder' or 'tpslOrder'
281
331
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
282
332
  """
@@ -303,8 +353,10 @@ class bybit(ccxt.async_support.bybit):
303
353
  async def watch_ticker(self, symbol: str, params={}) -> Ticker:
304
354
  """
305
355
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
306
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/ticker
307
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/etp-ticker
356
+
357
+ https://bybit-exchange.github.io/docs/v5/websocket/public/ticker
358
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-ticker
359
+
308
360
  :param str symbol: unified symbol of the market to fetch the ticker for
309
361
  :param dict [params]: extra parameters specific to the exchange API endpoint
310
362
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -313,7 +365,7 @@ class bybit(ccxt.async_support.bybit):
313
365
  market = self.market(symbol)
314
366
  symbol = market['symbol']
315
367
  messageHash = 'ticker:' + symbol
316
- url = self.get_url_by_market_type(symbol, False, 'watchTicker', params)
368
+ url = await self.get_url_by_market_type(symbol, False, 'watchTicker', params)
317
369
  params = self.clean_params(params)
318
370
  options = self.safe_value(self.options, 'watchTicker', {})
319
371
  topic = self.safe_string(options, 'name', 'tickers')
@@ -326,8 +378,10 @@ class bybit(ccxt.async_support.bybit):
326
378
  async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
327
379
  """
328
380
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
329
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/ticker
330
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/etp-ticker
381
+
382
+ https://bybit-exchange.github.io/docs/v5/websocket/public/ticker
383
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-ticker
384
+
331
385
  :param str[] symbols: unified symbol of the market to fetch the ticker for
332
386
  :param dict [params]: extra parameters specific to the exchange API endpoint
333
387
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -335,7 +389,7 @@ class bybit(ccxt.async_support.bybit):
335
389
  await self.load_markets()
336
390
  symbols = self.market_symbols(symbols, None, False)
337
391
  messageHashes = []
338
- url = self.get_url_by_market_type(symbols[0], False, 'watchTickers', params)
392
+ url = await self.get_url_by_market_type(symbols[0], False, 'watchTickers', params)
339
393
  params = self.clean_params(params)
340
394
  options = self.safe_value(self.options, 'watchTickers', {})
341
395
  topic = self.safe_string(options, 'name', 'tickers')
@@ -352,6 +406,48 @@ class bybit(ccxt.async_support.bybit):
352
406
  return result
353
407
  return self.filter_by_array(self.tickers, 'symbol', symbols)
354
408
 
409
+ async def un_watch_tickers(self, symbols: Strings = None, params={}) -> Any:
410
+ """
411
+ unWatches a price ticker
412
+
413
+ https://bybit-exchange.github.io/docs/v5/websocket/public/ticker
414
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-ticker
415
+
416
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
417
+ :param dict [params]: extra parameters specific to the exchange API endpoint
418
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
419
+ """
420
+ await self.load_markets()
421
+ symbols = self.market_symbols(symbols, None, False)
422
+ options = self.safe_value(self.options, 'watchTickers', {})
423
+ topic = self.safe_string(options, 'name', 'tickers')
424
+ messageHashes = []
425
+ subMessageHashes = []
426
+ marketIds = self.market_ids(symbols)
427
+ topics = []
428
+ for i in range(0, len(marketIds)):
429
+ marketId = marketIds[i]
430
+ symbol = symbols[i]
431
+ topics.append(topic + '.' + marketId)
432
+ subMessageHashes.append('ticker:' + symbol)
433
+ messageHashes.append('unsubscribe:ticker:' + symbol)
434
+ url = await self.get_url_by_market_type(symbols[0], False, 'watchTickers', params)
435
+ return await self.un_watch_topics(url, 'ticker', symbols, messageHashes, subMessageHashes, topics, params)
436
+
437
+ async def un_watch_ticker(self, symbols: str, params={}) -> Any:
438
+ """
439
+ unWatches a price ticker
440
+
441
+ https://bybit-exchange.github.io/docs/v5/websocket/public/ticker
442
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-ticker
443
+
444
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
445
+ :param dict [params]: extra parameters specific to the exchange API endpoint
446
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
447
+ """
448
+ await self.load_markets()
449
+ return await self.un_watch_tickers([symbols], params)
450
+
355
451
  def handle_ticker(self, client: Client, message):
356
452
  #
357
453
  # linear
@@ -495,11 +591,57 @@ class bybit(ccxt.async_support.bybit):
495
591
  messageHash = 'ticker:' + symbol
496
592
  client.resolve(self.tickers[symbol], messageHash)
497
593
 
594
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
595
+ """
596
+ watches best bid & ask for symbols
597
+
598
+ https://bybit-exchange.github.io/docs/v5/websocket/public/orderbook
599
+
600
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
601
+ :param dict [params]: extra parameters specific to the exchange API endpoint
602
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
603
+ """
604
+ await self.load_markets()
605
+ symbols = self.market_symbols(symbols, None, False)
606
+ messageHashes = []
607
+ url = await self.get_url_by_market_type(symbols[0], False, 'watchBidsAsks', params)
608
+ params = self.clean_params(params)
609
+ marketIds = self.market_ids(symbols)
610
+ topics = []
611
+ for i in range(0, len(marketIds)):
612
+ marketId = marketIds[i]
613
+ topic = 'orderbook.1.' + marketId
614
+ topics.append(topic)
615
+ messageHashes.append('bidask:' + symbols[i])
616
+ ticker = await self.watch_topics(url, messageHashes, topics, params)
617
+ if self.newUpdates:
618
+ return ticker
619
+ return self.filter_by_array(self.bidsasks, 'symbol', symbols)
620
+
621
+ def parse_ws_bid_ask(self, orderbook, market=None):
622
+ timestamp = self.safe_integer(orderbook, 'timestamp')
623
+ bids = self.sort_by(self.aggregate(orderbook['bids']), 0)
624
+ asks = self.sort_by(self.aggregate(orderbook['asks']), 0)
625
+ bestBid = self.safe_list(bids, 0, [])
626
+ bestAsk = self.safe_list(asks, 0, [])
627
+ return self.safe_ticker({
628
+ 'symbol': market['symbol'],
629
+ 'timestamp': timestamp,
630
+ 'datetime': self.iso8601(timestamp),
631
+ 'ask': self.safe_number(bestAsk, 0),
632
+ 'askVolume': self.safe_number(bestAsk, 1),
633
+ 'bid': self.safe_number(bestBid, 0),
634
+ 'bidVolume': self.safe_number(bestBid, 1),
635
+ 'info': orderbook,
636
+ }, market)
637
+
498
638
  async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
499
639
  """
500
640
  watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
501
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/kline
502
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
641
+
642
+ https://bybit-exchange.github.io/docs/v5/websocket/public/kline
643
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
644
+
503
645
  :param str symbol: unified symbol of the market to fetch OHLCV data for
504
646
  :param str timeframe: the length of time each candle represents
505
647
  :param int [since]: timestamp in ms of the earliest candle to fetch
@@ -507,19 +649,93 @@ class bybit(ccxt.async_support.bybit):
507
649
  :param dict [params]: extra parameters specific to the exchange API endpoint
508
650
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
509
651
  """
652
+ params['callerMethodName'] = 'watchOHLCV'
653
+ result = await self.watch_ohlcv_for_symbols([[symbol, timeframe]], since, limit, params)
654
+ return result[symbol][timeframe]
655
+
656
+ async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}):
657
+ """
658
+ watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
659
+
660
+ https://bybit-exchange.github.io/docs/v5/websocket/public/kline
661
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
662
+
663
+ :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
664
+ :param int [since]: timestamp in ms of the earliest candle to fetch
665
+ :param int [limit]: the maximum amount of candles to fetch
666
+ :param dict [params]: extra parameters specific to the exchange API endpoint
667
+ :returns dict: A list of candles ordered, open, high, low, close, volume
668
+ """
510
669
  await self.load_markets()
511
- market = self.market(symbol)
512
- symbol = market['symbol']
513
- url = self.get_url_by_market_type(symbol, False, 'watchOHLCV', params)
514
- params = self.clean_params(params)
515
- ohlcv = None
516
- timeframeId = self.safe_string(self.timeframes, timeframe, timeframe)
517
- topics = ['kline.' + timeframeId + '.' + market['id']]
518
- messageHash = 'kline' + ':' + timeframeId + ':' + symbol
519
- ohlcv = await self.watch_topics(url, [messageHash], topics, params)
670
+ symbols = self.get_list_from_object_values(symbolsAndTimeframes, 0)
671
+ marketSymbols = self.market_symbols(symbols, None, False, True, True)
672
+ firstSymbol = marketSymbols[0]
673
+ url = await self.get_url_by_market_type(firstSymbol, False, 'watchOHLCVForSymbols', params)
674
+ rawHashes = []
675
+ messageHashes = []
676
+ for i in range(0, len(symbolsAndTimeframes)):
677
+ data = symbolsAndTimeframes[i]
678
+ symbolString = self.safe_string(data, 0)
679
+ market = self.market(symbolString)
680
+ symbolString = market['symbol']
681
+ unfiedTimeframe = self.safe_string(data, 1)
682
+ timeframeId = self.safe_string(self.timeframes, unfiedTimeframe, unfiedTimeframe)
683
+ rawHashes.append('kline.' + timeframeId + '.' + market['id'])
684
+ messageHashes.append('ohlcv::' + symbolString + '::' + unfiedTimeframe)
685
+ symbol, timeframe, stored = await self.watch_topics(url, messageHashes, rawHashes, params)
520
686
  if self.newUpdates:
521
- limit = ohlcv.getLimit(symbol, limit)
522
- return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
687
+ limit = stored.getLimit(symbol, limit)
688
+ filtered = self.filter_by_since_limit(stored, since, limit, 0, True)
689
+ return self.create_ohlcv_object(symbol, timeframe, filtered)
690
+
691
+ async def un_watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], params={}) -> Any:
692
+ """
693
+ unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
694
+
695
+ https://bybit-exchange.github.io/docs/v5/websocket/public/kline
696
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
697
+
698
+ :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
699
+ :param dict [params]: extra parameters specific to the exchange API endpoint
700
+ :returns dict: A list of candles ordered, open, high, low, close, volume
701
+ """
702
+ await self.load_markets()
703
+ symbols = self.get_list_from_object_values(symbolsAndTimeframes, 0)
704
+ marketSymbols = self.market_symbols(symbols, None, False, True, True)
705
+ firstSymbol = marketSymbols[0]
706
+ url = await self.get_url_by_market_type(firstSymbol, False, 'watchOHLCVForSymbols', params)
707
+ rawHashes = []
708
+ subMessageHashes = []
709
+ messageHashes = []
710
+ for i in range(0, len(symbolsAndTimeframes)):
711
+ data = symbolsAndTimeframes[i]
712
+ symbolString = self.safe_string(data, 0)
713
+ market = self.market(symbolString)
714
+ symbolString = market['symbol']
715
+ unfiedTimeframe = self.safe_string(data, 1)
716
+ timeframeId = self.safe_string(self.timeframes, unfiedTimeframe, unfiedTimeframe)
717
+ rawHashes.append('kline.' + timeframeId + '.' + market['id'])
718
+ subMessageHashes.append('ohlcv::' + symbolString + '::' + unfiedTimeframe)
719
+ messageHashes.append('unsubscribe::ohlcv::' + symbolString + '::' + unfiedTimeframe)
720
+ subExtension = {
721
+ 'symbolsAndTimeframes': symbolsAndTimeframes,
722
+ }
723
+ return await self.un_watch_topics(url, 'ohlcv', symbols, messageHashes, subMessageHashes, rawHashes, params, subExtension)
724
+
725
+ async def un_watch_ohlcv(self, symbol: str, timeframe='1m', params={}) -> Any:
726
+ """
727
+ unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
728
+
729
+ https://bybit-exchange.github.io/docs/v5/websocket/public/kline
730
+ https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
731
+
732
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
733
+ :param str timeframe: the length of time each candle represents
734
+ :param dict [params]: extra parameters specific to the exchange API endpoint
735
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
736
+ """
737
+ params['callerMethodName'] = 'watchOHLCV'
738
+ return await self.un_watch_ohlcv_for_symbols([[symbol, timeframe]], params)
523
739
 
524
740
  def handle_ohlcv(self, client: Client, message):
525
741
  #
@@ -558,16 +774,16 @@ class bybit(ccxt.async_support.bybit):
558
774
  ohlcvsByTimeframe = self.safe_value(self.ohlcvs, symbol)
559
775
  if ohlcvsByTimeframe is None:
560
776
  self.ohlcvs[symbol] = {}
561
- stored = self.safe_value(ohlcvsByTimeframe, timeframe)
562
- if stored is None:
777
+ if self.safe_value(ohlcvsByTimeframe, timeframe) is None:
563
778
  limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
564
- stored = ArrayCacheByTimestamp(limit)
565
- self.ohlcvs[symbol][timeframe] = stored
779
+ self.ohlcvs[symbol][timeframe] = ArrayCacheByTimestamp(limit)
780
+ stored = self.ohlcvs[symbol][timeframe]
566
781
  for i in range(0, len(data)):
567
- parsed = self.parse_ws_ohlcv(data[i])
782
+ parsed = self.parse_ws_ohlcv(data[i], market)
568
783
  stored.append(parsed)
569
- messageHash = 'kline' + ':' + timeframeId + ':' + symbol
570
- client.resolve(stored, messageHash)
784
+ messageHash = 'ohlcv::' + symbol + '::' + timeframe
785
+ resolveData = [symbol, timeframe, stored]
786
+ client.resolve(resolveData, messageHash)
571
787
 
572
788
  def parse_ws_ohlcv(self, ohlcv, market=None) -> list:
573
789
  #
@@ -585,19 +801,22 @@ class bybit(ccxt.async_support.bybit):
585
801
  # "timestamp": 1670363219614
586
802
  # }
587
803
  #
804
+ volumeIndex = 'turnover' if (market['inverse']) else 'volume'
588
805
  return [
589
806
  self.safe_integer(ohlcv, 'start'),
590
807
  self.safe_number(ohlcv, 'open'),
591
808
  self.safe_number(ohlcv, 'high'),
592
809
  self.safe_number(ohlcv, 'low'),
593
810
  self.safe_number(ohlcv, 'close'),
594
- self.safe_number_2(ohlcv, 'volume', 'turnover'),
811
+ self.safe_number(ohlcv, volumeIndex),
595
812
  ]
596
813
 
597
814
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
598
815
  """
599
816
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
600
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/orderbook
817
+
818
+ https://bybit-exchange.github.io/docs/v5/websocket/public/orderbook
819
+
601
820
  :param str symbol: unified symbol of the market to fetch the order book for
602
821
  :param int [limit]: the maximum amount of order book entries to return.
603
822
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -608,7 +827,9 @@ class bybit(ccxt.async_support.bybit):
608
827
  async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
609
828
  """
610
829
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
611
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/orderbook
830
+
831
+ https://bybit-exchange.github.io/docs/v5/websocket/public/orderbook
832
+
612
833
  :param str[] symbols: unified array of symbols
613
834
  :param int [limit]: the maximum amount of order book entries to return.
614
835
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -619,16 +840,22 @@ class bybit(ccxt.async_support.bybit):
619
840
  if symbolsLength == 0:
620
841
  raise ArgumentsRequired(self.id + ' watchOrderBookForSymbols() requires a non-empty array of symbols')
621
842
  symbols = self.market_symbols(symbols)
622
- url = self.get_url_by_market_type(symbols[0], False, 'watchOrderBook', params)
843
+ url = await self.get_url_by_market_type(symbols[0], False, 'watchOrderBook', params)
623
844
  params = self.clean_params(params)
624
845
  market = self.market(symbols[0])
625
846
  if limit is None:
626
847
  limit = 50 if (market['spot']) else 500
848
+ if market['option']:
849
+ limit = 100
627
850
  else:
628
- if not market['spot']:
629
- # bybit only support limit 1, 50, 200, 500 for contract
630
- if (limit != 1) and (limit != 50) and (limit != 200) and (limit != 500):
631
- raise BadRequest(self.id + ' watchOrderBookForSymbols() can only use limit 1, 50, 200 and 500.')
851
+ limits = {
852
+ 'spot': [1, 50, 200, 1000],
853
+ 'option': [25, 100],
854
+ 'default': [1, 50, 200, 500, 1000],
855
+ }
856
+ selectedLimits = self.safe_list_2(limits, market['type'], 'default')
857
+ if not self.in_array(limit, selectedLimits):
858
+ raise BadRequest(self.id + ' watchOrderBookForSymbols(): for ' + market['type'] + ' markets limit can be one of: ' + self.json(selectedLimits))
632
859
  topics = []
633
860
  messageHashes = []
634
861
  for i in range(0, len(symbols)):
@@ -641,6 +868,55 @@ class bybit(ccxt.async_support.bybit):
641
868
  orderbook = await self.watch_topics(url, messageHashes, topics, params)
642
869
  return orderbook.limit()
643
870
 
871
+ async def un_watch_order_book_for_symbols(self, symbols: List[str], params={}) -> Any:
872
+ """
873
+ unsubscribe from the orderbook channel
874
+
875
+ https://bybit-exchange.github.io/docs/v5/websocket/public/orderbook
876
+
877
+ :param str[] symbols: unified symbol of the market to unwatch the trades for
878
+ :param dict [params]: extra parameters specific to the exchange API endpoint
879
+ :param int [params.limit]: orderbook limit, default is None
880
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
881
+ """
882
+ await self.load_markets()
883
+ symbols = self.market_symbols(symbols, None, False)
884
+ channel = 'orderbook.'
885
+ limit = self.safe_integer(params, 'limit')
886
+ if limit is not None:
887
+ params = self.omit(params, 'limit')
888
+ else:
889
+ firstMarket = self.market(symbols[0])
890
+ limit = 50 if firstMarket['spot'] else 500
891
+ channel += str(limit)
892
+ subMessageHashes = []
893
+ messageHashes = []
894
+ topics = []
895
+ for i in range(0, len(symbols)):
896
+ symbol = symbols[i]
897
+ market = self.market(symbol)
898
+ marketId = market['id']
899
+ topic = channel + '.' + marketId
900
+ messageHashes.append('unsubscribe:orderbook:' + symbol)
901
+ subMessageHashes.append('orderbook:' + symbol)
902
+ topics.append(topic)
903
+ url = await self.get_url_by_market_type(symbols[0], False, 'watchOrderBook', params)
904
+ return await self.un_watch_topics(url, 'orderbook', symbols, messageHashes, subMessageHashes, topics, params)
905
+
906
+ async def un_watch_order_book(self, symbol: str, params={}) -> Any:
907
+ """
908
+ unsubscribe from the orderbook channel
909
+
910
+ https://bybit-exchange.github.io/docs/v5/websocket/public/orderbook
911
+
912
+ :param str symbol: symbol of the market to unwatch the trades for
913
+ :param dict [params]: extra parameters specific to the exchange API endpoint
914
+ :param int [params.limit]: orderbook limit, default is None
915
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
916
+ """
917
+ await self.load_markets()
918
+ return await self.un_watch_order_book_for_symbols([symbol], params)
919
+
644
920
  def handle_order_book(self, client: Client, message):
645
921
  #
646
922
  # {
@@ -675,6 +951,8 @@ class bybit(ccxt.async_support.bybit):
675
951
  # }
676
952
  # }
677
953
  #
954
+ topic = self.safe_string(message, 'topic')
955
+ limit = topic.split('.')[1]
678
956
  isSpot = client.url.find('spot') >= 0
679
957
  type = self.safe_string(message, 'type')
680
958
  isSnapshot = (type == 'snapshot')
@@ -700,6 +978,12 @@ class bybit(ccxt.async_support.bybit):
700
978
  messageHash = 'orderbook' + ':' + symbol
701
979
  self.orderbooks[symbol] = orderbook
702
980
  client.resolve(orderbook, messageHash)
981
+ if limit == '1':
982
+ bidask = self.parse_ws_bid_ask(self.orderbooks[symbol], market)
983
+ newBidsAsks: dict = {}
984
+ newBidsAsks[symbol] = bidask
985
+ self.bidsasks[symbol] = bidask
986
+ client.resolve(newBidsAsks, 'bidask:' + symbol)
703
987
 
704
988
  def handle_delta(self, bookside, delta):
705
989
  bidAsk = self.parse_bid_ask(delta, 0, 1)
@@ -712,19 +996,23 @@ class bybit(ccxt.async_support.bybit):
712
996
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
713
997
  """
714
998
  watches information on multiple trades made in a market
715
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/trade
999
+
1000
+ https://bybit-exchange.github.io/docs/v5/websocket/public/trade
1001
+
716
1002
  :param str symbol: unified market symbol of the market trades were made in
717
1003
  :param int [since]: the earliest time in ms to fetch trades for
718
1004
  :param int [limit]: the maximum number of trade structures to retrieve
719
1005
  :param dict [params]: extra parameters specific to the exchange API endpoint
720
- :returns dict[]: a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure
1006
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
721
1007
  """
722
1008
  return await self.watch_trades_for_symbols([symbol], since, limit, params)
723
1009
 
724
1010
  async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
725
1011
  """
726
1012
  get the list of most recent trades for a list of symbols
727
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/trade
1013
+
1014
+ https://bybit-exchange.github.io/docs/v5/websocket/public/trade
1015
+
728
1016
  :param str[] symbols: unified symbol of the market to fetch trades for
729
1017
  :param int [since]: timestamp in ms of the earliest trade to fetch
730
1018
  :param int [limit]: the maximum amount of trades to fetch
@@ -737,7 +1025,7 @@ class bybit(ccxt.async_support.bybit):
737
1025
  if symbolsLength == 0:
738
1026
  raise ArgumentsRequired(self.id + ' watchTradesForSymbols() requires a non-empty array of symbols')
739
1027
  params = self.clean_params(params)
740
- url = self.get_url_by_market_type(symbols[0], False, 'watchTrades', params)
1028
+ url = await self.get_url_by_market_type(symbols[0], False, 'watchTrades', params)
741
1029
  topics = []
742
1030
  messageHashes = []
743
1031
  for i in range(0, len(symbols)):
@@ -754,6 +1042,45 @@ class bybit(ccxt.async_support.bybit):
754
1042
  limit = trades.getLimit(tradeSymbol, limit)
755
1043
  return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
756
1044
 
1045
+ async def un_watch_trades_for_symbols(self, symbols: List[str], params={}) -> Any:
1046
+ """
1047
+ unsubscribe from the trades channel
1048
+
1049
+ https://bybit-exchange.github.io/docs/v5/websocket/public/trade
1050
+
1051
+ :param str[] symbols: unified symbol of the market to unwatch the trades for
1052
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1053
+ :returns any: status of the unwatch request
1054
+ """
1055
+ await self.load_markets()
1056
+ symbols = self.market_symbols(symbols, None, False, True)
1057
+ url = await self.get_url_by_market_type(symbols[0], False, 'unWatchTradesForSymbols', params)
1058
+ messageHashes = []
1059
+ topics = []
1060
+ subMessageHashes = []
1061
+ for i in range(0, len(symbols)):
1062
+ symbol = symbols[i]
1063
+ market = self.market(symbol)
1064
+ topic = 'publicTrade.' + market['id']
1065
+ topics.append(topic)
1066
+ messageHash = 'unsubscribe:trade:' + symbol
1067
+ messageHashes.append(messageHash)
1068
+ subMessageHashes.append('trade:' + symbol)
1069
+ return await self.un_watch_topics(url, 'trades', symbols, messageHashes, subMessageHashes, topics, params)
1070
+
1071
+ async def un_watch_trades(self, symbol: str, params={}) -> Any:
1072
+ """
1073
+ unsubscribe from the trades channel
1074
+
1075
+ https://bybit-exchange.github.io/docs/v5/websocket/public/trade
1076
+
1077
+ :param str symbol: unified symbol of the market to unwatch the trades for
1078
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1079
+ :returns any: status of the unwatch request
1080
+ """
1081
+ await self.load_markets()
1082
+ return await self.un_watch_trades_for_symbols([symbol], params)
1083
+
757
1084
  def handle_trades(self, client: Client, message):
758
1085
  #
759
1086
  # {
@@ -873,13 +1200,15 @@ class bybit(ccxt.async_support.bybit):
873
1200
  async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
874
1201
  """
875
1202
  watches information on multiple trades made by the user
876
- :see: https://bybit-exchange.github.io/docs/v5/websocket/private/execution
1203
+
1204
+ https://bybit-exchange.github.io/docs/v5/websocket/private/execution
1205
+
877
1206
  :param str symbol: unified market symbol of the market orders were made in
878
1207
  :param int [since]: the earliest time in ms to fetch orders for
879
1208
  :param int [limit]: the maximum number of order structures to retrieve
880
1209
  :param dict [params]: extra parameters specific to the exchange API endpoint
881
1210
  :param boolean [params.unifiedMargin]: use unified margin account
882
- :returns dict[]: a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure
1211
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
883
1212
  """
884
1213
  method = 'watchMyTrades'
885
1214
  messageHash = 'myTrades'
@@ -887,7 +1216,7 @@ class bybit(ccxt.async_support.bybit):
887
1216
  if symbol is not None:
888
1217
  symbol = self.symbol(symbol)
889
1218
  messageHash += ':' + symbol
890
- url = self.get_url_by_market_type(symbol, True, method, params)
1219
+ url = await self.get_url_by_market_type(symbol, True, method, params)
891
1220
  await self.authenticate(url)
892
1221
  topicByMarket: dict = {
893
1222
  'spot': 'ticketInfo',
@@ -900,6 +1229,33 @@ class bybit(ccxt.async_support.bybit):
900
1229
  limit = trades.getLimit(symbol, limit)
901
1230
  return self.filter_by_symbol_since_limit(trades, symbol, since, limit, True)
902
1231
 
1232
+ async def un_watch_my_trades(self, symbol: Str = None, params={}) -> Any:
1233
+ """
1234
+ unWatches information on multiple trades made by the user
1235
+
1236
+ https://bybit-exchange.github.io/docs/v5/websocket/private/execution
1237
+
1238
+ :param str symbol: unified market symbol of the market orders were made in
1239
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1240
+ :param boolean [params.unifiedMargin]: use unified margin account
1241
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1242
+ """
1243
+ method = 'watchMyTrades'
1244
+ messageHash = 'unsubscribe:myTrades'
1245
+ subHash = 'myTrades'
1246
+ await self.load_markets()
1247
+ if symbol is not None:
1248
+ raise NotSupported(self.id + ' unWatchMyTrades() does not support a symbol parameter, you must unwatch all my trades')
1249
+ url = await self.get_url_by_market_type(symbol, True, method, params)
1250
+ await self.authenticate(url)
1251
+ topicByMarket: dict = {
1252
+ 'spot': 'ticketInfo',
1253
+ 'unified': 'execution',
1254
+ 'usdc': 'user.openapi.perp.trade',
1255
+ }
1256
+ topic = self.safe_value(topicByMarket, self.get_private_type(url))
1257
+ return await self.un_watch_topics(url, 'myTrades', [], [messageHash], [subHash], [topic], params)
1258
+
903
1259
  def handle_my_trades(self, client: Client, message):
904
1260
  #
905
1261
  # spot
@@ -973,12 +1329,17 @@ class bybit(ccxt.async_support.bybit):
973
1329
  self.myTrades = ArrayCacheBySymbolById(limit)
974
1330
  trades = self.myTrades
975
1331
  symbols: dict = {}
1332
+ filterExecTypes = self.handle_option('watchMyTrades', 'filterExecTypes', [])
976
1333
  for i in range(0, len(data)):
977
1334
  rawTrade = data[i]
978
1335
  parsed = None
979
1336
  if spot:
980
1337
  parsed = self.parse_ws_trade(rawTrade)
981
1338
  else:
1339
+ # filter unified trades
1340
+ execType = self.safe_string(rawTrade, 'execType', '')
1341
+ if not self.in_array(execType, filterExecTypes):
1342
+ continue
982
1343
  parsed = self.parse_trade(rawTrade)
983
1344
  symbol = parsed['symbol']
984
1345
  symbols[symbol] = True
@@ -993,9 +1354,13 @@ class bybit(ccxt.async_support.bybit):
993
1354
 
994
1355
  async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
995
1356
  """
996
- :see: https://bybit-exchange.github.io/docs/v5/websocket/private/position
1357
+
1358
+ https://bybit-exchange.github.io/docs/v5/websocket/private/position
1359
+
997
1360
  watch all open positions
998
1361
  :param str[] [symbols]: list of unified market symbols
1362
+ :param int [since]: the earliest time in ms to fetch positions for
1363
+ :param int [limit]: the maximum number of positions to retrieve
999
1364
  :param dict params: extra parameters specific to the exchange API endpoint
1000
1365
  :returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
1001
1366
  """
@@ -1006,14 +1371,14 @@ class bybit(ccxt.async_support.bybit):
1006
1371
  symbols = self.market_symbols(symbols)
1007
1372
  messageHash = '::' + ','.join(symbols)
1008
1373
  firstSymbol = self.safe_string(symbols, 0)
1009
- url = self.get_url_by_market_type(firstSymbol, True, method, params)
1374
+ url = await self.get_url_by_market_type(firstSymbol, True, method, params)
1010
1375
  messageHash = 'positions' + messageHash
1011
1376
  client = self.client(url)
1012
1377
  await self.authenticate(url)
1013
1378
  self.set_positions_cache(client, symbols)
1014
1379
  cache = self.positions
1015
1380
  fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', True)
1016
- awaitPositionsSnapshot = self.safe_bool('watchPositions', 'awaitPositionsSnapshot', True)
1381
+ awaitPositionsSnapshot = self.handle_option('watchPositions', 'awaitPositionsSnapshot', True)
1017
1382
  if fetchPositionsSnapshot and awaitPositionsSnapshot and cache is None:
1018
1383
  snapshot = await client.future('fetchPositionsSnapshot')
1019
1384
  return self.filter_by_symbols_since_limit(snapshot, symbols, since, limit, True)
@@ -1128,76 +1493,143 @@ class bybit(ccxt.async_support.bybit):
1128
1493
  client.resolve(positions, messageHash)
1129
1494
  client.resolve(newPositions, 'positions')
1130
1495
 
1496
+ async def un_watch_positions(self, symbols: Strings = None, params={}) -> Any:
1497
+ """
1498
+ unWatches all open positions
1499
+
1500
+ https://bybit-exchange.github.io/docs/v5/websocket/private/position
1501
+
1502
+ :param str[] [symbols]: list of unified market symbols
1503
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1504
+ :returns dict: status of the unwatch request
1505
+ """
1506
+ await self.load_markets()
1507
+ method = 'watchPositions'
1508
+ messageHash = 'unsubscribe:positions'
1509
+ subHash = 'positions'
1510
+ if not self.is_empty(symbols):
1511
+ raise NotSupported(self.id + ' unWatchPositions() does not support a symbol parameter, you must unwatch all orders')
1512
+ url = await self.get_url_by_market_type(None, True, method, params)
1513
+ await self.authenticate(url)
1514
+ topics = ['position']
1515
+ return await self.un_watch_topics(url, 'positions', symbols, [messageHash], [subHash], topics, params)
1516
+
1131
1517
  async def watch_liquidations(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
1132
1518
  """
1133
1519
  watch the public liquidations of a trading pair
1134
- :see: https://bybit-exchange.github.io/docs/v5/websocket/public/liquidation
1520
+
1521
+ https://bybit-exchange.github.io/docs/v5/websocket/public/liquidation
1522
+
1135
1523
  :param str symbol: unified CCXT market symbol
1136
1524
  :param int [since]: the earliest time in ms to fetch liquidations for
1137
1525
  :param int [limit]: the maximum number of liquidation structures to retrieve
1138
1526
  :param dict [params]: exchange specific parameters for the bitmex api endpoint
1527
+ :param str [params.method]: exchange specific method, supported: liquidation, allLiquidation
1139
1528
  :returns dict: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
1140
1529
  """
1141
1530
  await self.load_markets()
1142
1531
  market = self.market(symbol)
1143
1532
  symbol = market['symbol']
1144
- url = self.get_url_by_market_type(symbol, False, 'watchLiquidations', params)
1533
+ url = await self.get_url_by_market_type(symbol, False, 'watchLiquidations', params)
1145
1534
  params = self.clean_params(params)
1535
+ method = None
1536
+ method, params = self.handle_option_and_params(params, 'watchLiquidations', 'method', 'liquidation')
1146
1537
  messageHash = 'liquidations::' + symbol
1147
- topic = 'liquidation.' + market['id']
1538
+ topic = method + '.' + market['id']
1148
1539
  newLiquidation = await self.watch_topics(url, [messageHash], [topic], params)
1149
1540
  if self.newUpdates:
1150
- return [newLiquidation]
1541
+ return newLiquidation
1151
1542
  return self.filter_by_symbols_since_limit(self.liquidations, [symbol], since, limit, True)
1152
1543
 
1153
1544
  def handle_liquidation(self, client: Client, message):
1154
1545
  #
1155
- # {
1156
- # "data": {
1157
- # "price": "0.03803",
1158
- # "side": "Buy",
1159
- # "size": "1637",
1160
- # "symbol": "GALAUSDT",
1161
- # "updatedTime": 1673251091822
1162
- # },
1163
- # "topic": "liquidation.GALAUSDT",
1164
- # "ts": 1673251091822,
1165
- # "type": "snapshot"
1166
- # }
1546
+ # {
1547
+ # "data": {
1548
+ # "price": "0.03803",
1549
+ # "side": "Buy",
1550
+ # "size": "1637",
1551
+ # "symbol": "GALAUSDT",
1552
+ # "updatedTime": 1673251091822
1553
+ # },
1554
+ # "topic": "liquidation.GALAUSDT",
1555
+ # "ts": 1673251091822,
1556
+ # "type": "snapshot"
1557
+ # }
1167
1558
  #
1168
- rawLiquidation = self.safe_dict(message, 'data', {})
1169
- marketId = self.safe_string(rawLiquidation, 'symbol')
1170
- market = self.safe_market(marketId, None, '', 'contract')
1171
- symbol = self.safe_symbol(marketId)
1172
- liquidation = self.parse_ws_liquidation(rawLiquidation, market)
1173
- liquidations = self.safe_value(self.liquidations, symbol)
1174
- if liquidations is None:
1175
- limit = self.safe_integer(self.options, 'liquidationsLimit', 1000)
1176
- liquidations = ArrayCache(limit)
1177
- liquidations.append(liquidation)
1178
- self.liquidations[symbol] = liquidations
1179
- client.resolve([liquidation], 'liquidations')
1180
- client.resolve([liquidation], 'liquidations::' + symbol)
1559
+ # {
1560
+ # "topic": "allLiquidation.ROSEUSDT",
1561
+ # "type": "snapshot",
1562
+ # "ts": 1739502303204,
1563
+ # "data": [
1564
+ # {
1565
+ # "T": 1739502302929,
1566
+ # "s": "ROSEUSDT",
1567
+ # "S": "Sell",
1568
+ # "v": "20000",
1569
+ # "p": "0.04499"
1570
+ # }
1571
+ # ]
1572
+ # }
1573
+ #
1574
+ if isinstance(message['data'], list):
1575
+ rawLiquidations = self.safe_list(message, 'data', [])
1576
+ for i in range(0, len(rawLiquidations)):
1577
+ rawLiquidation = rawLiquidations[i]
1578
+ marketId = self.safe_string(rawLiquidation, 's')
1579
+ market = self.safe_market(marketId, None, '', 'contract')
1580
+ symbol = market['symbol']
1581
+ liquidation = self.parse_ws_liquidation(rawLiquidation, market)
1582
+ liquidations = self.safe_value(self.liquidations, symbol)
1583
+ if liquidations is None:
1584
+ limit = self.safe_integer(self.options, 'liquidationsLimit', 1000)
1585
+ liquidations = ArrayCache(limit)
1586
+ liquidations.append(liquidation)
1587
+ self.liquidations[symbol] = liquidations
1588
+ client.resolve([liquidation], 'liquidations')
1589
+ client.resolve([liquidation], 'liquidations::' + symbol)
1590
+ else:
1591
+ rawLiquidation = self.safe_dict(message, 'data', {})
1592
+ marketId = self.safe_string(rawLiquidation, 'symbol')
1593
+ market = self.safe_market(marketId, None, '', 'contract')
1594
+ symbol = market['symbol']
1595
+ liquidation = self.parse_ws_liquidation(rawLiquidation, market)
1596
+ liquidations = self.safe_value(self.liquidations, symbol)
1597
+ if liquidations is None:
1598
+ limit = self.safe_integer(self.options, 'liquidationsLimit', 1000)
1599
+ liquidations = ArrayCache(limit)
1600
+ liquidations.append(liquidation)
1601
+ self.liquidations[symbol] = liquidations
1602
+ client.resolve([liquidation], 'liquidations')
1603
+ client.resolve([liquidation], 'liquidations::' + symbol)
1181
1604
 
1182
1605
  def parse_ws_liquidation(self, liquidation, market=None):
1183
1606
  #
1184
- # {
1185
- # "price": "0.03803",
1186
- # "side": "Buy",
1187
- # "size": "1637",
1188
- # "symbol": "GALAUSDT",
1189
- # "updatedTime": 1673251091822
1190
- # }
1607
+ # {
1608
+ # "price": "0.03803",
1609
+ # "side": "Buy",
1610
+ # "size": "1637",
1611
+ # "symbol": "GALAUSDT",
1612
+ # "updatedTime": 1673251091822
1613
+ # }
1191
1614
  #
1192
- marketId = self.safe_string(liquidation, 'symbol')
1615
+ # {
1616
+ # "T": 1739502302929,
1617
+ # "s": "ROSEUSDT",
1618
+ # "S": "Sell",
1619
+ # "v": "20000",
1620
+ # "p": "0.04499"
1621
+ # }
1622
+ #
1623
+ marketId = self.safe_string_2(liquidation, 'symbol', 's')
1193
1624
  market = self.safe_market(marketId, market, '', 'contract')
1194
- timestamp = self.safe_integer(liquidation, 'updatedTime')
1625
+ timestamp = self.safe_integer_2(liquidation, 'updatedTime', 'T')
1195
1626
  return self.safe_liquidation({
1196
1627
  'info': liquidation,
1197
- 'symbol': self.safe_symbol(marketId, market),
1198
- 'contracts': self.safe_number(liquidation, 'size'),
1628
+ 'symbol': market['symbol'],
1629
+ 'contracts': self.safe_number_2(liquidation, 'size', 'v'),
1199
1630
  'contractSize': self.safe_number(market, 'contractSize'),
1200
- 'price': self.safe_number(liquidation, 'price'),
1631
+ 'price': self.safe_number_2(liquidation, 'price', 'p'),
1632
+ 'side': self.safe_string_lower(liquidation, 'side', 'S'),
1201
1633
  'baseValue': None,
1202
1634
  'quoteValue': None,
1203
1635
  'timestamp': timestamp,
@@ -1207,12 +1639,14 @@ class bybit(ccxt.async_support.bybit):
1207
1639
  async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1208
1640
  """
1209
1641
  watches information on multiple orders made by the user
1210
- :see: https://bybit-exchange.github.io/docs/v5/websocket/private/order
1642
+
1643
+ https://bybit-exchange.github.io/docs/v5/websocket/private/order
1644
+
1211
1645
  :param str symbol: unified market symbol of the market orders were made in
1212
1646
  :param int [since]: the earliest time in ms to fetch orders for
1213
1647
  :param int [limit]: the maximum number of order structures to retrieve
1214
1648
  :param dict [params]: extra parameters specific to the exchange API endpoint
1215
- :returns dict[]: a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure
1649
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1216
1650
  """
1217
1651
  await self.load_markets()
1218
1652
  method = 'watchOrders'
@@ -1220,7 +1654,7 @@ class bybit(ccxt.async_support.bybit):
1220
1654
  if symbol is not None:
1221
1655
  symbol = self.symbol(symbol)
1222
1656
  messageHash += ':' + symbol
1223
- url = self.get_url_by_market_type(symbol, True, method, params)
1657
+ url = await self.get_url_by_market_type(symbol, True, method, params)
1224
1658
  await self.authenticate(url)
1225
1659
  topicsByMarket: dict = {
1226
1660
  'spot': ['order', 'stopOrder'],
@@ -1233,6 +1667,33 @@ class bybit(ccxt.async_support.bybit):
1233
1667
  limit = orders.getLimit(symbol, limit)
1234
1668
  return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
1235
1669
 
1670
+ async def un_watch_orders(self, symbol: Str = None, params={}) -> Any:
1671
+ """
1672
+ unWatches information on multiple orders made by the user
1673
+
1674
+ https://bybit-exchange.github.io/docs/v5/websocket/private/order
1675
+
1676
+ :param str symbol: unified market symbol of the market orders were made in
1677
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1678
+ :param boolean [params.unifiedMargin]: use unified margin account
1679
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1680
+ """
1681
+ await self.load_markets()
1682
+ method = 'watchOrders'
1683
+ messageHash = 'unsubscribe:orders'
1684
+ subHash = 'orders'
1685
+ if symbol is not None:
1686
+ raise NotSupported(self.id + ' unWatchOrders() does not support a symbol parameter, you must unwatch all orders')
1687
+ url = await self.get_url_by_market_type(symbol, True, method, params)
1688
+ await self.authenticate(url)
1689
+ topicsByMarket: dict = {
1690
+ 'spot': ['order', 'stopOrder'],
1691
+ 'unified': ['order'],
1692
+ 'usdc': ['user.openapi.perp.order'],
1693
+ }
1694
+ topics = self.safe_value(topicsByMarket, self.get_private_type(url))
1695
+ return await self.un_watch_topics(url, 'orders', [], [messageHash], [subHash], topics, params)
1696
+
1236
1697
  def handle_order_ws(self, client: Client, message):
1237
1698
  #
1238
1699
  # {
@@ -1355,11 +1816,12 @@ class bybit(ccxt.async_support.bybit):
1355
1816
  rawOrders = self.safe_value(rawOrders, 'result', rawOrders)
1356
1817
  symbols: dict = {}
1357
1818
  for i in range(0, len(rawOrders)):
1358
- parsed = None
1359
- if isSpot:
1360
- parsed = self.parse_ws_spot_order(rawOrders[i])
1361
- else:
1362
- parsed = self.parse_order(rawOrders[i])
1819
+ parsed = self.parse_order(rawOrders[i])
1820
+ # if isSpot:
1821
+ # parsed = self.parseWsSpotOrder(rawOrders[i])
1822
+ # else:
1823
+ # parsed = self.parse_order(rawOrders[i])
1824
+ # }
1363
1825
  symbol = parsed['symbol']
1364
1826
  symbols[symbol] = True
1365
1827
  orders.append(parsed)
@@ -1370,141 +1832,12 @@ class bybit(ccxt.async_support.bybit):
1370
1832
  messageHash = 'orders'
1371
1833
  client.resolve(orders, messageHash)
1372
1834
 
1373
- def parse_ws_spot_order(self, order, market=None):
1374
- #
1375
- # {
1376
- # "e": "executionReport",
1377
- # "E": "1653297251061", # timestamp
1378
- # "s": "LTCUSDT", # symbol
1379
- # "c": "1653297250740", # user id
1380
- # "S": "SELL", # side
1381
- # "o": "MARKET_OF_BASE", # order type
1382
- # "f": "GTC", # time in force
1383
- # "q": "0.16233", # quantity
1384
- # "p": "0", # price
1385
- # "X": "NEW", # status
1386
- # "i": "1162336018974750208", # order id
1387
- # "M": "0",
1388
- # "l": "0", # last filled
1389
- # "z": "0", # total filled
1390
- # "L": "0", # last traded price
1391
- # "n": "0", # trading fee
1392
- # "N": '', # fee asset
1393
- # "u": True,
1394
- # "w": True,
1395
- # "m": False, # is limit_maker
1396
- # "O": "1653297251042", # order creation
1397
- # "Z": "0", # total filled
1398
- # "A": "0", # account id
1399
- # "C": False, # is close
1400
- # "v": "0", # leverage
1401
- # "d": "NO_LIQ"
1402
- # }
1403
- # v5
1404
- # {
1405
- # "category":"spot",
1406
- # "symbol":"LTCUSDT",
1407
- # "orderId":"1474764674982492160",
1408
- # "orderLinkId":"1690541649154749",
1409
- # "blockTradeId":"",
1410
- # "side":"Buy",
1411
- # "positionIdx":0,
1412
- # "orderStatus":"Cancelled",
1413
- # "cancelType":"UNKNOWN",
1414
- # "rejectReason":"EC_NoError",
1415
- # "timeInForce":"GTC",
1416
- # "isLeverage":"0",
1417
- # "price":"0",
1418
- # "qty":"5.00000",
1419
- # "avgPrice":"0",
1420
- # "leavesQty":"0.00000",
1421
- # "leavesValue":"5.0000000",
1422
- # "cumExecQty":"0.00000",
1423
- # "cumExecValue":"0.0000000",
1424
- # "cumExecFee":"",
1425
- # "orderType":"Market",
1426
- # "stopOrderType":"",
1427
- # "orderIv":"",
1428
- # "triggerPrice":"0.000",
1429
- # "takeProfit":"",
1430
- # "stopLoss":"",
1431
- # "triggerBy":"",
1432
- # "tpTriggerBy":"",
1433
- # "slTriggerBy":"",
1434
- # "triggerDirection":0,
1435
- # "placeType":"",
1436
- # "lastPriceOnCreated":"0.000",
1437
- # "closeOnTrigger":false,
1438
- # "reduceOnly":false,
1439
- # "smpGroup":0,
1440
- # "smpType":"None",
1441
- # "smpOrderId":"",
1442
- # "createdTime":"1690541649160",
1443
- # "updatedTime":"1690541649168"
1444
- # }
1445
- #
1446
- id = self.safe_string_2(order, 'i', 'orderId')
1447
- marketId = self.safe_string_2(order, 's', 'symbol')
1448
- symbol = self.safe_symbol(marketId, market, None, 'spot')
1449
- timestamp = self.safe_integer_2(order, 'O', 'createdTime')
1450
- price = self.safe_string_2(order, 'p', 'price')
1451
- if price == '0':
1452
- price = None # market orders
1453
- filled = self.safe_string_2(order, 'z', 'cumExecQty')
1454
- status = self.parse_order_status(self.safe_string_2(order, 'X', 'orderStatus'))
1455
- side = self.safe_string_lower_2(order, 'S', 'side')
1456
- lastTradeTimestamp = self.safe_string_2(order, 'E', 'updatedTime')
1457
- timeInForce = self.safe_string_2(order, 'f', 'timeInForce')
1458
- amount = None
1459
- cost = self.safe_string_2(order, 'Z', 'cumExecValue')
1460
- type = self.safe_string_lower_2(order, 'o', 'orderType')
1461
- if (type is not None) and (type.find('market') >= 0):
1462
- type = 'market'
1463
- if type == 'market' and side == 'buy':
1464
- amount = filled
1465
- else:
1466
- amount = self.safe_string_2(order, 'orderQty', 'qty')
1467
- fee = None
1468
- feeCost = self.safe_string_2(order, 'n', 'cumExecFee')
1469
- if feeCost is not None and feeCost != '0':
1470
- feeCurrencyId = self.safe_string(order, 'N')
1471
- feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
1472
- fee = {
1473
- 'cost': feeCost,
1474
- 'currency': feeCurrencyCode,
1475
- }
1476
- triggerPrice = self.omit_zero(self.safe_string(order, 'triggerPrice'))
1477
- return self.safe_order({
1478
- 'info': order,
1479
- 'id': id,
1480
- 'clientOrderId': self.safe_string_2(order, 'c', 'orderLinkId'),
1481
- 'timestamp': timestamp,
1482
- 'datetime': self.iso8601(timestamp),
1483
- 'lastTradeTimestamp': lastTradeTimestamp,
1484
- 'symbol': symbol,
1485
- 'type': type,
1486
- 'timeInForce': timeInForce,
1487
- 'postOnly': None,
1488
- 'side': side,
1489
- 'price': price,
1490
- 'stopPrice': triggerPrice,
1491
- 'triggerPrice': triggerPrice,
1492
- 'takeProfitPrice': self.safe_string(order, 'takeProfit'),
1493
- 'stopLossPrice': self.safe_string(order, 'stopLoss'),
1494
- 'reduceOnly': self.safe_value(order, 'reduceOnly'),
1495
- 'amount': amount,
1496
- 'cost': cost,
1497
- 'average': self.safe_string(order, 'avgPrice'),
1498
- 'filled': filled,
1499
- 'remaining': None,
1500
- 'status': status,
1501
- 'fee': fee,
1502
- }, market)
1503
-
1504
1835
  async def watch_balance(self, params={}) -> Balances:
1505
1836
  """
1506
1837
  watch balance and get the amount of funds available for trading or funds locked in orders
1507
- :see: https://bybit-exchange.github.io/docs/v5/websocket/private/wallet
1838
+
1839
+ https://bybit-exchange.github.io/docs/v5/websocket/private/wallet
1840
+
1508
1841
  :param dict [params]: extra parameters specific to the exchange API endpoint
1509
1842
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1510
1843
  """
@@ -1518,7 +1851,7 @@ class bybit(ccxt.async_support.bybit):
1518
1851
  unified = await self.isUnifiedEnabled()
1519
1852
  isUnifiedMargin = self.safe_bool(unified, 0, False)
1520
1853
  isUnifiedAccount = self.safe_bool(unified, 1, False)
1521
- url = self.get_url_by_market_type(None, True, method, params)
1854
+ url = await self.get_url_by_market_type(None, True, method, params)
1522
1855
  await self.authenticate(url)
1523
1856
  topicByMarket: dict = {
1524
1857
  'spot': 'outboundAccountInfo',
@@ -1779,7 +2112,24 @@ class bybit(ccxt.async_support.bybit):
1779
2112
  'args': topics,
1780
2113
  }
1781
2114
  message = self.extend(request, params)
1782
- return await self.watch_multiple(url, messageHashes, message, topics)
2115
+ return await self.watch_multiple(url, messageHashes, message, messageHashes)
2116
+
2117
+ async def un_watch_topics(self, url: str, topic: str, symbols: Strings, messageHashes: List[str], subMessageHashes: List[str], topics, params={}, subExtension={}):
2118
+ reqId = self.request_id()
2119
+ request: dict = {
2120
+ 'op': 'unsubscribe',
2121
+ 'req_id': reqId,
2122
+ 'args': topics,
2123
+ }
2124
+ subscription = {
2125
+ 'id': reqId,
2126
+ 'topic': topic,
2127
+ 'messageHashes': messageHashes,
2128
+ 'subMessageHashes': subMessageHashes,
2129
+ 'symbols': symbols,
2130
+ }
2131
+ message = self.extend(request, params)
2132
+ return await self.watch_multiple(url, messageHashes, message, messageHashes, self.extend(subscription, subExtension))
1783
2133
 
1784
2134
  async def authenticate(self, url, params={}):
1785
2135
  self.check_required_credentials()
@@ -1803,7 +2153,7 @@ class bybit(ccxt.async_support.bybit):
1803
2153
  self.watch(url, messageHash, message, messageHash)
1804
2154
  return await future
1805
2155
 
1806
- def handle_error_message(self, client: Client, message):
2156
+ def handle_error_message(self, client: Client, message) -> Bool:
1807
2157
  #
1808
2158
  # {
1809
2159
  # "success": False,
@@ -1894,7 +2244,7 @@ class bybit(ccxt.async_support.bybit):
1894
2244
  if event == 'sub':
1895
2245
  self.handle_subscription_status(client, message)
1896
2246
  return
1897
- topic = self.safe_string_2(message, 'topic', 'op')
2247
+ topic = self.safe_string_2(message, 'topic', 'op', '')
1898
2248
  methods: dict = {
1899
2249
  'orderbook': self.handle_order_book,
1900
2250
  'kline': self.handle_ohlcv,
@@ -1911,11 +2261,13 @@ class bybit(ccxt.async_support.bybit):
1911
2261
  'user.openapi.perp.trade': self.handle_my_trades,
1912
2262
  'position': self.handle_positions,
1913
2263
  'liquidation': self.handle_liquidation,
2264
+ 'allLiquidation': self.handle_liquidation,
1914
2265
  'pong': self.handle_pong,
1915
2266
  'order.create': self.handle_order_ws,
1916
2267
  'order.amend': self.handle_order_ws,
1917
2268
  'order.cancel': self.handle_order_ws,
1918
2269
  'auth': self.handle_authenticate,
2270
+ 'unsubscribe': self.handle_un_subscribe,
1919
2271
  }
1920
2272
  exacMethod = self.safe_value(methods, topic)
1921
2273
  if exacMethod is not None:
@@ -1933,7 +2285,7 @@ class bybit(ccxt.async_support.bybit):
1933
2285
  if type == 'AUTH_RESP':
1934
2286
  self.handle_authenticate(client, message)
1935
2287
 
1936
- def ping(self, client):
2288
+ def ping(self, client: Client):
1937
2289
  return {
1938
2290
  'req_id': self.request_id(),
1939
2291
  'op': 'ping',
@@ -1998,3 +2350,38 @@ class bybit(ccxt.async_support.bybit):
1998
2350
  # }
1999
2351
  #
2000
2352
  return message
2353
+
2354
+ def handle_un_subscribe(self, client: Client, message):
2355
+ #
2356
+ # {"success":true,"ret_msg":"","conn_id":"7188110e-6908-41e9-b863-6365127e92ad","req_id":"3","op":"unsubscribe"}
2357
+ #
2358
+ # client.subscription will be something like:
2359
+ # {
2360
+ # "publicTrade.LTCUSDT":true,
2361
+ # "publicTrade.ADAUSDT":true,
2362
+ # "unsubscribe:trade:LTC/USDT:USDT": {
2363
+ # "id":4,
2364
+ # "subHash": "trade:LTC/USDT"
2365
+ # },
2366
+ # }
2367
+ reqId = self.safe_string(message, 'req_id')
2368
+ keys = list(client.subscriptions.keys())
2369
+ for i in range(0, len(keys)):
2370
+ messageHash = keys[i]
2371
+ if not (messageHash in client.subscriptions):
2372
+ continue
2373
+ # the previous iteration can have deleted the messageHash from the subscriptions
2374
+ if messageHash.startswith('unsubscribe'):
2375
+ subscription = client.subscriptions[messageHash]
2376
+ subId = self.safe_string(subscription, 'id')
2377
+ if reqId != subId:
2378
+ continue
2379
+ messageHashes = self.safe_list(subscription, 'messageHashes', [])
2380
+ subMessageHashes = self.safe_list(subscription, 'subMessageHashes', [])
2381
+ for j in range(0, len(messageHashes)):
2382
+ unsubHash = messageHashes[j]
2383
+ subHash = subMessageHashes[j]
2384
+ usePrefix = (subHash == 'orders') or (subHash == 'myTrades')
2385
+ self.clean_unsubscription(client, subHash, unsubHash, usePrefix)
2386
+ self.clean_cache(subscription)
2387
+ return message