ccxt-ir 4.3.46.0.1__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 (772) hide show
  1. ccxt/__init__.py +358 -0
  2. ccxt/abantether.py +316 -0
  3. ccxt/abstract/__init__.py +0 -0
  4. ccxt/abstract/abantether.py +5 -0
  5. ccxt/abstract/ace.py +15 -0
  6. ccxt/abstract/afratether.py +6 -0
  7. ccxt/abstract/alpaca.py +70 -0
  8. ccxt/abstract/arzinja.py +5 -0
  9. ccxt/abstract/arzplus.py +7 -0
  10. ccxt/abstract/ascendex.py +77 -0
  11. ccxt/abstract/bequant.py +115 -0
  12. ccxt/abstract/bigone.py +45 -0
  13. ccxt/abstract/binance.py +712 -0
  14. ccxt/abstract/binancecoinm.py +712 -0
  15. ccxt/abstract/binanceus.py +764 -0
  16. ccxt/abstract/binanceusdm.py +712 -0
  17. ccxt/abstract/bingx.py +113 -0
  18. ccxt/abstract/bit2c.py +27 -0
  19. ccxt/abstract/bitbank.py +27 -0
  20. ccxt/abstract/bitbay.py +53 -0
  21. ccxt/abstract/bitbns.py +40 -0
  22. ccxt/abstract/bitcoincom.py +115 -0
  23. ccxt/abstract/bitfinex.py +69 -0
  24. ccxt/abstract/bitfinex2.py +139 -0
  25. ccxt/abstract/bitflyer.py +38 -0
  26. ccxt/abstract/bitget.py +508 -0
  27. ccxt/abstract/bithumb.py +32 -0
  28. ccxt/abstract/bitimen.py +7 -0
  29. ccxt/abstract/bitir.py +7 -0
  30. ccxt/abstract/bitmart.py +99 -0
  31. ccxt/abstract/bitmex.py +97 -0
  32. ccxt/abstract/bitopro.py +29 -0
  33. ccxt/abstract/bitpanda.py +35 -0
  34. ccxt/abstract/bitpin.py +7 -0
  35. ccxt/abstract/bitrue.py +72 -0
  36. ccxt/abstract/bitso.py +43 -0
  37. ccxt/abstract/bitstamp.py +258 -0
  38. ccxt/abstract/bitteam.py +29 -0
  39. ccxt/abstract/bitvavo.py +27 -0
  40. ccxt/abstract/bl3p.py +19 -0
  41. ccxt/abstract/blockchaincom.py +28 -0
  42. ccxt/abstract/blofin.py +37 -0
  43. ccxt/abstract/btcalpha.py +18 -0
  44. ccxt/abstract/btcbox.py +13 -0
  45. ccxt/abstract/btcmarkets.py +39 -0
  46. ccxt/abstract/btcturk.py +20 -0
  47. ccxt/abstract/bybit.py +298 -0
  48. ccxt/abstract/cex.py +33 -0
  49. ccxt/abstract/coinbase.py +94 -0
  50. ccxt/abstract/coinbaseadvanced.py +94 -0
  51. ccxt/abstract/coinbaseexchange.py +67 -0
  52. ccxt/abstract/coinbaseinternational.py +39 -0
  53. ccxt/abstract/coincatch.py +94 -0
  54. ccxt/abstract/coincheck.py +33 -0
  55. ccxt/abstract/coinex.py +237 -0
  56. ccxt/abstract/coinlist.py +54 -0
  57. ccxt/abstract/coinmate.py +62 -0
  58. ccxt/abstract/coinmetro.py +34 -0
  59. ccxt/abstract/coinone.py +67 -0
  60. ccxt/abstract/coinsph.py +54 -0
  61. ccxt/abstract/coinspot.py +28 -0
  62. ccxt/abstract/cryptocom.py +107 -0
  63. ccxt/abstract/currencycom.py +68 -0
  64. ccxt/abstract/delta.py +50 -0
  65. ccxt/abstract/deribit.py +125 -0
  66. ccxt/abstract/digifinex.py +91 -0
  67. ccxt/abstract/eterex.py +5 -0
  68. ccxt/abstract/excoino.py +7 -0
  69. ccxt/abstract/exir.py +8 -0
  70. ccxt/abstract/exmo.py +55 -0
  71. ccxt/abstract/exnovin.py +6 -0
  72. ccxt/abstract/farhadexchange.py +5 -0
  73. ccxt/abstract/fmfwio.py +115 -0
  74. ccxt/abstract/gate.py +265 -0
  75. ccxt/abstract/gateio.py +265 -0
  76. ccxt/abstract/gemini.py +58 -0
  77. ccxt/abstract/hashkey.py +67 -0
  78. ccxt/abstract/hitbtc.py +115 -0
  79. ccxt/abstract/hitbtc3.py +115 -0
  80. ccxt/abstract/hitobit.py +8 -0
  81. ccxt/abstract/hollaex.py +33 -0
  82. ccxt/abstract/htx.py +548 -0
  83. ccxt/abstract/huobi.py +548 -0
  84. ccxt/abstract/huobijp.py +114 -0
  85. ccxt/abstract/hyperliquid.py +6 -0
  86. ccxt/abstract/idex.py +26 -0
  87. ccxt/abstract/independentreserve.py +37 -0
  88. ccxt/abstract/indodax.py +26 -0
  89. ccxt/abstract/jibitex.py +7 -0
  90. ccxt/abstract/kraken.py +57 -0
  91. ccxt/abstract/krakenfutures.py +38 -0
  92. ccxt/abstract/kucoin.py +214 -0
  93. ccxt/abstract/kucoinfutures.py +233 -0
  94. ccxt/abstract/kuna.py +182 -0
  95. ccxt/abstract/latoken.py +56 -0
  96. ccxt/abstract/lbank.py +61 -0
  97. ccxt/abstract/luno.py +37 -0
  98. ccxt/abstract/lykke.py +29 -0
  99. ccxt/abstract/mercado.py +25 -0
  100. ccxt/abstract/mexc.py +178 -0
  101. ccxt/abstract/ndax.py +97 -0
  102. ccxt/abstract/nobitex.py +7 -0
  103. ccxt/abstract/novadax.py +29 -0
  104. ccxt/abstract/oceanex.py +22 -0
  105. ccxt/abstract/okcoin.py +74 -0
  106. ccxt/abstract/okexchange.py +8 -0
  107. ccxt/abstract/okx.py +324 -0
  108. ccxt/abstract/ompfinex.py +7 -0
  109. ccxt/abstract/onetrading.py +35 -0
  110. ccxt/abstract/oxfun.py +34 -0
  111. ccxt/abstract/p2b.py +22 -0
  112. ccxt/abstract/paradex.py +40 -0
  113. ccxt/abstract/paymium.py +28 -0
  114. ccxt/abstract/phemex.py +115 -0
  115. ccxt/abstract/poloniex.py +69 -0
  116. ccxt/abstract/poloniexfutures.py +48 -0
  117. ccxt/abstract/probit.py +23 -0
  118. ccxt/abstract/ramzinex.py +7 -0
  119. ccxt/abstract/sarmayex.py +5 -0
  120. ccxt/abstract/sarrafex.py +7 -0
  121. ccxt/abstract/tabdeal.py +7 -0
  122. ccxt/abstract/tetherland.py +5 -0
  123. ccxt/abstract/timex.py +62 -0
  124. ccxt/abstract/tokocrypto.py +37 -0
  125. ccxt/abstract/tradeogre.py +16 -0
  126. ccxt/abstract/twox.py +5 -0
  127. ccxt/abstract/ubitex.py +7 -0
  128. ccxt/abstract/upbit.py +38 -0
  129. ccxt/abstract/vertex.py +19 -0
  130. ccxt/abstract/wallex.py +8 -0
  131. ccxt/abstract/wavesexchange.py +154 -0
  132. ccxt/abstract/wazirx.py +30 -0
  133. ccxt/abstract/whitebit.py +98 -0
  134. ccxt/abstract/woo.py +83 -0
  135. ccxt/abstract/woofipro.py +119 -0
  136. ccxt/abstract/xt.py +152 -0
  137. ccxt/abstract/yobit.py +16 -0
  138. ccxt/abstract/zaif.py +38 -0
  139. ccxt/abstract/zonda.py +53 -0
  140. ccxt/ace.py +1012 -0
  141. ccxt/afratether.py +293 -0
  142. ccxt/alpaca.py +1083 -0
  143. ccxt/arzinja.py +285 -0
  144. ccxt/arzplus.py +412 -0
  145. ccxt/ascendex.py +3330 -0
  146. ccxt/async_support/__init__.py +337 -0
  147. ccxt/async_support/abantether.py +316 -0
  148. ccxt/async_support/ace.py +1012 -0
  149. ccxt/async_support/afratether.py +293 -0
  150. ccxt/async_support/alpaca.py +1083 -0
  151. ccxt/async_support/arzinja.py +285 -0
  152. ccxt/async_support/arzplus.py +412 -0
  153. ccxt/async_support/ascendex.py +3330 -0
  154. ccxt/async_support/base/__init__.py +1 -0
  155. ccxt/async_support/base/exchange.py +1966 -0
  156. ccxt/async_support/base/throttler.py +50 -0
  157. ccxt/async_support/base/ws/__init__.py +38 -0
  158. ccxt/async_support/base/ws/aiohttp_client.py +125 -0
  159. ccxt/async_support/base/ws/cache.py +212 -0
  160. ccxt/async_support/base/ws/client.py +193 -0
  161. ccxt/async_support/base/ws/fast_client.py +96 -0
  162. ccxt/async_support/base/ws/functions.py +59 -0
  163. ccxt/async_support/base/ws/future.py +58 -0
  164. ccxt/async_support/base/ws/order_book.py +78 -0
  165. ccxt/async_support/base/ws/order_book_side.py +174 -0
  166. ccxt/async_support/bequant.py +33 -0
  167. ccxt/async_support/bigone.py +2113 -0
  168. ccxt/async_support/binance.py +12234 -0
  169. ccxt/async_support/binancecoinm.py +45 -0
  170. ccxt/async_support/binanceus.py +211 -0
  171. ccxt/async_support/binanceusdm.py +58 -0
  172. ccxt/async_support/bingx.py +4325 -0
  173. ccxt/async_support/bit2c.py +866 -0
  174. ccxt/async_support/bitbank.py +1001 -0
  175. ccxt/async_support/bitbay.py +17 -0
  176. ccxt/async_support/bitbns.py +1154 -0
  177. ccxt/async_support/bitcoincom.py +17 -0
  178. ccxt/async_support/bitfinex.py +1617 -0
  179. ccxt/async_support/bitfinex2.py +3552 -0
  180. ccxt/async_support/bitflyer.py +995 -0
  181. ccxt/async_support/bitget.py +8273 -0
  182. ccxt/async_support/bithumb.py +1061 -0
  183. ccxt/async_support/bitimen.py +401 -0
  184. ccxt/async_support/bitir.py +490 -0
  185. ccxt/async_support/bitmart.py +4415 -0
  186. ccxt/async_support/bitmex.py +2756 -0
  187. ccxt/async_support/bitopro.py +1630 -0
  188. ccxt/async_support/bitpanda.py +16 -0
  189. ccxt/async_support/bitpin.py +454 -0
  190. ccxt/async_support/bitrue.py +3027 -0
  191. ccxt/async_support/bitso.py +1670 -0
  192. ccxt/async_support/bitstamp.py +2203 -0
  193. ccxt/async_support/bitteam.py +2239 -0
  194. ccxt/async_support/bitvavo.py +1968 -0
  195. ccxt/async_support/bl3p.py +485 -0
  196. ccxt/async_support/blockchaincom.py +1104 -0
  197. ccxt/async_support/blofin.py +2066 -0
  198. ccxt/async_support/btcalpha.py +891 -0
  199. ccxt/async_support/btcbox.py +544 -0
  200. ccxt/async_support/btcmarkets.py +1221 -0
  201. ccxt/async_support/btcturk.py +911 -0
  202. ccxt/async_support/bybit.py +8159 -0
  203. ccxt/async_support/cex.py +1605 -0
  204. ccxt/async_support/coinbase.py +4475 -0
  205. ccxt/async_support/coinbaseadvanced.py +17 -0
  206. ccxt/async_support/coinbaseexchange.py +1734 -0
  207. ccxt/async_support/coinbaseinternational.py +1899 -0
  208. ccxt/async_support/coincatch.py +5069 -0
  209. ccxt/async_support/coincheck.py +815 -0
  210. ccxt/async_support/coinex.py +5526 -0
  211. ccxt/async_support/coinlist.py +2243 -0
  212. ccxt/async_support/coinmate.py +1067 -0
  213. ccxt/async_support/coinmetro.py +1797 -0
  214. ccxt/async_support/coinone.py +1127 -0
  215. ccxt/async_support/coinsph.py +1850 -0
  216. ccxt/async_support/coinspot.py +534 -0
  217. ccxt/async_support/cryptocom.py +2822 -0
  218. ccxt/async_support/currencycom.py +1950 -0
  219. ccxt/async_support/delta.py +3376 -0
  220. ccxt/async_support/deribit.py +3437 -0
  221. ccxt/async_support/digifinex.py +3960 -0
  222. ccxt/async_support/eterex.py +286 -0
  223. ccxt/async_support/excoino.py +399 -0
  224. ccxt/async_support/exir.py +375 -0
  225. ccxt/async_support/exmo.py +2462 -0
  226. ccxt/async_support/exnovin.py +360 -0
  227. ccxt/async_support/farhadexchange.py +266 -0
  228. ccxt/async_support/fmfwio.py +34 -0
  229. ccxt/async_support/gate.py +6976 -0
  230. ccxt/async_support/gateio.py +16 -0
  231. ccxt/async_support/gemini.py +1825 -0
  232. ccxt/async_support/hashkey.py +4150 -0
  233. ccxt/async_support/hitbtc.py +3423 -0
  234. ccxt/async_support/hitbtc3.py +16 -0
  235. ccxt/async_support/hitobit.py +391 -0
  236. ccxt/async_support/hollaex.py +1813 -0
  237. ccxt/async_support/htx.py +8506 -0
  238. ccxt/async_support/huobi.py +16 -0
  239. ccxt/async_support/huobijp.py +1801 -0
  240. ccxt/async_support/hyperliquid.py +2431 -0
  241. ccxt/async_support/idex.py +1766 -0
  242. ccxt/async_support/independentreserve.py +784 -0
  243. ccxt/async_support/indodax.py +1247 -0
  244. ccxt/async_support/jibitex.py +395 -0
  245. ccxt/async_support/kraken.py +2894 -0
  246. ccxt/async_support/krakenfutures.py +2601 -0
  247. ccxt/async_support/kucoin.py +4602 -0
  248. ccxt/async_support/kucoinfutures.py +2698 -0
  249. ccxt/async_support/kuna.py +1841 -0
  250. ccxt/async_support/latoken.py +1664 -0
  251. ccxt/async_support/lbank.py +2683 -0
  252. ccxt/async_support/luno.py +1067 -0
  253. ccxt/async_support/lykke.py +1270 -0
  254. ccxt/async_support/mercado.py +842 -0
  255. ccxt/async_support/mexc.py +5369 -0
  256. ccxt/async_support/ndax.py +2354 -0
  257. ccxt/async_support/nobitex.py +419 -0
  258. ccxt/async_support/novadax.py +1484 -0
  259. ccxt/async_support/oceanex.py +903 -0
  260. ccxt/async_support/okcoin.py +2936 -0
  261. ccxt/async_support/okexchange.py +349 -0
  262. ccxt/async_support/okx.py +7827 -0
  263. ccxt/async_support/ompfinex.py +472 -0
  264. ccxt/async_support/onetrading.py +1911 -0
  265. ccxt/async_support/oxfun.py +2773 -0
  266. ccxt/async_support/p2b.py +1194 -0
  267. ccxt/async_support/paradex.py +2015 -0
  268. ccxt/async_support/paymium.py +564 -0
  269. ccxt/async_support/phemex.py +4473 -0
  270. ccxt/async_support/poloniex.py +2232 -0
  271. ccxt/async_support/poloniexfutures.py +1717 -0
  272. ccxt/async_support/probit.py +1734 -0
  273. ccxt/async_support/ramzinex.py +476 -0
  274. ccxt/async_support/sarmayex.py +357 -0
  275. ccxt/async_support/sarrafex.py +478 -0
  276. ccxt/async_support/tabdeal.py +364 -0
  277. ccxt/async_support/tetherland.py +349 -0
  278. ccxt/async_support/timex.py +1593 -0
  279. ccxt/async_support/tokocrypto.py +2405 -0
  280. ccxt/async_support/tradeogre.py +608 -0
  281. ccxt/async_support/twox.py +326 -0
  282. ccxt/async_support/ubitex.py +409 -0
  283. ccxt/async_support/upbit.py +1833 -0
  284. ccxt/async_support/vertex.py +2922 -0
  285. ccxt/async_support/wallex.py +445 -0
  286. ccxt/async_support/wavesexchange.py +2473 -0
  287. ccxt/async_support/wazirx.py +1224 -0
  288. ccxt/async_support/whitebit.py +2469 -0
  289. ccxt/async_support/woo.py +3114 -0
  290. ccxt/async_support/woofipro.py +2533 -0
  291. ccxt/async_support/xt.py +4454 -0
  292. ccxt/async_support/yobit.py +1283 -0
  293. ccxt/async_support/zaif.py +725 -0
  294. ccxt/async_support/zonda.py +1828 -0
  295. ccxt/base/__init__.py +27 -0
  296. ccxt/base/decimal_to_precision.py +174 -0
  297. ccxt/base/errors.py +242 -0
  298. ccxt/base/exchange.py +5941 -0
  299. ccxt/base/precise.py +287 -0
  300. ccxt/base/types.py +502 -0
  301. ccxt/bequant.py +33 -0
  302. ccxt/bigone.py +2112 -0
  303. ccxt/binance.py +12233 -0
  304. ccxt/binancecoinm.py +45 -0
  305. ccxt/binanceus.py +211 -0
  306. ccxt/binanceusdm.py +58 -0
  307. ccxt/bingx.py +4324 -0
  308. ccxt/bit2c.py +866 -0
  309. ccxt/bitbank.py +1001 -0
  310. ccxt/bitbay.py +17 -0
  311. ccxt/bitbns.py +1154 -0
  312. ccxt/bitcoincom.py +17 -0
  313. ccxt/bitfinex.py +1617 -0
  314. ccxt/bitfinex2.py +3552 -0
  315. ccxt/bitflyer.py +995 -0
  316. ccxt/bitget.py +8272 -0
  317. ccxt/bithumb.py +1061 -0
  318. ccxt/bitimen.py +401 -0
  319. ccxt/bitir.py +490 -0
  320. ccxt/bitmart.py +4415 -0
  321. ccxt/bitmex.py +2756 -0
  322. ccxt/bitopro.py +1630 -0
  323. ccxt/bitpanda.py +16 -0
  324. ccxt/bitpin.py +454 -0
  325. ccxt/bitrue.py +3026 -0
  326. ccxt/bitso.py +1670 -0
  327. ccxt/bitstamp.py +2203 -0
  328. ccxt/bitteam.py +2239 -0
  329. ccxt/bitvavo.py +1968 -0
  330. ccxt/bl3p.py +485 -0
  331. ccxt/blockchaincom.py +1104 -0
  332. ccxt/blofin.py +2066 -0
  333. ccxt/btcalpha.py +891 -0
  334. ccxt/btcbox.py +544 -0
  335. ccxt/btcmarkets.py +1221 -0
  336. ccxt/btcturk.py +911 -0
  337. ccxt/bybit.py +8158 -0
  338. ccxt/cex.py +1605 -0
  339. ccxt/coinbase.py +4474 -0
  340. ccxt/coinbaseadvanced.py +17 -0
  341. ccxt/coinbaseexchange.py +1734 -0
  342. ccxt/coinbaseinternational.py +1899 -0
  343. ccxt/coincatch.py +5069 -0
  344. ccxt/coincheck.py +815 -0
  345. ccxt/coinex.py +5525 -0
  346. ccxt/coinlist.py +2243 -0
  347. ccxt/coinmate.py +1067 -0
  348. ccxt/coinmetro.py +1797 -0
  349. ccxt/coinone.py +1127 -0
  350. ccxt/coinsph.py +1850 -0
  351. ccxt/coinspot.py +534 -0
  352. ccxt/cryptocom.py +2822 -0
  353. ccxt/currencycom.py +1950 -0
  354. ccxt/delta.py +3376 -0
  355. ccxt/deribit.py +3437 -0
  356. ccxt/digifinex.py +3959 -0
  357. ccxt/eterex.py +286 -0
  358. ccxt/excoino.py +399 -0
  359. ccxt/exir.py +375 -0
  360. ccxt/exmo.py +2462 -0
  361. ccxt/exnovin.py +360 -0
  362. ccxt/farhadexchange.py +266 -0
  363. ccxt/fmfwio.py +34 -0
  364. ccxt/gate.py +6975 -0
  365. ccxt/gateio.py +16 -0
  366. ccxt/gemini.py +1824 -0
  367. ccxt/hashkey.py +4150 -0
  368. ccxt/hitbtc.py +3423 -0
  369. ccxt/hitbtc3.py +16 -0
  370. ccxt/hitobit.py +391 -0
  371. ccxt/hollaex.py +1813 -0
  372. ccxt/htx.py +8505 -0
  373. ccxt/huobi.py +16 -0
  374. ccxt/huobijp.py +1801 -0
  375. ccxt/hyperliquid.py +2430 -0
  376. ccxt/idex.py +1766 -0
  377. ccxt/independentreserve.py +784 -0
  378. ccxt/indodax.py +1247 -0
  379. ccxt/jibitex.py +395 -0
  380. ccxt/kraken.py +2894 -0
  381. ccxt/krakenfutures.py +2601 -0
  382. ccxt/kucoin.py +4601 -0
  383. ccxt/kucoinfutures.py +2698 -0
  384. ccxt/kuna.py +1841 -0
  385. ccxt/latoken.py +1664 -0
  386. ccxt/lbank.py +2682 -0
  387. ccxt/luno.py +1067 -0
  388. ccxt/lykke.py +1270 -0
  389. ccxt/mercado.py +842 -0
  390. ccxt/mexc.py +5369 -0
  391. ccxt/ndax.py +2354 -0
  392. ccxt/nobitex.py +419 -0
  393. ccxt/novadax.py +1484 -0
  394. ccxt/oceanex.py +903 -0
  395. ccxt/okcoin.py +2936 -0
  396. ccxt/okexchange.py +349 -0
  397. ccxt/okx.py +7826 -0
  398. ccxt/ompfinex.py +472 -0
  399. ccxt/onetrading.py +1911 -0
  400. ccxt/oxfun.py +2772 -0
  401. ccxt/p2b.py +1194 -0
  402. ccxt/paradex.py +2015 -0
  403. ccxt/paymium.py +564 -0
  404. ccxt/phemex.py +4473 -0
  405. ccxt/poloniex.py +2232 -0
  406. ccxt/poloniexfutures.py +1717 -0
  407. ccxt/pro/__init__.py +149 -0
  408. ccxt/pro/alpaca.py +685 -0
  409. ccxt/pro/ascendex.py +916 -0
  410. ccxt/pro/bequant.py +38 -0
  411. ccxt/pro/binance.py +3488 -0
  412. ccxt/pro/binancecoinm.py +28 -0
  413. ccxt/pro/binanceus.py +48 -0
  414. ccxt/pro/binanceusdm.py +31 -0
  415. ccxt/pro/bingx.py +1264 -0
  416. ccxt/pro/bitcoincom.py +34 -0
  417. ccxt/pro/bitfinex.py +621 -0
  418. ccxt/pro/bitfinex2.py +1083 -0
  419. ccxt/pro/bitget.py +1692 -0
  420. ccxt/pro/bithumb.py +368 -0
  421. ccxt/pro/bitmart.py +1449 -0
  422. ccxt/pro/bitmex.py +1656 -0
  423. ccxt/pro/bitopro.py +445 -0
  424. ccxt/pro/bitpanda.py +15 -0
  425. ccxt/pro/bitrue.py +447 -0
  426. ccxt/pro/bitstamp.py +522 -0
  427. ccxt/pro/bitvavo.py +1270 -0
  428. ccxt/pro/blockchaincom.py +738 -0
  429. ccxt/pro/blofin.py +692 -0
  430. ccxt/pro/bybit.py +2000 -0
  431. ccxt/pro/cex.py +1440 -0
  432. ccxt/pro/coinbase.py +678 -0
  433. ccxt/pro/coinbaseadvanced.py +16 -0
  434. ccxt/pro/coinbaseexchange.py +895 -0
  435. ccxt/pro/coinbaseinternational.py +620 -0
  436. ccxt/pro/coincatch.py +1464 -0
  437. ccxt/pro/coincheck.py +199 -0
  438. ccxt/pro/coinex.py +1061 -0
  439. ccxt/pro/coinone.py +395 -0
  440. ccxt/pro/cryptocom.py +947 -0
  441. ccxt/pro/currencycom.py +536 -0
  442. ccxt/pro/deribit.py +892 -0
  443. ccxt/pro/exmo.py +629 -0
  444. ccxt/pro/gate.py +1416 -0
  445. ccxt/pro/gateio.py +15 -0
  446. ccxt/pro/gemini.py +865 -0
  447. ccxt/pro/hashkey.py +802 -0
  448. ccxt/pro/hitbtc.py +1216 -0
  449. ccxt/pro/hollaex.py +563 -0
  450. ccxt/pro/htx.py +2215 -0
  451. ccxt/pro/huobi.py +15 -0
  452. ccxt/pro/huobijp.py +570 -0
  453. ccxt/pro/hyperliquid.py +525 -0
  454. ccxt/pro/idex.py +672 -0
  455. ccxt/pro/independentreserve.py +270 -0
  456. ccxt/pro/kraken.py +1356 -0
  457. ccxt/pro/krakenfutures.py +1492 -0
  458. ccxt/pro/kucoin.py +1133 -0
  459. ccxt/pro/kucoinfutures.py +1081 -0
  460. ccxt/pro/lbank.py +843 -0
  461. ccxt/pro/luno.py +303 -0
  462. ccxt/pro/mexc.py +1122 -0
  463. ccxt/pro/ndax.py +506 -0
  464. ccxt/pro/okcoin.py +698 -0
  465. ccxt/pro/okx.py +1851 -0
  466. ccxt/pro/onetrading.py +1275 -0
  467. ccxt/pro/oxfun.py +950 -0
  468. ccxt/pro/p2b.py +419 -0
  469. ccxt/pro/paradex.py +352 -0
  470. ccxt/pro/phemex.py +1441 -0
  471. ccxt/pro/poloniex.py +1166 -0
  472. ccxt/pro/poloniexfutures.py +990 -0
  473. ccxt/pro/probit.py +551 -0
  474. ccxt/pro/upbit.py +520 -0
  475. ccxt/pro/vertex.py +943 -0
  476. ccxt/pro/wazirx.py +749 -0
  477. ccxt/pro/whitebit.py +864 -0
  478. ccxt/pro/woo.py +1078 -0
  479. ccxt/pro/woofipro.py +1183 -0
  480. ccxt/pro/xt.py +1067 -0
  481. ccxt/probit.py +1734 -0
  482. ccxt/ramzinex.py +476 -0
  483. ccxt/sarmayex.py +357 -0
  484. ccxt/sarrafex.py +478 -0
  485. ccxt/static_dependencies/__init__.py +1 -0
  486. ccxt/static_dependencies/ecdsa/__init__.py +14 -0
  487. ccxt/static_dependencies/ecdsa/_version.py +520 -0
  488. ccxt/static_dependencies/ecdsa/curves.py +56 -0
  489. ccxt/static_dependencies/ecdsa/der.py +221 -0
  490. ccxt/static_dependencies/ecdsa/ecdsa.py +310 -0
  491. ccxt/static_dependencies/ecdsa/ellipticcurve.py +197 -0
  492. ccxt/static_dependencies/ecdsa/keys.py +332 -0
  493. ccxt/static_dependencies/ecdsa/numbertheory.py +531 -0
  494. ccxt/static_dependencies/ecdsa/rfc6979.py +100 -0
  495. ccxt/static_dependencies/ecdsa/util.py +266 -0
  496. ccxt/static_dependencies/ethereum/__init__.py +7 -0
  497. ccxt/static_dependencies/ethereum/abi/__init__.py +16 -0
  498. ccxt/static_dependencies/ethereum/abi/abi.py +19 -0
  499. ccxt/static_dependencies/ethereum/abi/base.py +152 -0
  500. ccxt/static_dependencies/ethereum/abi/codec.py +217 -0
  501. ccxt/static_dependencies/ethereum/abi/constants.py +3 -0
  502. ccxt/static_dependencies/ethereum/abi/decoding.py +565 -0
  503. ccxt/static_dependencies/ethereum/abi/encoding.py +720 -0
  504. ccxt/static_dependencies/ethereum/abi/exceptions.py +139 -0
  505. ccxt/static_dependencies/ethereum/abi/grammar.py +443 -0
  506. ccxt/static_dependencies/ethereum/abi/packed.py +13 -0
  507. ccxt/static_dependencies/ethereum/abi/py.typed +0 -0
  508. ccxt/static_dependencies/ethereum/abi/registry.py +643 -0
  509. ccxt/static_dependencies/ethereum/abi/tools/__init__.py +3 -0
  510. ccxt/static_dependencies/ethereum/abi/tools/_strategies.py +230 -0
  511. ccxt/static_dependencies/ethereum/abi/utils/__init__.py +0 -0
  512. ccxt/static_dependencies/ethereum/abi/utils/numeric.py +83 -0
  513. ccxt/static_dependencies/ethereum/abi/utils/padding.py +27 -0
  514. ccxt/static_dependencies/ethereum/abi/utils/string.py +19 -0
  515. ccxt/static_dependencies/ethereum/account/__init__.py +3 -0
  516. ccxt/static_dependencies/ethereum/account/encode_typed_data/__init__.py +4 -0
  517. ccxt/static_dependencies/ethereum/account/encode_typed_data/encoding_and_hashing.py +239 -0
  518. ccxt/static_dependencies/ethereum/account/encode_typed_data/helpers.py +40 -0
  519. ccxt/static_dependencies/ethereum/account/messages.py +263 -0
  520. ccxt/static_dependencies/ethereum/account/py.typed +0 -0
  521. ccxt/static_dependencies/ethereum/hexbytes/__init__.py +5 -0
  522. ccxt/static_dependencies/ethereum/hexbytes/_utils.py +54 -0
  523. ccxt/static_dependencies/ethereum/hexbytes/main.py +65 -0
  524. ccxt/static_dependencies/ethereum/hexbytes/py.typed +0 -0
  525. ccxt/static_dependencies/ethereum/typing/__init__.py +63 -0
  526. ccxt/static_dependencies/ethereum/typing/abi.py +6 -0
  527. ccxt/static_dependencies/ethereum/typing/bls.py +7 -0
  528. ccxt/static_dependencies/ethereum/typing/discovery.py +5 -0
  529. ccxt/static_dependencies/ethereum/typing/encoding.py +7 -0
  530. ccxt/static_dependencies/ethereum/typing/enums.py +17 -0
  531. ccxt/static_dependencies/ethereum/typing/ethpm.py +9 -0
  532. ccxt/static_dependencies/ethereum/typing/evm.py +20 -0
  533. ccxt/static_dependencies/ethereum/typing/networks.py +1122 -0
  534. ccxt/static_dependencies/ethereum/typing/py.typed +0 -0
  535. ccxt/static_dependencies/ethereum/utils/__init__.py +115 -0
  536. ccxt/static_dependencies/ethereum/utils/abi.py +72 -0
  537. ccxt/static_dependencies/ethereum/utils/address.py +171 -0
  538. ccxt/static_dependencies/ethereum/utils/applicators.py +151 -0
  539. ccxt/static_dependencies/ethereum/utils/conversions.py +190 -0
  540. ccxt/static_dependencies/ethereum/utils/currency.py +107 -0
  541. ccxt/static_dependencies/ethereum/utils/curried/__init__.py +269 -0
  542. ccxt/static_dependencies/ethereum/utils/debug.py +20 -0
  543. ccxt/static_dependencies/ethereum/utils/decorators.py +132 -0
  544. ccxt/static_dependencies/ethereum/utils/encoding.py +6 -0
  545. ccxt/static_dependencies/ethereum/utils/exceptions.py +4 -0
  546. ccxt/static_dependencies/ethereum/utils/functional.py +75 -0
  547. ccxt/static_dependencies/ethereum/utils/hexadecimal.py +74 -0
  548. ccxt/static_dependencies/ethereum/utils/humanize.py +188 -0
  549. ccxt/static_dependencies/ethereum/utils/logging.py +159 -0
  550. ccxt/static_dependencies/ethereum/utils/module_loading.py +31 -0
  551. ccxt/static_dependencies/ethereum/utils/numeric.py +43 -0
  552. ccxt/static_dependencies/ethereum/utils/py.typed +0 -0
  553. ccxt/static_dependencies/ethereum/utils/toolz.py +76 -0
  554. ccxt/static_dependencies/ethereum/utils/types.py +54 -0
  555. ccxt/static_dependencies/ethereum/utils/typing/__init__.py +18 -0
  556. ccxt/static_dependencies/ethereum/utils/typing/misc.py +14 -0
  557. ccxt/static_dependencies/ethereum/utils/units.py +31 -0
  558. ccxt/static_dependencies/keccak/__init__.py +3 -0
  559. ccxt/static_dependencies/keccak/keccak.py +197 -0
  560. ccxt/static_dependencies/lark/__init__.py +38 -0
  561. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  562. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  563. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  564. ccxt/static_dependencies/lark/common.py +86 -0
  565. ccxt/static_dependencies/lark/exceptions.py +292 -0
  566. ccxt/static_dependencies/lark/grammar.py +130 -0
  567. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  568. ccxt/static_dependencies/lark/indenter.py +143 -0
  569. ccxt/static_dependencies/lark/lark.py +658 -0
  570. ccxt/static_dependencies/lark/lexer.py +678 -0
  571. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  572. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  573. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  574. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  575. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  576. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  577. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  578. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  579. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  580. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  581. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  582. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  583. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  584. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  585. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  586. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  587. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  588. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  589. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  590. ccxt/static_dependencies/lark/tree.py +267 -0
  591. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  592. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  593. ccxt/static_dependencies/lark/utils.py +343 -0
  594. ccxt/static_dependencies/lark/visitors.py +596 -0
  595. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  596. ccxt/static_dependencies/marshmallow/base.py +65 -0
  597. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  598. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  599. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  600. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  601. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  602. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  603. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  604. ccxt/static_dependencies/marshmallow/types.py +12 -0
  605. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  606. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  607. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  608. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  609. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  610. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  611. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  612. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  613. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  614. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  615. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  616. ccxt/static_dependencies/msgpack/__init__.py +55 -0
  617. ccxt/static_dependencies/msgpack/exceptions.py +48 -0
  618. ccxt/static_dependencies/msgpack/ext.py +168 -0
  619. ccxt/static_dependencies/msgpack/fallback.py +951 -0
  620. ccxt/static_dependencies/parsimonious/__init__.py +10 -0
  621. ccxt/static_dependencies/parsimonious/exceptions.py +105 -0
  622. ccxt/static_dependencies/parsimonious/expressions.py +479 -0
  623. ccxt/static_dependencies/parsimonious/grammar.py +487 -0
  624. ccxt/static_dependencies/parsimonious/nodes.py +325 -0
  625. ccxt/static_dependencies/parsimonious/utils.py +40 -0
  626. ccxt/static_dependencies/starknet/__init__.py +0 -0
  627. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  628. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  629. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  630. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  631. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  632. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  633. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  634. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  635. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  636. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  637. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  638. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  639. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  640. ccxt/static_dependencies/starknet/common.py +15 -0
  641. ccxt/static_dependencies/starknet/constants.py +39 -0
  642. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  643. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  644. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  645. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  646. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  647. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  648. ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  649. ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  650. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  651. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  652. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  653. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  654. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  655. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  656. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  657. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  658. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  659. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  660. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  661. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  662. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  663. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  664. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  665. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  666. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  667. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  668. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  669. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  670. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  671. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  672. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  673. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  674. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  675. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  676. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  677. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  678. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  679. ccxt/static_dependencies/starkware/__init__.py +0 -0
  680. ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  681. ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  682. ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  683. ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  684. ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  685. ccxt/static_dependencies/sympy/__init__.py +0 -0
  686. ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  687. ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  688. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  689. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  690. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  691. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  692. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  693. ccxt/static_dependencies/toolz/__init__.py +26 -0
  694. ccxt/static_dependencies/toolz/_signatures.py +784 -0
  695. ccxt/static_dependencies/toolz/_version.py +520 -0
  696. ccxt/static_dependencies/toolz/compatibility.py +30 -0
  697. ccxt/static_dependencies/toolz/curried/__init__.py +101 -0
  698. ccxt/static_dependencies/toolz/curried/exceptions.py +22 -0
  699. ccxt/static_dependencies/toolz/curried/operator.py +22 -0
  700. ccxt/static_dependencies/toolz/dicttoolz.py +339 -0
  701. ccxt/static_dependencies/toolz/functoolz.py +1049 -0
  702. ccxt/static_dependencies/toolz/itertoolz.py +1057 -0
  703. ccxt/static_dependencies/toolz/recipes.py +46 -0
  704. ccxt/static_dependencies/toolz/utils.py +9 -0
  705. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  706. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  707. ccxt/tabdeal.py +364 -0
  708. ccxt/test/__init__.py +3 -0
  709. ccxt/test/base/__init__.py +29 -0
  710. ccxt/test/base/test_account.py +26 -0
  711. ccxt/test/base/test_balance.py +56 -0
  712. ccxt/test/base/test_borrow_interest.py +35 -0
  713. ccxt/test/base/test_borrow_rate.py +32 -0
  714. ccxt/test/base/test_calculate_fee.py +51 -0
  715. ccxt/test/base/test_crypto.py +127 -0
  716. ccxt/test/base/test_currency.py +76 -0
  717. ccxt/test/base/test_datetime.py +109 -0
  718. ccxt/test/base/test_decimal_to_precision.py +392 -0
  719. ccxt/test/base/test_deep_extend.py +68 -0
  720. ccxt/test/base/test_deposit_withdrawal.py +50 -0
  721. ccxt/test/base/test_exchange_datetime_functions.py +76 -0
  722. ccxt/test/base/test_funding_rate_history.py +29 -0
  723. ccxt/test/base/test_last_price.py +31 -0
  724. ccxt/test/base/test_ledger_entry.py +45 -0
  725. ccxt/test/base/test_ledger_item.py +48 -0
  726. ccxt/test/base/test_leverage_tier.py +33 -0
  727. ccxt/test/base/test_liquidation.py +50 -0
  728. ccxt/test/base/test_margin_mode.py +24 -0
  729. ccxt/test/base/test_margin_modification.py +35 -0
  730. ccxt/test/base/test_market.py +193 -0
  731. ccxt/test/base/test_number.py +411 -0
  732. ccxt/test/base/test_ohlcv.py +33 -0
  733. ccxt/test/base/test_open_interest.py +32 -0
  734. ccxt/test/base/test_order.py +64 -0
  735. ccxt/test/base/test_order_book.py +69 -0
  736. ccxt/test/base/test_position.py +60 -0
  737. ccxt/test/base/test_shared_methods.py +353 -0
  738. ccxt/test/base/test_status.py +24 -0
  739. ccxt/test/base/test_throttle.py +126 -0
  740. ccxt/test/base/test_ticker.py +92 -0
  741. ccxt/test/base/test_trade.py +47 -0
  742. ccxt/test/base/test_trading_fee.py +26 -0
  743. ccxt/test/base/test_transaction.py +39 -0
  744. ccxt/test/test_async.py +1649 -0
  745. ccxt/test/test_sync.py +1648 -0
  746. ccxt/test/tests_async.py +1558 -0
  747. ccxt/test/tests_helpers.py +287 -0
  748. ccxt/test/tests_init.py +39 -0
  749. ccxt/test/tests_sync.py +1555 -0
  750. ccxt/tetherland.py +349 -0
  751. ccxt/timex.py +1593 -0
  752. ccxt/tokocrypto.py +2405 -0
  753. ccxt/tradeogre.py +608 -0
  754. ccxt/twox.py +326 -0
  755. ccxt/ubitex.py +409 -0
  756. ccxt/upbit.py +1833 -0
  757. ccxt/vertex.py +2922 -0
  758. ccxt/wallex.py +445 -0
  759. ccxt/wavesexchange.py +2472 -0
  760. ccxt/wazirx.py +1224 -0
  761. ccxt/whitebit.py +2469 -0
  762. ccxt/woo.py +3114 -0
  763. ccxt/woofipro.py +2533 -0
  764. ccxt/xt.py +4453 -0
  765. ccxt/yobit.py +1283 -0
  766. ccxt/zaif.py +725 -0
  767. ccxt/zonda.py +1828 -0
  768. ccxt_ir-4.3.46.0.1.dist-info/LICENSE.txt +21 -0
  769. ccxt_ir-4.3.46.0.1.dist-info/METADATA +655 -0
  770. ccxt_ir-4.3.46.0.1.dist-info/RECORD +772 -0
  771. ccxt_ir-4.3.46.0.1.dist-info/WHEEL +6 -0
  772. ccxt_ir-4.3.46.0.1.dist-info/top_level.txt +1 -0
ccxt/pro/bybit.py ADDED
@@ -0,0 +1,2000 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+
6
+ import ccxt.async_support
7
+ from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp
8
+ import asyncio
9
+ import hashlib
10
+ from ccxt.base.types import Balances, Int, Liquidation, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade
11
+ from ccxt.async_support.base.ws.client import Client
12
+ from typing import List
13
+ from ccxt.base.errors import ExchangeError
14
+ from ccxt.base.errors import AuthenticationError
15
+ from ccxt.base.errors import ArgumentsRequired
16
+ from ccxt.base.errors import BadRequest
17
+
18
+
19
+ class bybit(ccxt.async_support.bybit):
20
+
21
+ def describe(self):
22
+ return self.deep_extend(super(bybit, self).describe(), {
23
+ 'has': {
24
+ 'ws': True,
25
+ 'createOrderWs': True,
26
+ 'editOrderWs': True,
27
+ 'fetchOpenOrdersWs': False,
28
+ 'fetchOrderWs': False,
29
+ 'cancelOrderWs': True,
30
+ 'cancelOrdersWs': False,
31
+ 'cancelAllOrdersWs': False,
32
+ 'fetchTradesWs': False,
33
+ 'fetchBalanceWs': False,
34
+ 'watchBalance': True,
35
+ 'watchLiquidations': True,
36
+ 'watchLiquidationsForSymbols': False,
37
+ 'watchMyLiquidations': False,
38
+ 'watchMyLiquidationsForSymbols': False,
39
+ 'watchMyTrades': True,
40
+ 'watchOHLCV': True,
41
+ 'watchOHLCVForSymbols': False,
42
+ 'watchOrderBook': True,
43
+ 'watchOrderBookForSymbols': True,
44
+ 'watchOrders': True,
45
+ 'watchTicker': True,
46
+ 'watchTickers': True,
47
+ 'watchTrades': True,
48
+ 'watchPositions': True,
49
+ 'watchTradesForSymbols': True,
50
+ },
51
+ 'urls': {
52
+ 'api': {
53
+ 'ws': {
54
+ 'public': {
55
+ 'spot': 'wss://stream.{hostname}/v5/public/spot',
56
+ 'inverse': 'wss://stream.{hostname}/v5/public/inverse',
57
+ 'option': 'wss://stream.{hostname}/v5/public/option',
58
+ 'linear': 'wss://stream.{hostname}/v5/public/linear',
59
+ },
60
+ 'private': {
61
+ 'spot': {
62
+ 'unified': 'wss://stream.{hostname}/v5/private',
63
+ 'nonUnified': 'wss://stream.{hostname}/spot/private/v3',
64
+ },
65
+ 'contract': 'wss://stream.{hostname}/v5/private',
66
+ 'usdc': 'wss://stream.{hostname}/trade/option/usdc/private/v1',
67
+ 'trade': 'wss://stream.bybit.com/v5/trade',
68
+ },
69
+ },
70
+ },
71
+ 'test': {
72
+ 'ws': {
73
+ 'public': {
74
+ 'spot': 'wss://stream-testnet.{hostname}/v5/public/spot',
75
+ 'inverse': 'wss://stream-testnet.{hostname}/v5/public/inverse',
76
+ 'linear': 'wss://stream-testnet.{hostname}/v5/public/linear',
77
+ 'option': 'wss://stream-testnet.{hostname}/v5/public/option',
78
+ },
79
+ 'private': {
80
+ 'spot': {
81
+ 'unified': 'wss://stream-testnet.{hostname}/v5/private',
82
+ 'nonUnified': 'wss://stream-testnet.{hostname}/spot/private/v3',
83
+ },
84
+ 'contract': 'wss://stream-testnet.{hostname}/v5/private',
85
+ 'usdc': 'wss://stream-testnet.{hostname}/trade/option/usdc/private/v1',
86
+ 'trade': 'wss://stream-testnet.bybit.com/v5/trade',
87
+ },
88
+ },
89
+ },
90
+ },
91
+ 'options': {
92
+ 'watchTicker': {
93
+ 'name': 'tickers', # 'tickers' for 24hr statistical ticker or 'tickers_lt' for leverage token ticker
94
+ },
95
+ 'watchPositions': {
96
+ 'fetchPositionsSnapshot': True, # or False
97
+ 'awaitPositionsSnapshot': True, # whether to wait for the positions snapshot before providing updates
98
+ },
99
+ 'spot': {
100
+ 'timeframes': {
101
+ '1m': '1m',
102
+ '3m': '3m',
103
+ '5m': '5m',
104
+ '15m': '15m',
105
+ '30m': '30m',
106
+ '1h': '1h',
107
+ '2h': '2h',
108
+ '4h': '4h',
109
+ '6h': '6h',
110
+ '12h': '12h',
111
+ '1d': '1d',
112
+ '1w': '1w',
113
+ '1M': '1M',
114
+ },
115
+ },
116
+ 'contract': {
117
+ 'timeframes': {
118
+ '1m': '1',
119
+ '3m': '3',
120
+ '5m': '5',
121
+ '15m': '15',
122
+ '30m': '30',
123
+ '1h': '60',
124
+ '2h': '120',
125
+ '4h': '240',
126
+ '6h': '360',
127
+ '12h': '720',
128
+ '1d': 'D',
129
+ '1w': 'W',
130
+ '1M': 'M',
131
+ },
132
+ },
133
+ },
134
+ 'streaming': {
135
+ 'ping': self.ping,
136
+ 'keepAlive': 18000,
137
+ },
138
+ })
139
+
140
+ def request_id(self):
141
+ requestId = self.sum(self.safe_integer(self.options, 'requestId', 0), 1)
142
+ self.options['requestId'] = requestId
143
+ return requestId
144
+
145
+ def get_url_by_market_type(self, symbol: Str = None, isPrivate=False, method: Str = None, params={}):
146
+ accessibility = 'private' if isPrivate else 'public'
147
+ isUsdcSettled = None
148
+ isSpot = None
149
+ type = None
150
+ market = None
151
+ url = self.urls['api']['ws']
152
+ if symbol is not None:
153
+ market = self.market(symbol)
154
+ isUsdcSettled = market['settle'] == 'USDC'
155
+ type = market['type']
156
+ else:
157
+ type, params = self.handle_market_type_and_params(method, None, params)
158
+ defaultSettle = self.safe_string(self.options, 'defaultSettle')
159
+ defaultSettle = self.safe_string_2(params, 'settle', 'defaultSettle', defaultSettle)
160
+ isUsdcSettled = (defaultSettle == 'USDC')
161
+ isSpot = (type == 'spot')
162
+ if isPrivate:
163
+ url = url[accessibility]['usdc'] if (isUsdcSettled) else url[accessibility]['contract']
164
+ else:
165
+ if isSpot:
166
+ url = url[accessibility]['spot']
167
+ elif type == 'swap':
168
+ subType = None
169
+ subType, params = self.handle_sub_type_and_params(method, market, params, 'linear')
170
+ url = url[accessibility][subType]
171
+ else:
172
+ # option
173
+ url = url[accessibility]['option']
174
+ url = self.implode_hostname(url)
175
+ return url
176
+
177
+ def clean_params(self, params):
178
+ params = self.omit(params, ['type', 'subType', 'settle', 'defaultSettle', 'unifiedMargin'])
179
+ return params
180
+
181
+ async def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
182
+ """
183
+ 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
186
+ :param str symbol: unified symbol of the market to create an order in
187
+ :param str type: 'market' or 'limit'
188
+ :param str side: 'buy' or 'sell'
189
+ :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
191
+ :param dict [params]: extra parameters specific to the exchange API endpoint
192
+ :param str [params.timeInForce]: "GTC", "IOC", "FOK"
193
+ :param bool [params.postOnly]: True or False whether the order is post-only
194
+ :param bool [params.reduceOnly]: True or False whether the order is reduce-only
195
+ :param str [params.positionIdx]: *contracts only* 0 for one-way mode, 1 buy side of hedged mode, 2 sell side of hedged mode
196
+ :param boolean [params.isLeverage]: *unified spot only* False then spot trading True then margin trading
197
+ :param str [params.tpslMode]: *contract only* 'full' or 'partial'
198
+ :param str [params.mmp]: *option only* market maker protection
199
+ :param str [params.triggerDirection]: *contract only* the direction for trigger orders, 'above' or 'below'
200
+ :param float [params.triggerPrice]: The price at which a trigger order is triggered at
201
+ :param float [params.stopLossPrice]: The price at which a stop loss order is triggered at
202
+ :param float [params.takeProfitPrice]: The price at which a take profit order is triggered at
203
+ :param dict [params.takeProfit]: *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered
204
+ :param float [params.takeProfit.triggerPrice]: take profit trigger price
205
+ :param dict [params.stopLoss]: *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered
206
+ :param float [params.stopLoss.triggerPrice]: stop loss trigger price
207
+ :param str [params.trailingAmount]: the quote amount to trail away from the current market price
208
+ :param str [params.trailingTriggerPrice]: the price to trigger a trailing order, default uses the price argument
209
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
210
+ """
211
+ await self.load_markets()
212
+ orderRequest = self.create_order_request(symbol, type, side, amount, price, params, True)
213
+ url = self.urls['api']['ws']['private']['trade']
214
+ await self.authenticate(url)
215
+ requestId = str(self.request_id())
216
+ request: dict = {
217
+ 'op': 'order.create',
218
+ 'reqId': requestId,
219
+ 'args': [
220
+ orderRequest,
221
+ ],
222
+ 'header': {
223
+ 'X-BAPI-TIMESTAMP': str(self.milliseconds()),
224
+ 'X-BAPI-RECV-WINDOW': str(self.options['recvWindow']),
225
+ },
226
+ }
227
+ return await self.watch(url, requestId, request, requestId, True)
228
+
229
+ async def edit_order_ws(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
230
+ """
231
+ 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
234
+ :param str id: cancel order id
235
+ :param str symbol: unified symbol of the market to create an order in
236
+ :param str type: 'market' or 'limit'
237
+ :param str side: 'buy' or 'sell'
238
+ :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
240
+ :param dict [params]: extra parameters specific to the exchange API endpoint
241
+ :param float [params.triggerPrice]: The price that a trigger order is triggered at
242
+ :param float [params.stopLossPrice]: The price that a stop loss order is triggered at
243
+ :param float [params.takeProfitPrice]: The price that a take profit order is triggered at
244
+ :param dict [params.takeProfit]: *takeProfit object in params* containing the triggerPrice that the attached take profit order will be triggered
245
+ :param float [params.takeProfit.triggerPrice]: take profit trigger price
246
+ :param dict [params.stopLoss]: *stopLoss object in params* containing the triggerPrice that the attached stop loss order will be triggered
247
+ :param float [params.stopLoss.triggerPrice]: stop loss trigger price
248
+ :param str [params.triggerBy]: 'IndexPrice', 'MarkPrice' or 'LastPrice', default is 'LastPrice', required if no initial value for triggerPrice
249
+ :param str [params.slTriggerBy]: 'IndexPrice', 'MarkPrice' or 'LastPrice', default is 'LastPrice', required if no initial value for stopLoss
250
+ :param str [params.tpTriggerby]: 'IndexPrice', 'MarkPrice' or 'LastPrice', default is 'LastPrice', required if no initial value for takeProfit
251
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
252
+ """
253
+ await self.load_markets()
254
+ orderRequest = self.edit_order_request(id, symbol, type, side, amount, price, params)
255
+ url = self.urls['api']['ws']['private']['trade']
256
+ await self.authenticate(url)
257
+ requestId = str(self.request_id())
258
+ request: dict = {
259
+ 'op': 'order.amend',
260
+ 'reqId': requestId,
261
+ 'args': [
262
+ orderRequest,
263
+ ],
264
+ 'header': {
265
+ 'X-BAPI-TIMESTAMP': str(self.milliseconds()),
266
+ 'X-BAPI-RECV-WINDOW': str(self.options['recvWindow']),
267
+ },
268
+ }
269
+ return await self.watch(url, requestId, request, requestId, True)
270
+
271
+ async def cancel_order_ws(self, id: str, symbol: Str = None, params={}):
272
+ """
273
+ 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
276
+ :param str id: order id
277
+ :param str symbol: unified symbol of the market the order was made in
278
+ :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
280
+ :param str [params.orderFilter]: *spot only* 'Order' or 'StopOrder' or 'tpslOrder'
281
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
282
+ """
283
+ await self.load_markets()
284
+ orderRequest = self.cancel_order_request(id, symbol, params)
285
+ url = self.urls['api']['ws']['private']['trade']
286
+ await self.authenticate(url)
287
+ requestId = str(self.request_id())
288
+ if 'orderFilter' in orderRequest:
289
+ del orderRequest['orderFilter']
290
+ request: dict = {
291
+ 'op': 'order.cancel',
292
+ 'reqId': requestId,
293
+ 'args': [
294
+ orderRequest,
295
+ ],
296
+ 'header': {
297
+ 'X-BAPI-TIMESTAMP': str(self.milliseconds()),
298
+ 'X-BAPI-RECV-WINDOW': str(self.options['recvWindow']),
299
+ },
300
+ }
301
+ return await self.watch(url, requestId, request, requestId, True)
302
+
303
+ async def watch_ticker(self, symbol: str, params={}) -> Ticker:
304
+ """
305
+ 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
308
+ :param str symbol: unified symbol of the market to fetch the ticker for
309
+ :param dict [params]: extra parameters specific to the exchange API endpoint
310
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
311
+ """
312
+ await self.load_markets()
313
+ market = self.market(symbol)
314
+ symbol = market['symbol']
315
+ messageHash = 'ticker:' + symbol
316
+ url = self.get_url_by_market_type(symbol, False, 'watchTicker', params)
317
+ params = self.clean_params(params)
318
+ options = self.safe_value(self.options, 'watchTicker', {})
319
+ topic = self.safe_string(options, 'name', 'tickers')
320
+ if not market['spot'] and topic != 'tickers':
321
+ raise BadRequest(self.id + ' watchTicker() only supports name tickers for contract markets')
322
+ topic += '.' + market['id']
323
+ topics = [topic]
324
+ return await self.watch_topics(url, [messageHash], topics, params)
325
+
326
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
327
+ """
328
+ 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
331
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
332
+ :param dict [params]: extra parameters specific to the exchange API endpoint
333
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
334
+ """
335
+ await self.load_markets()
336
+ symbols = self.market_symbols(symbols, None, False)
337
+ messageHashes = []
338
+ url = self.get_url_by_market_type(symbols[0], False, 'watchTickers', params)
339
+ params = self.clean_params(params)
340
+ options = self.safe_value(self.options, 'watchTickers', {})
341
+ topic = self.safe_string(options, 'name', 'tickers')
342
+ marketIds = self.market_ids(symbols)
343
+ topics = []
344
+ for i in range(0, len(marketIds)):
345
+ marketId = marketIds[i]
346
+ topics.append(topic + '.' + marketId)
347
+ messageHashes.append('ticker:' + symbols[i])
348
+ ticker = await self.watch_topics(url, messageHashes, topics, params)
349
+ if self.newUpdates:
350
+ result: dict = {}
351
+ result[ticker['symbol']] = ticker
352
+ return result
353
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
354
+
355
+ def handle_ticker(self, client: Client, message):
356
+ #
357
+ # linear
358
+ # {
359
+ # "topic": "tickers.BTCUSDT",
360
+ # "type": "snapshot",
361
+ # "data": {
362
+ # "symbol": "BTCUSDT",
363
+ # "tickDirection": "PlusTick",
364
+ # "price24hPcnt": "0.017103",
365
+ # "lastPrice": "17216.00",
366
+ # "prevPrice24h": "16926.50",
367
+ # "highPrice24h": "17281.50",
368
+ # "lowPrice24h": "16915.00",
369
+ # "prevPrice1h": "17238.00",
370
+ # "markPrice": "17217.33",
371
+ # "indexPrice": "17227.36",
372
+ # "openInterest": "68744.761",
373
+ # "openInterestValue": "1183601235.91",
374
+ # "turnover24h": "1570383121.943499",
375
+ # "volume24h": "91705.276",
376
+ # "nextFundingTime": "1673280000000",
377
+ # "fundingRate": "-0.000212",
378
+ # "bid1Price": "17215.50",
379
+ # "bid1Size": "84.489",
380
+ # "ask1Price": "17216.00",
381
+ # "ask1Size": "83.020"
382
+ # },
383
+ # "cs": 24987956059,
384
+ # "ts": 1673272861686
385
+ # }
386
+ #
387
+ # option
388
+ # {
389
+ # "id": "tickers.BTC-6JAN23-17500-C-2480334983-1672917511074",
390
+ # "topic": "tickers.BTC-6JAN23-17500-C",
391
+ # "ts": 1672917511074,
392
+ # "data": {
393
+ # "symbol": "BTC-6JAN23-17500-C",
394
+ # "bidPrice": "0",
395
+ # "bidSize": "0",
396
+ # "bidIv": "0",
397
+ # "askPrice": "10",
398
+ # "askSize": "5.1",
399
+ # "askIv": "0.514",
400
+ # "lastPrice": "10",
401
+ # "highPrice24h": "25",
402
+ # "lowPrice24h": "5",
403
+ # "markPrice": "7.86976724",
404
+ # "indexPrice": "16823.73",
405
+ # "markPriceIv": "0.4896",
406
+ # "underlyingPrice": "16815.1",
407
+ # "openInterest": "49.85",
408
+ # "turnover24h": "446802.8473",
409
+ # "volume24h": "26.55",
410
+ # "totalVolume": "86",
411
+ # "totalTurnover": "1437431",
412
+ # "delta": "0.047831",
413
+ # "gamma": "0.00021453",
414
+ # "vega": "0.81351067",
415
+ # "theta": "-19.9115368",
416
+ # "predictedDeliveryPrice": "0",
417
+ # "change24h": "-0.33333334"
418
+ # },
419
+ # "type": "snapshot"
420
+ # }
421
+ #
422
+ # spot
423
+ # {
424
+ # "topic": "tickers.BTCUSDT",
425
+ # "ts": 1673853746003,
426
+ # "type": "snapshot",
427
+ # "cs": 2588407389,
428
+ # "data": {
429
+ # "symbol": "BTCUSDT",
430
+ # "lastPrice": "21109.77",
431
+ # "highPrice24h": "21426.99",
432
+ # "lowPrice24h": "20575",
433
+ # "prevPrice24h": "20704.93",
434
+ # "volume24h": "6780.866843",
435
+ # "turnover24h": "141946527.22907118",
436
+ # "price24hPcnt": "0.0196",
437
+ # "usdIndexPrice": "21120.2400136"
438
+ # }
439
+ # }
440
+ #
441
+ # lt ticker
442
+ # {
443
+ # "topic": "tickers_lt.EOS3LUSDT",
444
+ # "ts": 1672325446847,
445
+ # "type": "snapshot",
446
+ # "data": {
447
+ # "symbol": "EOS3LUSDT",
448
+ # "lastPrice": "0.41477848043290448",
449
+ # "highPrice24h": "0.435285472510871305",
450
+ # "lowPrice24h": "0.394601507960931382",
451
+ # "prevPrice24h": "0.431502290172376349",
452
+ # "price24hPcnt": "-0.0388"
453
+ # }
454
+ # }
455
+ # swap delta
456
+ # {
457
+ # "topic":"tickers.AAVEUSDT",
458
+ # "type":"delta",
459
+ # "data":{
460
+ # "symbol":"AAVEUSDT",
461
+ # "bid1Price":"112.89",
462
+ # "bid1Size":"2.12",
463
+ # "ask1Price":"112.90",
464
+ # "ask1Size":"5.02"
465
+ # },
466
+ # "cs":78039939929,
467
+ # "ts":1709210212704
468
+ # }
469
+ #
470
+ topic = self.safe_string(message, 'topic', '')
471
+ updateType = self.safe_string(message, 'type', '')
472
+ data = self.safe_dict(message, 'data', {})
473
+ isSpot = self.safe_string(data, 'usdIndexPrice') is not None
474
+ type = 'spot' if isSpot else 'contract'
475
+ symbol = None
476
+ parsed = None
477
+ if (updateType == 'snapshot'):
478
+ parsed = self.parse_ticker(data)
479
+ symbol = parsed['symbol']
480
+ elif updateType == 'delta':
481
+ topicParts = topic.split('.')
482
+ topicLength = len(topicParts)
483
+ marketId = self.safe_string(topicParts, topicLength - 1)
484
+ market = self.safe_market(marketId, None, None, type)
485
+ symbol = market['symbol']
486
+ # update the info in place
487
+ ticker = self.safe_dict(self.tickers, symbol, {})
488
+ rawTicker = self.safe_dict(ticker, 'info', {})
489
+ merged = self.extend(rawTicker, data)
490
+ parsed = self.parse_ticker(merged)
491
+ timestamp = self.safe_integer(message, 'ts')
492
+ parsed['timestamp'] = timestamp
493
+ parsed['datetime'] = self.iso8601(timestamp)
494
+ self.tickers[symbol] = parsed
495
+ messageHash = 'ticker:' + symbol
496
+ client.resolve(self.tickers[symbol], messageHash)
497
+
498
+ async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
499
+ """
500
+ 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
503
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
504
+ :param str timeframe: the length of time each candle represents
505
+ :param int [since]: timestamp in ms of the earliest candle to fetch
506
+ :param int [limit]: the maximum amount of candles to fetch
507
+ :param dict [params]: extra parameters specific to the exchange API endpoint
508
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
509
+ """
510
+ 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)
520
+ if self.newUpdates:
521
+ limit = ohlcv.getLimit(symbol, limit)
522
+ return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
523
+
524
+ def handle_ohlcv(self, client: Client, message):
525
+ #
526
+ # {
527
+ # "topic": "kline.5.BTCUSDT",
528
+ # "data": [
529
+ # {
530
+ # "start": 1672324800000,
531
+ # "end": 1672325099999,
532
+ # "interval": "5",
533
+ # "open": "16649.5",
534
+ # "close": "16677",
535
+ # "high": "16677",
536
+ # "low": "16608",
537
+ # "volume": "2.081",
538
+ # "turnover": "34666.4005",
539
+ # "confirm": False,
540
+ # "timestamp": 1672324988882
541
+ # }
542
+ # ],
543
+ # "ts": 1672324988882,
544
+ # "type": "snapshot"
545
+ # }
546
+ #
547
+ data = self.safe_value(message, 'data', {})
548
+ topic = self.safe_string(message, 'topic')
549
+ topicParts = topic.split('.')
550
+ topicLength = len(topicParts)
551
+ timeframeId = self.safe_string(topicParts, 1)
552
+ timeframe = self.find_timeframe(timeframeId)
553
+ marketId = self.safe_string(topicParts, topicLength - 1)
554
+ isSpot = client.url.find('spot') > -1
555
+ marketType = 'spot' if isSpot else 'contract'
556
+ market = self.safe_market(marketId, None, None, marketType)
557
+ symbol = market['symbol']
558
+ ohlcvsByTimeframe = self.safe_value(self.ohlcvs, symbol)
559
+ if ohlcvsByTimeframe is None:
560
+ self.ohlcvs[symbol] = {}
561
+ stored = self.safe_value(ohlcvsByTimeframe, timeframe)
562
+ if stored is None:
563
+ limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
564
+ stored = ArrayCacheByTimestamp(limit)
565
+ self.ohlcvs[symbol][timeframe] = stored
566
+ for i in range(0, len(data)):
567
+ parsed = self.parse_ws_ohlcv(data[i])
568
+ stored.append(parsed)
569
+ messageHash = 'kline' + ':' + timeframeId + ':' + symbol
570
+ client.resolve(stored, messageHash)
571
+
572
+ def parse_ws_ohlcv(self, ohlcv, market=None) -> list:
573
+ #
574
+ # {
575
+ # "start": 1670363160000,
576
+ # "end": 1670363219999,
577
+ # "interval": "1",
578
+ # "open": "16987.5",
579
+ # "close": "16987.5",
580
+ # "high": "16988",
581
+ # "low": "16987.5",
582
+ # "volume": "23.511",
583
+ # "turnover": "399396.344",
584
+ # "confirm": False,
585
+ # "timestamp": 1670363219614
586
+ # }
587
+ #
588
+ return [
589
+ self.safe_integer(ohlcv, 'start'),
590
+ self.safe_number(ohlcv, 'open'),
591
+ self.safe_number(ohlcv, 'high'),
592
+ self.safe_number(ohlcv, 'low'),
593
+ self.safe_number(ohlcv, 'close'),
594
+ self.safe_number_2(ohlcv, 'volume', 'turnover'),
595
+ ]
596
+
597
+ async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
598
+ """
599
+ 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
601
+ :param str symbol: unified symbol of the market to fetch the order book for
602
+ :param int [limit]: the maximum amount of order book entries to return.
603
+ :param dict [params]: extra parameters specific to the exchange API endpoint
604
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
605
+ """
606
+ return await self.watch_order_book_for_symbols([symbol], limit, params)
607
+
608
+ async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
609
+ """
610
+ 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
612
+ :param str[] symbols: unified array of symbols
613
+ :param int [limit]: the maximum amount of order book entries to return.
614
+ :param dict [params]: extra parameters specific to the exchange API endpoint
615
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
616
+ """
617
+ await self.load_markets()
618
+ symbolsLength = len(symbols)
619
+ if symbolsLength == 0:
620
+ raise ArgumentsRequired(self.id + ' watchOrderBookForSymbols() requires a non-empty array of symbols')
621
+ symbols = self.market_symbols(symbols)
622
+ url = self.get_url_by_market_type(symbols[0], False, 'watchOrderBook', params)
623
+ params = self.clean_params(params)
624
+ market = self.market(symbols[0])
625
+ if limit is None:
626
+ limit = 50 if (market['spot']) else 500
627
+ 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.')
632
+ topics = []
633
+ messageHashes = []
634
+ for i in range(0, len(symbols)):
635
+ symbol = symbols[i]
636
+ marketId = self.market_id(symbol)
637
+ topic = 'orderbook.' + str(limit) + '.' + marketId
638
+ topics.append(topic)
639
+ messageHash = 'orderbook:' + symbol
640
+ messageHashes.append(messageHash)
641
+ orderbook = await self.watch_topics(url, messageHashes, topics, params)
642
+ return orderbook.limit()
643
+
644
+ def handle_order_book(self, client: Client, message):
645
+ #
646
+ # {
647
+ # "topic": "orderbook.50.BTCUSDT",
648
+ # "type": "snapshot",
649
+ # "ts": 1672304484978,
650
+ # "data": {
651
+ # "s": "BTCUSDT",
652
+ # "b": [
653
+ # ...,
654
+ # [
655
+ # "16493.50",
656
+ # "0.006"
657
+ # ],
658
+ # [
659
+ # "16493.00",
660
+ # "0.100"
661
+ # ]
662
+ # ],
663
+ # "a": [
664
+ # [
665
+ # "16611.00",
666
+ # "0.029"
667
+ # ],
668
+ # [
669
+ # "16612.00",
670
+ # "0.213"
671
+ # ],
672
+ # ],
673
+ # "u": 18521288,
674
+ # "seq": 7961638724
675
+ # }
676
+ # }
677
+ #
678
+ isSpot = client.url.find('spot') >= 0
679
+ type = self.safe_string(message, 'type')
680
+ isSnapshot = (type == 'snapshot')
681
+ data = self.safe_dict(message, 'data', {})
682
+ marketId = self.safe_string(data, 's')
683
+ marketType = 'spot' if isSpot else 'contract'
684
+ market = self.safe_market(marketId, None, None, marketType)
685
+ symbol = market['symbol']
686
+ timestamp = self.safe_integer(message, 'ts')
687
+ if not (symbol in self.orderbooks):
688
+ self.orderbooks[symbol] = self.order_book()
689
+ orderbook = self.orderbooks[symbol]
690
+ if isSnapshot:
691
+ snapshot = self.parse_order_book(data, symbol, timestamp, 'b', 'a')
692
+ orderbook.reset(snapshot)
693
+ else:
694
+ asks = self.safe_list(data, 'a', [])
695
+ bids = self.safe_list(data, 'b', [])
696
+ self.handle_deltas(orderbook['asks'], asks)
697
+ self.handle_deltas(orderbook['bids'], bids)
698
+ orderbook['timestamp'] = timestamp
699
+ orderbook['datetime'] = self.iso8601(timestamp)
700
+ messageHash = 'orderbook' + ':' + symbol
701
+ self.orderbooks[symbol] = orderbook
702
+ client.resolve(orderbook, messageHash)
703
+
704
+ def handle_delta(self, bookside, delta):
705
+ bidAsk = self.parse_bid_ask(delta, 0, 1)
706
+ bookside.storeArray(bidAsk)
707
+
708
+ def handle_deltas(self, bookside, deltas):
709
+ for i in range(0, len(deltas)):
710
+ self.handle_delta(bookside, deltas[i])
711
+
712
+ async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
713
+ """
714
+ watches information on multiple trades made in a market
715
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/public/trade
716
+ :param str symbol: unified market symbol of the market trades were made in
717
+ :param int [since]: the earliest time in ms to fetch trades for
718
+ :param int [limit]: the maximum number of trade structures to retrieve
719
+ :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
721
+ """
722
+ return await self.watch_trades_for_symbols([symbol], since, limit, params)
723
+
724
+ async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
725
+ """
726
+ get the list of most recent trades for a list of symbols
727
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/public/trade
728
+ :param str[] symbols: unified symbol of the market to fetch trades for
729
+ :param int [since]: timestamp in ms of the earliest trade to fetch
730
+ :param int [limit]: the maximum amount of trades to fetch
731
+ :param dict [params]: extra parameters specific to the exchange API endpoint
732
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
733
+ """
734
+ await self.load_markets()
735
+ symbols = self.market_symbols(symbols)
736
+ symbolsLength = len(symbols)
737
+ if symbolsLength == 0:
738
+ raise ArgumentsRequired(self.id + ' watchTradesForSymbols() requires a non-empty array of symbols')
739
+ params = self.clean_params(params)
740
+ url = self.get_url_by_market_type(symbols[0], False, 'watchTrades', params)
741
+ topics = []
742
+ messageHashes = []
743
+ for i in range(0, len(symbols)):
744
+ symbol = symbols[i]
745
+ market = self.market(symbol)
746
+ topic = 'publicTrade.' + market['id']
747
+ topics.append(topic)
748
+ messageHash = 'trade:' + symbol
749
+ messageHashes.append(messageHash)
750
+ trades = await self.watch_topics(url, messageHashes, topics, params)
751
+ if self.newUpdates:
752
+ first = self.safe_value(trades, 0)
753
+ tradeSymbol = self.safe_string(first, 'symbol')
754
+ limit = trades.getLimit(tradeSymbol, limit)
755
+ return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
756
+
757
+ def handle_trades(self, client: Client, message):
758
+ #
759
+ # {
760
+ # "topic": "publicTrade.BTCUSDT",
761
+ # "type": "snapshot",
762
+ # "ts": 1672304486868,
763
+ # "data": [
764
+ # {
765
+ # "T": 1672304486865,
766
+ # "s": "BTCUSDT",
767
+ # "S": "Buy",
768
+ # "v": "0.001",
769
+ # "p": "16578.50",
770
+ # "L": "PlusTick",
771
+ # "i": "20f43950-d8dd-5b31-9112-a178eb6023af",
772
+ # "BT": False
773
+ # }
774
+ # ]
775
+ # }
776
+ #
777
+ data = self.safe_value(message, 'data', {})
778
+ topic = self.safe_string(message, 'topic')
779
+ trades = data
780
+ parts = topic.split('.')
781
+ isSpot = client.url.find('spot') >= 0
782
+ marketType = 'spot' if (isSpot) else 'contract'
783
+ marketId = self.safe_string(parts, 1)
784
+ market = self.safe_market(marketId, None, None, marketType)
785
+ symbol = market['symbol']
786
+ stored = self.safe_value(self.trades, symbol)
787
+ if stored is None:
788
+ limit = self.safe_integer(self.options, 'tradesLimit', 1000)
789
+ stored = ArrayCache(limit)
790
+ self.trades[symbol] = stored
791
+ for j in range(0, len(trades)):
792
+ parsed = self.parse_ws_trade(trades[j], market)
793
+ stored.append(parsed)
794
+ messageHash = 'trade' + ':' + symbol
795
+ client.resolve(stored, messageHash)
796
+
797
+ def parse_ws_trade(self, trade, market=None):
798
+ #
799
+ # public
800
+ # {
801
+ # "T": 1672304486865,
802
+ # "s": "BTCUSDT",
803
+ # "S": "Buy",
804
+ # "v": "0.001",
805
+ # "p": "16578.50",
806
+ # "L": "PlusTick",
807
+ # "i": "20f43950-d8dd-5b31-9112-a178eb6023af",
808
+ # "BT": False
809
+ # }
810
+ #
811
+ # spot private
812
+ # {
813
+ # "e": "ticketInfo",
814
+ # "E": "1662348310386",
815
+ # "s": "BTCUSDT",
816
+ # "q": "0.001007",
817
+ # "t": "1662348310373",
818
+ # "p": "19842.02",
819
+ # "T": "2100000000002220938",
820
+ # "o": "1238261807653647872",
821
+ # "c": "spotx008",
822
+ # "O": "1238225004531834368",
823
+ # "a": "533287",
824
+ # "A": "642908",
825
+ # "m": False,
826
+ # "S": "BUY"
827
+ # }
828
+ #
829
+ id = self.safe_string_n(trade, ['i', 'T', 'v'])
830
+ isContract = ('BT' in trade)
831
+ marketType = 'contract' if isContract else 'spot'
832
+ if market is not None:
833
+ marketType = market['type']
834
+ marketId = self.safe_string(trade, 's')
835
+ market = self.safe_market(marketId, market, None, marketType)
836
+ symbol = market['symbol']
837
+ timestamp = self.safe_integer_2(trade, 't', 'T')
838
+ side = self.safe_string_lower(trade, 'S')
839
+ takerOrMaker = None
840
+ m = self.safe_value(trade, 'm')
841
+ if side is None:
842
+ side = 'buy' if m else 'sell'
843
+ else:
844
+ # spot private
845
+ takerOrMaker = m
846
+ price = self.safe_string(trade, 'p')
847
+ amount = self.safe_string_2(trade, 'q', 'v')
848
+ orderId = self.safe_string(trade, 'o')
849
+ return self.safe_trade({
850
+ 'id': id,
851
+ 'info': trade,
852
+ 'timestamp': timestamp,
853
+ 'datetime': self.iso8601(timestamp),
854
+ 'symbol': symbol,
855
+ 'order': orderId,
856
+ 'type': None,
857
+ 'side': side,
858
+ 'takerOrMaker': takerOrMaker,
859
+ 'price': price,
860
+ 'amount': amount,
861
+ 'cost': None,
862
+ 'fee': None,
863
+ }, market)
864
+
865
+ def get_private_type(self, url):
866
+ if url.find('spot') >= 0:
867
+ return 'spot'
868
+ elif url.find('v5/private') >= 0:
869
+ return 'unified'
870
+ else:
871
+ return 'usdc'
872
+
873
+ async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
874
+ """
875
+ watches information on multiple trades made by the user
876
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/private/execution
877
+ :param str symbol: unified market symbol of the market orders were made in
878
+ :param int [since]: the earliest time in ms to fetch orders for
879
+ :param int [limit]: the maximum number of order structures to retrieve
880
+ :param dict [params]: extra parameters specific to the exchange API endpoint
881
+ :param boolean [params.unifiedMargin]: use unified margin account
882
+ :returns dict[]: a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure
883
+ """
884
+ method = 'watchMyTrades'
885
+ messageHash = 'myTrades'
886
+ await self.load_markets()
887
+ if symbol is not None:
888
+ symbol = self.symbol(symbol)
889
+ messageHash += ':' + symbol
890
+ url = self.get_url_by_market_type(symbol, True, method, params)
891
+ await self.authenticate(url)
892
+ topicByMarket: dict = {
893
+ 'spot': 'ticketInfo',
894
+ 'unified': 'execution',
895
+ 'usdc': 'user.openapi.perp.trade',
896
+ }
897
+ topic = self.safe_value(topicByMarket, self.get_private_type(url))
898
+ trades = await self.watch_topics(url, [messageHash], [topic], params)
899
+ if self.newUpdates:
900
+ limit = trades.getLimit(symbol, limit)
901
+ return self.filter_by_symbol_since_limit(trades, symbol, since, limit, True)
902
+
903
+ def handle_my_trades(self, client: Client, message):
904
+ #
905
+ # spot
906
+ # {
907
+ # "type": "snapshot",
908
+ # "topic": "ticketInfo",
909
+ # "ts": "1662348310388",
910
+ # "data": [
911
+ # {
912
+ # "e": "ticketInfo",
913
+ # "E": "1662348310386",
914
+ # "s": "BTCUSDT",
915
+ # "q": "0.001007",
916
+ # "t": "1662348310373",
917
+ # "p": "19842.02",
918
+ # "T": "2100000000002220938",
919
+ # "o": "1238261807653647872",
920
+ # "c": "spotx008",
921
+ # "O": "1238225004531834368",
922
+ # "a": "533287",
923
+ # "A": "642908",
924
+ # "m": False,
925
+ # "S": "BUY"
926
+ # }
927
+ # ]
928
+ # }
929
+ # unified
930
+ # {
931
+ # "id": "592324803b2785-26fa-4214-9963-bdd4727f07be",
932
+ # "topic": "execution",
933
+ # "creationTime": 1672364174455,
934
+ # "data": [
935
+ # {
936
+ # "category": "linear",
937
+ # "symbol": "XRPUSDT",
938
+ # "execFee": "0.005061",
939
+ # "execId": "7e2ae69c-4edf-5800-a352-893d52b446aa",
940
+ # "execPrice": "0.3374",
941
+ # "execQty": "25",
942
+ # "execType": "Trade",
943
+ # "execValue": "8.435",
944
+ # "isMaker": False,
945
+ # "feeRate": "0.0006",
946
+ # "tradeIv": "",
947
+ # "markIv": "",
948
+ # "blockTradeId": "",
949
+ # "markPrice": "0.3391",
950
+ # "indexPrice": "",
951
+ # "underlyingPrice": "",
952
+ # "leavesQty": "0",
953
+ # "orderId": "f6e324ff-99c2-4e89-9739-3086e47f9381",
954
+ # "orderLinkId": "",
955
+ # "orderPrice": "0.3207",
956
+ # "orderQty": "25",
957
+ # "orderType": "Market",
958
+ # "stopOrderType": "UNKNOWN",
959
+ # "side": "Sell",
960
+ # "execTime": "1672364174443",
961
+ # "isLeverage": "0"
962
+ # }
963
+ # ]
964
+ # }
965
+ #
966
+ topic = self.safe_string(message, 'topic')
967
+ spot = topic == 'ticketInfo'
968
+ data = self.safe_value(message, 'data', [])
969
+ if not isinstance(data, list):
970
+ data = self.safe_value(data, 'result', [])
971
+ if self.myTrades is None:
972
+ limit = self.safe_integer(self.options, 'tradesLimit', 1000)
973
+ self.myTrades = ArrayCacheBySymbolById(limit)
974
+ trades = self.myTrades
975
+ symbols: dict = {}
976
+ for i in range(0, len(data)):
977
+ rawTrade = data[i]
978
+ parsed = None
979
+ if spot:
980
+ parsed = self.parse_ws_trade(rawTrade)
981
+ else:
982
+ parsed = self.parse_trade(rawTrade)
983
+ symbol = parsed['symbol']
984
+ symbols[symbol] = True
985
+ trades.append(parsed)
986
+ keys = list(symbols.keys())
987
+ for i in range(0, len(keys)):
988
+ currentMessageHash = 'myTrades:' + keys[i]
989
+ client.resolve(trades, currentMessageHash)
990
+ # non-symbol specific
991
+ messageHash = 'myTrades'
992
+ client.resolve(trades, messageHash)
993
+
994
+ async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
995
+ """
996
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/private/position
997
+ watch all open positions
998
+ :param str[] [symbols]: list of unified market symbols
999
+ :param dict params: extra parameters specific to the exchange API endpoint
1000
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
1001
+ """
1002
+ await self.load_markets()
1003
+ method = 'watchPositions'
1004
+ messageHash = ''
1005
+ if not self.is_empty(symbols):
1006
+ symbols = self.market_symbols(symbols)
1007
+ messageHash = '::' + ','.join(symbols)
1008
+ firstSymbol = self.safe_string(symbols, 0)
1009
+ url = self.get_url_by_market_type(firstSymbol, True, method, params)
1010
+ messageHash = 'positions' + messageHash
1011
+ client = self.client(url)
1012
+ await self.authenticate(url)
1013
+ self.set_positions_cache(client, symbols)
1014
+ cache = self.positions
1015
+ fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', True)
1016
+ awaitPositionsSnapshot = self.safe_bool('watchPositions', 'awaitPositionsSnapshot', True)
1017
+ if fetchPositionsSnapshot and awaitPositionsSnapshot and cache is None:
1018
+ snapshot = await client.future('fetchPositionsSnapshot')
1019
+ return self.filter_by_symbols_since_limit(snapshot, symbols, since, limit, True)
1020
+ topics = ['position']
1021
+ newPositions = await self.watch_topics(url, [messageHash], topics, params)
1022
+ if self.newUpdates:
1023
+ return newPositions
1024
+ return self.filter_by_symbols_since_limit(cache, symbols, since, limit, True)
1025
+
1026
+ def set_positions_cache(self, client: Client, symbols: Strings = None):
1027
+ if self.positions is not None:
1028
+ return
1029
+ fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', True)
1030
+ if fetchPositionsSnapshot:
1031
+ messageHash = 'fetchPositionsSnapshot'
1032
+ if not (messageHash in client.futures):
1033
+ client.future(messageHash)
1034
+ self.spawn(self.load_positions_snapshot, client, messageHash)
1035
+ else:
1036
+ self.positions = ArrayCacheBySymbolBySide()
1037
+
1038
+ async def load_positions_snapshot(self, client, messageHash):
1039
+ # one ws channel gives positions for all types, for snapshot must load all positions
1040
+ fetchFunctions = [
1041
+ self.fetch_positions(None, {'type': 'swap', 'subType': 'linear'}),
1042
+ self.fetch_positions(None, {'type': 'swap', 'subType': 'inverse'}),
1043
+ ]
1044
+ promises = await asyncio.gather(*fetchFunctions)
1045
+ self.positions = ArrayCacheBySymbolBySide()
1046
+ cache = self.positions
1047
+ for i in range(0, len(promises)):
1048
+ positions = promises[i]
1049
+ for ii in range(0, len(positions)):
1050
+ position = positions[ii]
1051
+ cache.append(position)
1052
+ # don't remove the future from the .futures cache
1053
+ future = client.futures[messageHash]
1054
+ future.resolve(cache)
1055
+ client.resolve(cache, 'position')
1056
+
1057
+ def handle_positions(self, client, message):
1058
+ #
1059
+ # {
1060
+ # topic: 'position',
1061
+ # id: '504b2671629b08e3c4f6960382a59363:3bc4028023786545:0:01',
1062
+ # creationTime: 1694566055295,
1063
+ # data: [{
1064
+ # bustPrice: '15.00',
1065
+ # category: 'inverse',
1066
+ # createdTime: '1670083436351',
1067
+ # cumRealisedPnl: '0.00011988',
1068
+ # entryPrice: '19358.58553268',
1069
+ # leverage: '10',
1070
+ # liqPrice: '15.00',
1071
+ # markPrice: '25924.00',
1072
+ # positionBalance: '0.0000156',
1073
+ # positionIdx: 0,
1074
+ # positionMM: '0.001',
1075
+ # positionIM: '0.0000015497',
1076
+ # positionStatus: 'Normal',
1077
+ # positionValue: '0.00015497',
1078
+ # riskId: 1,
1079
+ # riskLimitValue: '150',
1080
+ # side: 'Buy',
1081
+ # size: '3',
1082
+ # stopLoss: '0.00',
1083
+ # symbol: 'BTCUSD',
1084
+ # takeProfit: '0.00',
1085
+ # tpslMode: 'Full',
1086
+ # tradeMode: 0,
1087
+ # autoAddMargin: 1,
1088
+ # trailingStop: '0.00',
1089
+ # unrealisedPnl: '0.00003925',
1090
+ # updatedTime: '1694566055293',
1091
+ # adlRankIndicator: 3
1092
+ # }]
1093
+ # }
1094
+ #
1095
+ # each account is connected to a different endpoint
1096
+ # and has exactly one subscriptionhash which is the account type
1097
+ if self.positions is None:
1098
+ self.positions = ArrayCacheBySymbolBySide()
1099
+ cache = self.positions
1100
+ newPositions = []
1101
+ rawPositions = self.safe_value(message, 'data', [])
1102
+ for i in range(0, len(rawPositions)):
1103
+ rawPosition = rawPositions[i]
1104
+ position = self.parse_position(rawPosition)
1105
+ side = self.safe_string(position, 'side')
1106
+ # hacky solution to handle closing positions
1107
+ # without crashing, we should handle self properly later
1108
+ newPositions.append(position)
1109
+ if side is None or side == '':
1110
+ # closing update, adding both sides to "reset" both sides
1111
+ # since we don't know which side is being closed
1112
+ position['side'] = 'long'
1113
+ cache.append(position)
1114
+ position['side'] = 'short'
1115
+ cache.append(position)
1116
+ position['side'] = None
1117
+ else:
1118
+ # regular update
1119
+ cache.append(position)
1120
+ messageHashes = self.find_message_hashes(client, 'positions::')
1121
+ for i in range(0, len(messageHashes)):
1122
+ messageHash = messageHashes[i]
1123
+ parts = messageHash.split('::')
1124
+ symbolsString = parts[1]
1125
+ symbols = symbolsString.split(',')
1126
+ positions = self.filter_by_array(newPositions, 'symbol', symbols, False)
1127
+ if not self.is_empty(positions):
1128
+ client.resolve(positions, messageHash)
1129
+ client.resolve(newPositions, 'positions')
1130
+
1131
+ async def watch_liquidations(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
1132
+ """
1133
+ watch the public liquidations of a trading pair
1134
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/public/liquidation
1135
+ :param str symbol: unified CCXT market symbol
1136
+ :param int [since]: the earliest time in ms to fetch liquidations for
1137
+ :param int [limit]: the maximum number of liquidation structures to retrieve
1138
+ :param dict [params]: exchange specific parameters for the bitmex api endpoint
1139
+ :returns dict: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
1140
+ """
1141
+ await self.load_markets()
1142
+ market = self.market(symbol)
1143
+ symbol = market['symbol']
1144
+ url = self.get_url_by_market_type(symbol, False, 'watchLiquidations', params)
1145
+ params = self.clean_params(params)
1146
+ messageHash = 'liquidations::' + symbol
1147
+ topic = 'liquidation.' + market['id']
1148
+ newLiquidation = await self.watch_topics(url, [messageHash], [topic], params)
1149
+ if self.newUpdates:
1150
+ return [newLiquidation]
1151
+ return self.filter_by_symbols_since_limit(self.liquidations, [symbol], since, limit, True)
1152
+
1153
+ def handle_liquidation(self, client: Client, message):
1154
+ #
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
+ # }
1167
+ #
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)
1181
+
1182
+ def parse_ws_liquidation(self, liquidation, market=None):
1183
+ #
1184
+ # {
1185
+ # "price": "0.03803",
1186
+ # "side": "Buy",
1187
+ # "size": "1637",
1188
+ # "symbol": "GALAUSDT",
1189
+ # "updatedTime": 1673251091822
1190
+ # }
1191
+ #
1192
+ marketId = self.safe_string(liquidation, 'symbol')
1193
+ market = self.safe_market(marketId, market, '', 'contract')
1194
+ timestamp = self.safe_integer(liquidation, 'updatedTime')
1195
+ return self.safe_liquidation({
1196
+ 'info': liquidation,
1197
+ 'symbol': self.safe_symbol(marketId, market),
1198
+ 'contracts': self.safe_number(liquidation, 'size'),
1199
+ 'contractSize': self.safe_number(market, 'contractSize'),
1200
+ 'price': self.safe_number(liquidation, 'price'),
1201
+ 'baseValue': None,
1202
+ 'quoteValue': None,
1203
+ 'timestamp': timestamp,
1204
+ 'datetime': self.iso8601(timestamp),
1205
+ })
1206
+
1207
+ async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1208
+ """
1209
+ watches information on multiple orders made by the user
1210
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/private/order
1211
+ :param str symbol: unified market symbol of the market orders were made in
1212
+ :param int [since]: the earliest time in ms to fetch orders for
1213
+ :param int [limit]: the maximum number of order structures to retrieve
1214
+ :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
1216
+ """
1217
+ await self.load_markets()
1218
+ method = 'watchOrders'
1219
+ messageHash = 'orders'
1220
+ if symbol is not None:
1221
+ symbol = self.symbol(symbol)
1222
+ messageHash += ':' + symbol
1223
+ url = self.get_url_by_market_type(symbol, True, method, params)
1224
+ await self.authenticate(url)
1225
+ topicsByMarket: dict = {
1226
+ 'spot': ['order', 'stopOrder'],
1227
+ 'unified': ['order'],
1228
+ 'usdc': ['user.openapi.perp.order'],
1229
+ }
1230
+ topics = self.safe_value(topicsByMarket, self.get_private_type(url))
1231
+ orders = await self.watch_topics(url, [messageHash], topics, params)
1232
+ if self.newUpdates:
1233
+ limit = orders.getLimit(symbol, limit)
1234
+ return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
1235
+
1236
+ def handle_order_ws(self, client: Client, message):
1237
+ #
1238
+ # {
1239
+ # "reqId":"1",
1240
+ # "retCode":0,
1241
+ # "retMsg":"OK",
1242
+ # "op":"order.create",
1243
+ # "data":{
1244
+ # "orderId":"1673523595617593600",
1245
+ # "orderLinkId":"1673523595617593601"
1246
+ # },
1247
+ # "header":{
1248
+ # "X-Bapi-Limit":"20",
1249
+ # "X-Bapi-Limit-Status":"19",
1250
+ # "X-Bapi-Limit-Reset-Timestamp":"1714235558880",
1251
+ # "Traceid":"584a06d373f2fdcb3a4dfdd81d27df11",
1252
+ # "Timenow":"1714235558881"
1253
+ # },
1254
+ # "connId":"cojidqec0hv9fgvhtbt0-40e"
1255
+ # }
1256
+ #
1257
+ messageHash = self.safe_string(message, 'reqId')
1258
+ data = self.safe_dict(message, 'data')
1259
+ order = self.parse_order(data)
1260
+ client.resolve(order, messageHash)
1261
+
1262
+ def handle_order(self, client: Client, message):
1263
+ #
1264
+ # spot
1265
+ # {
1266
+ # "type": "snapshot",
1267
+ # "topic": "order",
1268
+ # "ts": "1662348310441",
1269
+ # "data": [
1270
+ # {
1271
+ # "e": "order",
1272
+ # "E": "1662348310441",
1273
+ # "s": "BTCUSDT",
1274
+ # "c": "spotx008",
1275
+ # "S": "BUY",
1276
+ # "o": "MARKET_OF_QUOTE",
1277
+ # "f": "GTC",
1278
+ # "q": "20",
1279
+ # "p": "0",
1280
+ # "X": "CANCELED",
1281
+ # "i": "1238261807653647872",
1282
+ # "M": "1238225004531834368",
1283
+ # "l": "0.001007",
1284
+ # "z": "0.001007",
1285
+ # "L": "19842.02",
1286
+ # "n": "0",
1287
+ # "N": "BTC",
1288
+ # "u": True,
1289
+ # "w": True,
1290
+ # "m": False,
1291
+ # "O": "1662348310368",
1292
+ # "Z": "19.98091414",
1293
+ # "A": "0",
1294
+ # "C": False,
1295
+ # "v": "0",
1296
+ # "d": "NO_LIQ",
1297
+ # "t": "2100000000002220938"
1298
+ # }
1299
+ # ]
1300
+ # }
1301
+ # unified
1302
+ # {
1303
+ # "id": "5923240c6880ab-c59f-420b-9adb-3639adc9dd90",
1304
+ # "topic": "order",
1305
+ # "creationTime": 1672364262474,
1306
+ # "data": [
1307
+ # {
1308
+ # "symbol": "ETH-30DEC22-1400-C",
1309
+ # "orderId": "5cf98598-39a7-459e-97bf-76ca765ee020",
1310
+ # "side": "Sell",
1311
+ # "orderType": "Market",
1312
+ # "cancelType": "UNKNOWN",
1313
+ # "price": "72.5",
1314
+ # "qty": "1",
1315
+ # "orderIv": "",
1316
+ # "timeInForce": "IOC",
1317
+ # "orderStatus": "Filled",
1318
+ # "orderLinkId": "",
1319
+ # "lastPriceOnCreated": "",
1320
+ # "reduceOnly": False,
1321
+ # "leavesQty": "",
1322
+ # "leavesValue": "",
1323
+ # "cumExecQty": "1",
1324
+ # "cumExecValue": "75",
1325
+ # "avgPrice": "75",
1326
+ # "blockTradeId": "",
1327
+ # "positionIdx": 0,
1328
+ # "cumExecFee": "0.358635",
1329
+ # "createdTime": "1672364262444",
1330
+ # "updatedTime": "1672364262457",
1331
+ # "rejectReason": "EC_NoError",
1332
+ # "stopOrderType": "",
1333
+ # "triggerPrice": "",
1334
+ # "takeProfit": "",
1335
+ # "stopLoss": "",
1336
+ # "tpTriggerBy": "",
1337
+ # "slTriggerBy": "",
1338
+ # "triggerDirection": 0,
1339
+ # "triggerBy": "",
1340
+ # "closeOnTrigger": False,
1341
+ # "category": "option"
1342
+ # }
1343
+ # ]
1344
+ # }
1345
+ #
1346
+ if self.orders is None:
1347
+ limit = self.safe_integer(self.options, 'ordersLimit', 1000)
1348
+ self.orders = ArrayCacheBySymbolById(limit)
1349
+ orders = self.orders
1350
+ rawOrders = self.safe_value(message, 'data', [])
1351
+ first = self.safe_value(rawOrders, 0, {})
1352
+ category = self.safe_string(first, 'category')
1353
+ isSpot = category == 'spot'
1354
+ if not isSpot:
1355
+ rawOrders = self.safe_value(rawOrders, 'result', rawOrders)
1356
+ symbols: dict = {}
1357
+ 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])
1363
+ symbol = parsed['symbol']
1364
+ symbols[symbol] = True
1365
+ orders.append(parsed)
1366
+ symbolsArray = list(symbols.keys())
1367
+ for i in range(0, len(symbolsArray)):
1368
+ currentMessageHash = 'orders:' + symbolsArray[i]
1369
+ client.resolve(orders, currentMessageHash)
1370
+ messageHash = 'orders'
1371
+ client.resolve(orders, messageHash)
1372
+
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
+ async def watch_balance(self, params={}) -> Balances:
1505
+ """
1506
+ 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
1508
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1509
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1510
+ """
1511
+ await self.load_markets()
1512
+ method = 'watchBalance'
1513
+ messageHash = 'balances'
1514
+ type = None
1515
+ type, params = self.handle_market_type_and_params('watchBalance', None, params)
1516
+ subType = None
1517
+ subType, params = self.handle_sub_type_and_params('watchBalance', None, params)
1518
+ unified = await self.isUnifiedEnabled()
1519
+ isUnifiedMargin = self.safe_bool(unified, 0, False)
1520
+ isUnifiedAccount = self.safe_bool(unified, 1, False)
1521
+ url = self.get_url_by_market_type(None, True, method, params)
1522
+ await self.authenticate(url)
1523
+ topicByMarket: dict = {
1524
+ 'spot': 'outboundAccountInfo',
1525
+ 'unified': 'wallet',
1526
+ }
1527
+ if isUnifiedAccount:
1528
+ # unified account
1529
+ if subType == 'inverse':
1530
+ messageHash += ':contract'
1531
+ else:
1532
+ messageHash += ':unified'
1533
+ if not isUnifiedMargin and not isUnifiedAccount:
1534
+ # normal account using v5
1535
+ if type == 'spot':
1536
+ messageHash += ':spot'
1537
+ else:
1538
+ messageHash += ':contract'
1539
+ if isUnifiedMargin:
1540
+ # unified margin account using v5
1541
+ if type == 'spot':
1542
+ messageHash += ':spot'
1543
+ else:
1544
+ if subType == 'linear':
1545
+ messageHash += ':unified'
1546
+ else:
1547
+ messageHash += ':contract'
1548
+ topics = [self.safe_value(topicByMarket, self.get_private_type(url))]
1549
+ return await self.watch_topics(url, [messageHash], topics, params)
1550
+
1551
+ def handle_balance(self, client: Client, message):
1552
+ #
1553
+ # spot
1554
+ # {
1555
+ # "type": "snapshot",
1556
+ # "topic": "outboundAccountInfo",
1557
+ # "ts": "1662107217641",
1558
+ # "data": [
1559
+ # {
1560
+ # "e": "outboundAccountInfo",
1561
+ # "E": "1662107217640",
1562
+ # "T": True,
1563
+ # "W": True,
1564
+ # "D": True,
1565
+ # "B": [
1566
+ # {
1567
+ # "a": "USDT",
1568
+ # "f": "176.81254174",
1569
+ # "l": "201.575"
1570
+ # }
1571
+ # ]
1572
+ # }
1573
+ # ]
1574
+ # }
1575
+ # unified
1576
+ # {
1577
+ # "id": "5923242c464be9-25ca-483d-a743-c60101fc656f",
1578
+ # "topic": "wallet",
1579
+ # "creationTime": 1672364262482,
1580
+ # "data": [
1581
+ # {
1582
+ # "accountIMRate": "0.016",
1583
+ # "accountMMRate": "0.003",
1584
+ # "totalEquity": "12837.78330098",
1585
+ # "totalWalletBalance": "12840.4045924",
1586
+ # "totalMarginBalance": "12837.78330188",
1587
+ # "totalAvailableBalance": "12632.05767702",
1588
+ # "totalPerpUPL": "-2.62129051",
1589
+ # "totalInitialMargin": "205.72562486",
1590
+ # "totalMaintenanceMargin": "39.42876721",
1591
+ # "coin": [
1592
+ # {
1593
+ # "coin": "USDC",
1594
+ # "equity": "200.62572554",
1595
+ # "usdValue": "200.62572554",
1596
+ # "walletBalance": "201.34882644",
1597
+ # "availableToWithdraw": "0",
1598
+ # "availableToBorrow": "1500000",
1599
+ # "borrowAmount": "0",
1600
+ # "accruedInterest": "0",
1601
+ # "totalOrderIM": "0",
1602
+ # "totalPositionIM": "202.99874213",
1603
+ # "totalPositionMM": "39.14289747",
1604
+ # "unrealisedPnl": "74.2768991",
1605
+ # "cumRealisedPnl": "-209.1544627",
1606
+ # "bonus": "0"
1607
+ # },
1608
+ # {
1609
+ # "coin": "BTC",
1610
+ # "equity": "0.06488393",
1611
+ # "usdValue": "1023.08402268",
1612
+ # "walletBalance": "0.06488393",
1613
+ # "availableToWithdraw": "0.06488393",
1614
+ # "availableToBorrow": "2.5",
1615
+ # "borrowAmount": "0",
1616
+ # "accruedInterest": "0",
1617
+ # "totalOrderIM": "0",
1618
+ # "totalPositionIM": "0",
1619
+ # "totalPositionMM": "0",
1620
+ # "unrealisedPnl": "0",
1621
+ # "cumRealisedPnl": "0",
1622
+ # "bonus": "0"
1623
+ # },
1624
+ # {
1625
+ # "coin": "ETH",
1626
+ # "equity": "0",
1627
+ # "usdValue": "0",
1628
+ # "walletBalance": "0",
1629
+ # "availableToWithdraw": "0",
1630
+ # "availableToBorrow": "26",
1631
+ # "borrowAmount": "0",
1632
+ # "accruedInterest": "0",
1633
+ # "totalOrderIM": "0",
1634
+ # "totalPositionIM": "0",
1635
+ # "totalPositionMM": "0",
1636
+ # "unrealisedPnl": "0",
1637
+ # "cumRealisedPnl": "0",
1638
+ # "bonus": "0"
1639
+ # },
1640
+ # {
1641
+ # "coin": "USDT",
1642
+ # "equity": "11726.64664904",
1643
+ # "usdValue": "11613.58597018",
1644
+ # "walletBalance": "11728.54414904",
1645
+ # "availableToWithdraw": "11723.92075829",
1646
+ # "availableToBorrow": "2500000",
1647
+ # "borrowAmount": "0",
1648
+ # "accruedInterest": "0",
1649
+ # "totalOrderIM": "0",
1650
+ # "totalPositionIM": "2.72589075",
1651
+ # "totalPositionMM": "0.28576575",
1652
+ # "unrealisedPnl": "-1.8975",
1653
+ # "cumRealisedPnl": "0.64782276",
1654
+ # "bonus": "0"
1655
+ # },
1656
+ # {
1657
+ # "coin": "EOS3L",
1658
+ # "equity": "215.0570412",
1659
+ # "usdValue": "0",
1660
+ # "walletBalance": "215.0570412",
1661
+ # "availableToWithdraw": "215.0570412",
1662
+ # "availableToBorrow": "0",
1663
+ # "borrowAmount": "0",
1664
+ # "accruedInterest": "",
1665
+ # "totalOrderIM": "0",
1666
+ # "totalPositionIM": "0",
1667
+ # "totalPositionMM": "0",
1668
+ # "unrealisedPnl": "0",
1669
+ # "cumRealisedPnl": "0",
1670
+ # "bonus": "0"
1671
+ # },
1672
+ # {
1673
+ # "coin": "BIT",
1674
+ # "equity": "1.82",
1675
+ # "usdValue": "0.48758257",
1676
+ # "walletBalance": "1.82",
1677
+ # "availableToWithdraw": "1.82",
1678
+ # "availableToBorrow": "0",
1679
+ # "borrowAmount": "0",
1680
+ # "accruedInterest": "",
1681
+ # "totalOrderIM": "0",
1682
+ # "totalPositionIM": "0",
1683
+ # "totalPositionMM": "0",
1684
+ # "unrealisedPnl": "0",
1685
+ # "cumRealisedPnl": "0",
1686
+ # "bonus": "0"
1687
+ # }
1688
+ # ],
1689
+ # "accountType": "UNIFIED"
1690
+ # }
1691
+ # ]
1692
+ # }
1693
+ #
1694
+ if self.balance is None:
1695
+ self.balance = {}
1696
+ messageHash = 'balance'
1697
+ topic = self.safe_value(message, 'topic')
1698
+ info = None
1699
+ rawBalances = []
1700
+ account = None
1701
+ if topic == 'outboundAccountInfo':
1702
+ account = 'spot'
1703
+ data = self.safe_value(message, 'data', [])
1704
+ for i in range(0, len(data)):
1705
+ B = self.safe_value(data[i], 'B', [])
1706
+ rawBalances = self.array_concat(rawBalances, B)
1707
+ info = rawBalances
1708
+ if topic == 'wallet':
1709
+ data = self.safe_value(message, 'data', {})
1710
+ for i in range(0, len(data)):
1711
+ result = self.safe_value(data, 0, {})
1712
+ account = self.safe_string_lower(result, 'accountType')
1713
+ rawBalances = self.array_concat(rawBalances, self.safe_value(result, 'coin', []))
1714
+ info = data
1715
+ for i in range(0, len(rawBalances)):
1716
+ self.parse_ws_balance(rawBalances[i], account)
1717
+ if account is not None:
1718
+ if self.safe_value(self.balance, account) is None:
1719
+ self.balance[account] = {}
1720
+ self.balance[account]['info'] = info
1721
+ timestamp = self.safe_integer(message, 'ts')
1722
+ self.balance[account]['timestamp'] = timestamp
1723
+ self.balance[account]['datetime'] = self.iso8601(timestamp)
1724
+ self.balance[account] = self.safe_balance(self.balance[account])
1725
+ messageHash = 'balances:' + account
1726
+ client.resolve(self.balance[account], messageHash)
1727
+ else:
1728
+ self.balance['info'] = info
1729
+ timestamp = self.safe_integer(message, 'ts')
1730
+ self.balance['timestamp'] = timestamp
1731
+ self.balance['datetime'] = self.iso8601(timestamp)
1732
+ self.balance = self.safe_balance(self.balance)
1733
+ messageHash = 'balances'
1734
+ client.resolve(self.balance, messageHash)
1735
+
1736
+ def parse_ws_balance(self, balance, accountType=None):
1737
+ #
1738
+ # spot
1739
+ # {
1740
+ # "a": "USDT",
1741
+ # "f": "176.81254174",
1742
+ # "l": "201.575"
1743
+ # }
1744
+ # unified
1745
+ # {
1746
+ # "coin": "BTC",
1747
+ # "equity": "0.06488393",
1748
+ # "usdValue": "1023.08402268",
1749
+ # "walletBalance": "0.06488393",
1750
+ # "availableToWithdraw": "0.06488393",
1751
+ # "availableToBorrow": "2.5",
1752
+ # "borrowAmount": "0",
1753
+ # "accruedInterest": "0",
1754
+ # "totalOrderIM": "0",
1755
+ # "totalPositionIM": "0",
1756
+ # "totalPositionMM": "0",
1757
+ # "unrealisedPnl": "0",
1758
+ # "cumRealisedPnl": "0",
1759
+ # "bonus": "0"
1760
+ # }
1761
+ #
1762
+ account = self.account()
1763
+ currencyId = self.safe_string_2(balance, 'a', 'coin')
1764
+ code = self.safe_currency_code(currencyId)
1765
+ account['free'] = self.safe_string_n(balance, ['availableToWithdraw', 'f', 'free', 'availableToWithdraw'])
1766
+ account['used'] = self.safe_string_2(balance, 'l', 'locked')
1767
+ account['total'] = self.safe_string(balance, 'walletBalance')
1768
+ if accountType is not None:
1769
+ if self.safe_value(self.balance, accountType) is None:
1770
+ self.balance[accountType] = {}
1771
+ self.balance[accountType][code] = account
1772
+ else:
1773
+ self.balance[code] = account
1774
+
1775
+ async def watch_topics(self, url, messageHashes, topics, params={}):
1776
+ request: dict = {
1777
+ 'op': 'subscribe',
1778
+ 'req_id': self.request_id(),
1779
+ 'args': topics,
1780
+ }
1781
+ message = self.extend(request, params)
1782
+ return await self.watch_multiple(url, messageHashes, message, topics)
1783
+
1784
+ async def authenticate(self, url, params={}):
1785
+ self.check_required_credentials()
1786
+ messageHash = 'authenticated'
1787
+ client = self.client(url)
1788
+ future = client.future(messageHash)
1789
+ authenticated = self.safe_value(client.subscriptions, messageHash)
1790
+ if authenticated is None:
1791
+ expiresInt = self.milliseconds() + 10000
1792
+ expires = self.number_to_string(expiresInt)
1793
+ path = 'GET/realtime'
1794
+ auth = path + expires
1795
+ signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256, 'hex')
1796
+ request: dict = {
1797
+ 'op': 'auth',
1798
+ 'args': [
1799
+ self.apiKey, expires, signature,
1800
+ ],
1801
+ }
1802
+ message = self.extend(request, params)
1803
+ self.watch(url, messageHash, message, messageHash)
1804
+ return await future
1805
+
1806
+ def handle_error_message(self, client: Client, message):
1807
+ #
1808
+ # {
1809
+ # "success": False,
1810
+ # "ret_msg": "error:invalid op",
1811
+ # "conn_id": "5e079fdd-9c7f-404d-9dbf-969d650838b5",
1812
+ # "request": {op: '', args: null}
1813
+ # }
1814
+ #
1815
+ # auth error
1816
+ #
1817
+ # {
1818
+ # "success": False,
1819
+ # "ret_msg": "error:USVC1111",
1820
+ # "conn_id": "e73770fb-a0dc-45bd-8028-140e20958090",
1821
+ # "request": {
1822
+ # "op": "auth",
1823
+ # "args": [
1824
+ # "9rFT6uR4uz9Imkw4Wx",
1825
+ # "1653405853543",
1826
+ # "542e71bd85597b4db0290f0ce2d13ed1fd4bb5df3188716c1e9cc69a879f7889"
1827
+ # ]
1828
+ # }
1829
+ #
1830
+ # {code: '-10009', desc: "Invalid period!"}
1831
+ #
1832
+ # {
1833
+ # "reqId":"1",
1834
+ # "retCode":170131,
1835
+ # "retMsg":"Insufficient balance.",
1836
+ # "op":"order.create",
1837
+ # "data":{
1838
+ #
1839
+ # },
1840
+ # "header":{
1841
+ # "X-Bapi-Limit":"20",
1842
+ # "X-Bapi-Limit-Status":"19",
1843
+ # "X-Bapi-Limit-Reset-Timestamp":"1714236608944",
1844
+ # "Traceid":"3d7168a137bf32a947b7e5e6a575ac7f",
1845
+ # "Timenow":"1714236608946"
1846
+ # },
1847
+ # "connId":"cojifin88smerbj9t560-406"
1848
+ # }
1849
+ #
1850
+ code = self.safe_string_n(message, ['code', 'ret_code', 'retCode'])
1851
+ try:
1852
+ if code is not None and code != '0':
1853
+ feedback = self.id + ' ' + self.json(message)
1854
+ self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
1855
+ msg = self.safe_string_2(message, 'retMsg', 'ret_msg')
1856
+ self.throw_broadly_matched_exception(self.exceptions['broad'], msg, feedback)
1857
+ raise ExchangeError(feedback)
1858
+ success = self.safe_value(message, 'success')
1859
+ if success is not None and not success:
1860
+ ret_msg = self.safe_string(message, 'ret_msg')
1861
+ request = self.safe_value(message, 'request', {})
1862
+ op = self.safe_string(request, 'op')
1863
+ if op == 'auth':
1864
+ raise AuthenticationError('Authentication failed: ' + ret_msg)
1865
+ else:
1866
+ raise ExchangeError(self.id + ' ' + ret_msg)
1867
+ return False
1868
+ except Exception as error:
1869
+ if isinstance(error, AuthenticationError):
1870
+ messageHash = 'authenticated'
1871
+ client.reject(error, messageHash)
1872
+ if messageHash in client.subscriptions:
1873
+ del client.subscriptions[messageHash]
1874
+ else:
1875
+ messageHash = self.safe_string(message, 'reqId')
1876
+ client.reject(error, messageHash)
1877
+ return True
1878
+
1879
+ def handle_message(self, client: Client, message):
1880
+ if self.handle_error_message(client, message):
1881
+ return
1882
+ # contract pong
1883
+ ret_msg = self.safe_string(message, 'ret_msg')
1884
+ if ret_msg == 'pong':
1885
+ self.handle_pong(client, message)
1886
+ return
1887
+ # spot pong
1888
+ pong = self.safe_integer(message, 'pong')
1889
+ if pong is not None:
1890
+ self.handle_pong(client, message)
1891
+ return
1892
+ # pong
1893
+ event = self.safe_string(message, 'event')
1894
+ if event == 'sub':
1895
+ self.handle_subscription_status(client, message)
1896
+ return
1897
+ topic = self.safe_string_2(message, 'topic', 'op')
1898
+ methods: dict = {
1899
+ 'orderbook': self.handle_order_book,
1900
+ 'kline': self.handle_ohlcv,
1901
+ 'order': self.handle_order,
1902
+ 'stopOrder': self.handle_order,
1903
+ 'ticker': self.handle_ticker,
1904
+ 'trade': self.handle_trades,
1905
+ 'publicTrade': self.handle_trades,
1906
+ 'depth': self.handle_order_book,
1907
+ 'wallet': self.handle_balance,
1908
+ 'outboundAccountInfo': self.handle_balance,
1909
+ 'execution': self.handle_my_trades,
1910
+ 'ticketInfo': self.handle_my_trades,
1911
+ 'user.openapi.perp.trade': self.handle_my_trades,
1912
+ 'position': self.handle_positions,
1913
+ 'liquidation': self.handle_liquidation,
1914
+ 'pong': self.handle_pong,
1915
+ 'order.create': self.handle_order_ws,
1916
+ 'order.amend': self.handle_order_ws,
1917
+ 'order.cancel': self.handle_order_ws,
1918
+ 'auth': self.handle_authenticate,
1919
+ }
1920
+ exacMethod = self.safe_value(methods, topic)
1921
+ if exacMethod is not None:
1922
+ exacMethod(client, message)
1923
+ return
1924
+ keys = list(methods.keys())
1925
+ for i in range(0, len(keys)):
1926
+ key = keys[i]
1927
+ if topic.find(keys[i]) >= 0:
1928
+ method = methods[key]
1929
+ method(client, message)
1930
+ return
1931
+ # unified auth acknowledgement
1932
+ type = self.safe_string(message, 'type')
1933
+ if type == 'AUTH_RESP':
1934
+ self.handle_authenticate(client, message)
1935
+
1936
+ def ping(self, client):
1937
+ return {
1938
+ 'req_id': self.request_id(),
1939
+ 'op': 'ping',
1940
+ }
1941
+
1942
+ def handle_pong(self, client: Client, message):
1943
+ #
1944
+ # {
1945
+ # "success": True,
1946
+ # "ret_msg": "pong",
1947
+ # "conn_id": "db3158a0-8960-44b9-a9de-ac350ee13158",
1948
+ # "request": {op: "ping", args: null}
1949
+ # }
1950
+ #
1951
+ # {pong: 1653296711335}
1952
+ #
1953
+ client.lastPong = self.safe_integer(message, 'pong')
1954
+ return message
1955
+
1956
+ def handle_authenticate(self, client: Client, message):
1957
+ #
1958
+ # {
1959
+ # "success": True,
1960
+ # "ret_msg": '',
1961
+ # "op": "auth",
1962
+ # "conn_id": "ce3dpomvha7dha97tvp0-2xh"
1963
+ # }
1964
+ #
1965
+ # {
1966
+ # "retCode":0,
1967
+ # "retMsg":"OK",
1968
+ # "op":"auth",
1969
+ # "connId":"cojifin88smerbj9t560-404"
1970
+ # }
1971
+ #
1972
+ success = self.safe_value(message, 'success')
1973
+ code = self.safe_integer(message, 'retCode')
1974
+ messageHash = 'authenticated'
1975
+ if success or code == 0:
1976
+ future = self.safe_value(client.futures, messageHash)
1977
+ future.resolve(True)
1978
+ else:
1979
+ error = AuthenticationError(self.id + ' ' + self.json(message))
1980
+ client.reject(error, messageHash)
1981
+ if messageHash in client.subscriptions:
1982
+ del client.subscriptions[messageHash]
1983
+ return message
1984
+
1985
+ def handle_subscription_status(self, client: Client, message):
1986
+ #
1987
+ # {
1988
+ # "topic": "kline",
1989
+ # "event": "sub",
1990
+ # "params": {
1991
+ # "symbol": "LTCUSDT",
1992
+ # "binary": "false",
1993
+ # "klineType": "1m",
1994
+ # "symbolName": "LTCUSDT"
1995
+ # },
1996
+ # "code": "0",
1997
+ # "msg": "Success"
1998
+ # }
1999
+ #
2000
+ return message