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/okx.py ADDED
@@ -0,0 +1,1851 @@
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 hashlib
9
+ from ccxt.base.types import Balances, Int, Liquidation, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade
10
+ from ccxt.async_support.base.ws.client import Client
11
+ from typing import List
12
+ from ccxt.base.errors import ExchangeError
13
+ from ccxt.base.errors import AuthenticationError
14
+ from ccxt.base.errors import ArgumentsRequired
15
+ from ccxt.base.errors import BadRequest
16
+ from ccxt.base.errors import InvalidNonce
17
+
18
+
19
+ class okx(ccxt.async_support.okx):
20
+
21
+ def describe(self):
22
+ return self.deep_extend(super(okx, self).describe(), {
23
+ 'has': {
24
+ 'ws': True,
25
+ 'watchTicker': True,
26
+ 'watchTickers': True,
27
+ 'watchOrderBook': True,
28
+ 'watchTrades': True,
29
+ 'watchTradesForSymbols': True,
30
+ 'watchOrderBookForSymbols': True,
31
+ 'watchBalance': True,
32
+ 'watchLiquidations': 'emulated',
33
+ 'watchLiquidationsForSymbols': True,
34
+ 'watchMyLiquidations': 'emulated',
35
+ 'watchMyLiquidationsForSymbols': True,
36
+ 'watchOHLCV': True,
37
+ 'watchOHLCVForSymbols': True,
38
+ 'watchOrders': True,
39
+ 'watchMyTrades': True,
40
+ 'watchPositions': True,
41
+ 'watchFundingRate': True,
42
+ 'watchFundingRates': True,
43
+ 'createOrderWs': True,
44
+ 'editOrderWs': True,
45
+ 'cancelOrderWs': True,
46
+ 'cancelOrdersWs': True,
47
+ 'cancelAllOrdersWs': True,
48
+ },
49
+ 'urls': {
50
+ 'api': {
51
+ 'ws': 'wss://ws.okx.com:8443/ws/v5',
52
+ },
53
+ 'test': {
54
+ 'ws': 'wss://wspap.okx.com:8443/ws/v5',
55
+ },
56
+ },
57
+ 'options': {
58
+ 'watchOrderBook': {
59
+ #
60
+ # bbo-tbt
61
+ # 1. Newly added channel that sends tick-by-tick Level 1 data
62
+ # 2. All API users can subscribe
63
+ # 3. Public depth channel, verification not required
64
+ #
65
+ # books-l2-tbt
66
+ # 1. Only users who're VIP5 and above can subscribe
67
+ # 2. Identity verification required before subscription
68
+ #
69
+ # books50-l2-tbt
70
+ # 1. Only users who're VIP4 and above can subscribe
71
+ # 2. Identity verification required before subscription
72
+ #
73
+ # books
74
+ # 1. All API users can subscribe
75
+ # 2. Public depth channel, verification not required
76
+ #
77
+ # books5
78
+ # 1. All API users can subscribe
79
+ # 2. Public depth channel, verification not required
80
+ # 3. Data feeds will be delivered every 100ms(vs. every 200ms now)
81
+ #
82
+ 'depth': 'books',
83
+ },
84
+ 'watchBalance': 'spot', # margin, futures, swap
85
+ 'watchTicker': {
86
+ 'channel': 'tickers', # tickers, sprd-tickers, index-tickers, block-tickers
87
+ },
88
+ 'watchTickers': {
89
+ 'channel': 'tickers', # tickers, sprd-tickers, index-tickers, block-tickers
90
+ },
91
+ 'watchOrders': {
92
+ 'type': 'ANY', # SPOT, MARGIN, SWAP, FUTURES, OPTION, ANY
93
+ },
94
+ 'watchMyTrades': {
95
+ 'type': 'ANY', # SPOT, MARGIN, SWAP, FUTURES, OPTION, ANY
96
+ },
97
+ 'createOrderWs': {
98
+ 'op': 'batch-orders', # order, batch-orders
99
+ },
100
+ 'editOrderWs': {
101
+ 'op': 'amend-order', # amend-order, batch-amend-orders
102
+ },
103
+ 'ws': {
104
+ # 'inflate': True,
105
+ },
106
+ 'checksum': True,
107
+ },
108
+ 'streaming': {
109
+ # okex does not support built-in ws protocol-level ping-pong
110
+ # instead it requires a custom text-based ping-pong
111
+ 'ping': self.ping,
112
+ 'keepAlive': 20000,
113
+ },
114
+ })
115
+
116
+ def get_url(self, channel: str, access='public'):
117
+ # for context: https://www.okx.com/help-center/changes-to-v5-api-websocket-subscription-parameter-and-url
118
+ isSandbox = self.options['sandboxMode']
119
+ sandboxSuffix = '?brokerId=9999' if isSandbox else ''
120
+ isBusiness = (access == 'business')
121
+ isPublic = (access == 'public')
122
+ url = self.urls['api']['ws']
123
+ if isBusiness or (channel.find('candle') > -1) or (channel == 'orders-algo'):
124
+ return url + '/business' + sandboxSuffix
125
+ elif isPublic:
126
+ return url + '/public' + sandboxSuffix
127
+ return url + '/private' + sandboxSuffix
128
+
129
+ async def subscribe_multiple(self, access, channel, symbols: Strings = None, params={}):
130
+ await self.load_markets()
131
+ if symbols is None:
132
+ symbols = self.symbols
133
+ symbols = self.market_symbols(symbols)
134
+ url = self.get_url(channel, access)
135
+ messageHash = channel
136
+ args = []
137
+ messageHash += '::' + ','.join(symbols)
138
+ for i in range(0, len(symbols)):
139
+ marketId = self.market_id(symbols[i])
140
+ arg: dict = {
141
+ 'channel': channel,
142
+ 'instId': marketId,
143
+ }
144
+ args.append(self.extend(arg, params))
145
+ request: dict = {
146
+ 'op': 'subscribe',
147
+ 'args': args,
148
+ }
149
+ return await self.watch(url, messageHash, request, messageHash)
150
+
151
+ async def subscribe(self, access, messageHash, channel, symbol, params={}):
152
+ await self.load_markets()
153
+ url = self.get_url(channel, access)
154
+ firstArgument: dict = {
155
+ 'channel': channel,
156
+ }
157
+ if symbol is not None:
158
+ market = self.market(symbol)
159
+ messageHash += ':' + market['id']
160
+ firstArgument['instId'] = market['id']
161
+ request: dict = {
162
+ 'op': 'subscribe',
163
+ 'args': [
164
+ self.deep_extend(firstArgument, params),
165
+ ],
166
+ }
167
+ return await self.watch(url, messageHash, request, messageHash)
168
+
169
+ async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
170
+ """
171
+ get the list of most recent trades for a particular symbol
172
+ :param str symbol: unified symbol of the market to fetch trades for
173
+ :param int [since]: timestamp in ms of the earliest trade to fetch
174
+ :param int [limit]: the maximum amount of trades to fetch
175
+ :param dict [params]: extra parameters specific to the exchange API endpoint
176
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
177
+ """
178
+ return await self.watch_trades_for_symbols([symbol], since, limit, params)
179
+
180
+ async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
181
+ """
182
+ get the list of most recent trades for a particular symbol
183
+ :param str symbol: unified symbol of the market to fetch trades for
184
+ :param int [since]: timestamp in ms of the earliest trade to fetch
185
+ :param int [limit]: the maximum amount of trades to fetch
186
+ :param dict [params]: extra parameters specific to the exchange API endpoint
187
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
188
+ """
189
+ symbolsLength = len(symbols)
190
+ if symbolsLength == 0:
191
+ raise ArgumentsRequired(self.id + ' watchTradesForSymbols() requires a non-empty array of symbols')
192
+ await self.load_markets()
193
+ symbols = self.market_symbols(symbols)
194
+ channel = 'trades'
195
+ topics = []
196
+ messageHashes = []
197
+ for i in range(0, len(symbols)):
198
+ symbol = symbols[i]
199
+ messageHashes.append(channel + ':' + symbol)
200
+ marketId = self.market_id(symbol)
201
+ topic: dict = {
202
+ 'channel': channel,
203
+ 'instId': marketId,
204
+ }
205
+ topics.append(topic)
206
+ request: dict = {
207
+ 'op': 'subscribe',
208
+ 'args': topics,
209
+ }
210
+ url = self.get_url(channel, 'public')
211
+ trades = await self.watch_multiple(url, messageHashes, request, messageHashes)
212
+ if self.newUpdates:
213
+ first = self.safe_value(trades, 0)
214
+ tradeSymbol = self.safe_string(first, 'symbol')
215
+ limit = trades.getLimit(tradeSymbol, limit)
216
+ return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
217
+
218
+ def handle_trades(self, client: Client, message):
219
+ #
220
+ # {
221
+ # "arg": {channel: "trades", instId: "BTC-USDT"},
222
+ # "data": [
223
+ # {
224
+ # "instId": "BTC-USDT",
225
+ # "tradeId": "216970876",
226
+ # "px": "31684.5",
227
+ # "sz": "0.00001186",
228
+ # "side": "buy",
229
+ # "ts": "1626531038288"
230
+ # }
231
+ # ]
232
+ # }
233
+ #
234
+ arg = self.safe_value(message, 'arg', {})
235
+ channel = self.safe_string(arg, 'channel')
236
+ marketId = self.safe_string(arg, 'instId')
237
+ symbol = self.safe_symbol(marketId)
238
+ data = self.safe_value(message, 'data', [])
239
+ tradesLimit = self.safe_integer(self.options, 'tradesLimit', 1000)
240
+ for i in range(0, len(data)):
241
+ trade = self.parse_trade(data[i])
242
+ messageHash = channel + ':' + symbol
243
+ stored = self.safe_value(self.trades, symbol)
244
+ if stored is None:
245
+ stored = ArrayCache(tradesLimit)
246
+ self.trades[symbol] = stored
247
+ stored.append(trade)
248
+ client.resolve(stored, messageHash)
249
+
250
+ async def watch_funding_rate(self, symbol: str, params={}) -> FundingRate:
251
+ """
252
+ watch the current funding rate
253
+ :see: https://www.okx.com/docs-v5/en/#public-data-websocket-funding-rate-channel
254
+ :param str symbol: unified market symbol
255
+ :param dict [params]: extra parameters specific to the exchange API endpoint
256
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
257
+ """
258
+ symbol = self.symbol(symbol)
259
+ fr = await self.watch_funding_rates([symbol], params)
260
+ return fr[symbol]
261
+
262
+ async def watch_funding_rates(self, symbols: List[str], params={}) -> FundingRates:
263
+ """
264
+ watch the funding rate for multiple markets
265
+ :see: https://www.okx.com/docs-v5/en/#public-data-websocket-funding-rate-channel
266
+ :param str[] symbols: list of unified market symbols
267
+ :param dict [params]: extra parameters specific to the exchange API endpoint
268
+ :returns dict: a dictionary of `funding rates structures <https://docs.ccxt.com/#/?id=funding-rates-structure>`, indexe by market symbols
269
+ """
270
+ await self.load_markets()
271
+ symbols = self.market_symbols(symbols)
272
+ channel = 'funding-rate'
273
+ topics = []
274
+ messageHashes = []
275
+ for i in range(0, len(symbols)):
276
+ symbol = symbols[i]
277
+ messageHashes.append(channel + ':' + symbol)
278
+ marketId = self.market_id(symbol)
279
+ topic: dict = {
280
+ 'channel': channel,
281
+ 'instId': marketId,
282
+ }
283
+ topics.append(topic)
284
+ request: dict = {
285
+ 'op': 'subscribe',
286
+ 'args': topics,
287
+ }
288
+ url = self.get_url(channel, 'public')
289
+ fundingRate = await self.watch_multiple(url, messageHashes, request, messageHashes)
290
+ if self.newUpdates:
291
+ symbol = self.safe_string(fundingRate, 'symbol')
292
+ result: dict = {}
293
+ result[symbol] = fundingRate
294
+ return result
295
+ return self.filter_by_array(self.fundingRates, 'symbol', symbols)
296
+
297
+ def handle_funding_rate(self, client: Client, message):
298
+ #
299
+ # "data":[
300
+ # {
301
+ # "fundingRate":"0.0001875391284828",
302
+ # "fundingTime":"1700726400000",
303
+ # "instId":"BTC-USD-SWAP",
304
+ # "instType":"SWAP",
305
+ # "method": "next_period",
306
+ # "maxFundingRate":"0.00375",
307
+ # "minFundingRate":"-0.00375",
308
+ # "nextFundingRate":"0.0002608059239328",
309
+ # "nextFundingTime":"1700755200000",
310
+ # "premium": "0.0001233824646391",
311
+ # "settFundingRate":"0.0001699799259033",
312
+ # "settState":"settled",
313
+ # "ts":"1700724675402"
314
+ # }
315
+ # ]
316
+ #
317
+ data = self.safe_list(message, 'data', [])
318
+ for i in range(0, len(data)):
319
+ rawfr = data[i]
320
+ fundingRate = self.parse_funding_rate(rawfr)
321
+ symbol = fundingRate['symbol']
322
+ self.fundingRates[symbol] = fundingRate
323
+ client.resolve(fundingRate, 'funding-rate' + ':' + fundingRate['symbol'])
324
+
325
+ async def watch_ticker(self, symbol: str, params={}) -> Ticker:
326
+ """
327
+ :see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-ws-tickers-channel
328
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
329
+ :param str symbol: unified symbol of the market to fetch the ticker for
330
+ :param dict [params]: extra parameters specific to the exchange API endpoint
331
+ :param str [params.channel]: the channel to subscribe to, tickers by default. Can be tickers, sprd-tickers, index-tickers, block-tickers
332
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
333
+ """
334
+ channel = None
335
+ channel, params = self.handle_option_and_params(params, 'watchTicker', 'channel', 'tickers')
336
+ params['channel'] = channel
337
+ ticker = await self.watch_tickers([symbol], params)
338
+ return self.safe_value(ticker, symbol)
339
+
340
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
341
+ """
342
+ :see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-ws-tickers-channel
343
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
344
+ :param str[] [symbols]: unified symbol of the market to fetch the ticker for
345
+ :param dict [params]: extra parameters specific to the exchange API endpoint
346
+ :param str [params.channel]: the channel to subscribe to, tickers by default. Can be tickers, sprd-tickers, index-tickers, block-tickers
347
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
348
+ """
349
+ if self.is_empty(symbols):
350
+ raise ArgumentsRequired(self.id + ' watchTickers requires a list of symbols')
351
+ channel = None
352
+ channel, params = self.handle_option_and_params(params, 'watchTickers', 'channel', 'tickers')
353
+ newTickers = await self.subscribe_multiple('public', channel, symbols, params)
354
+ if self.newUpdates:
355
+ return newTickers
356
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
357
+
358
+ def handle_ticker(self, client: Client, message):
359
+ #
360
+ # {
361
+ # "arg": {channel: "tickers", instId: "BTC-USDT"},
362
+ # "data": [
363
+ # {
364
+ # "instType": "SPOT",
365
+ # "instId": "BTC-USDT",
366
+ # "last": "31500.1",
367
+ # "lastSz": "0.00001754",
368
+ # "askPx": "31500.1",
369
+ # "askSz": "0.00998144",
370
+ # "bidPx": "31500",
371
+ # "bidSz": "3.05652439",
372
+ # "open24h": "31697",
373
+ # "high24h": "32248",
374
+ # "low24h": "31165.6",
375
+ # "sodUtc0": "31385.5",
376
+ # "sodUtc8": "32134.9",
377
+ # "volCcy24h": "503403597.38138519",
378
+ # "vol24h": "15937.10781721",
379
+ # "ts": "1626526618762"
380
+ # }
381
+ # ]
382
+ # }
383
+ #
384
+ arg = self.safe_value(message, 'arg', {})
385
+ channel = self.safe_string(arg, 'channel')
386
+ data = self.safe_value(message, 'data', [])
387
+ newTickers = []
388
+ for i in range(0, len(data)):
389
+ ticker = self.parse_ticker(data[i])
390
+ symbol = ticker['symbol']
391
+ self.tickers[symbol] = ticker
392
+ newTickers.append(ticker)
393
+ messageHashes = self.find_message_hashes(client, channel + '::')
394
+ for i in range(0, len(messageHashes)):
395
+ messageHash = messageHashes[i]
396
+ parts = messageHash.split('::')
397
+ symbolsString = parts[1]
398
+ symbols = symbolsString.split(',')
399
+ tickers = self.filter_by_array(newTickers, 'symbol', symbols)
400
+ tickersSymbols = list(tickers.keys())
401
+ numTickers = len(tickersSymbols)
402
+ if numTickers > 0:
403
+ client.resolve(tickers, messageHash)
404
+ return message
405
+
406
+ async def watch_liquidations_for_symbols(self, symbols: List[str] = None, since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
407
+ """
408
+ watch the public liquidations of a trading pair
409
+ :see: https://www.okx.com/docs-v5/en/#public-data-websocket-liquidation-orders-channel
410
+ :param str symbol: unified CCXT market symbol
411
+ :param int [since]: the earliest time in ms to fetch liquidations for
412
+ :param int [limit]: the maximum number of liquidation structures to retrieve
413
+ :param dict [params]: exchange specific parameters for the okx api endpoint
414
+ :returns dict: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
415
+ """
416
+ await self.load_markets()
417
+ symbols = self.market_symbols(symbols, None, True, True)
418
+ messageHash = 'liquidations'
419
+ if symbols is not None:
420
+ messageHash += '::' + ','.join(symbols)
421
+ market = self.get_market_from_symbols(symbols)
422
+ type = None
423
+ type, params = self.handle_market_type_and_params('watchliquidationsForSymbols', market, params)
424
+ channel = 'liquidation-orders'
425
+ if type == 'spot':
426
+ type = 'SWAP'
427
+ elif type == 'future':
428
+ type = 'futures'
429
+ uppercaseType = type.upper()
430
+ request = {
431
+ 'instType': uppercaseType,
432
+ }
433
+ newLiquidations = await self.subscribe('public', messageHash, channel, None, self.extend(request, params))
434
+ if self.newUpdates:
435
+ return newLiquidations
436
+ return self.filter_by_symbols_since_limit(self.liquidations, symbols, since, limit, True)
437
+
438
+ def handle_liquidation(self, client: Client, message):
439
+ #
440
+ # {
441
+ # "arg": {
442
+ # "channel": "liquidation-orders",
443
+ # "instType": "SWAP"
444
+ # },
445
+ # "data": [
446
+ # {
447
+ # "details": [
448
+ # {
449
+ # "bkLoss": "0",
450
+ # "bkPx": "0.007831",
451
+ # "ccy": "",
452
+ # "posSide": "short",
453
+ # "side": "buy",
454
+ # "sz": "13",
455
+ # "ts": "1692266434010"
456
+ # }
457
+ # ],
458
+ # "instFamily": "IOST-USDT",
459
+ # "instId": "IOST-USDT-SWAP",
460
+ # "instType": "SWAP",
461
+ # "uly": "IOST-USDT"
462
+ # }
463
+ # ]
464
+ # }
465
+ #
466
+ rawLiquidations = self.safe_list(message, 'data', [])
467
+ for i in range(0, len(rawLiquidations)):
468
+ rawLiquidation = rawLiquidations[i]
469
+ liquidation = self.parse_ws_liquidation(rawLiquidation)
470
+ symbol = self.safe_string(liquidation, 'symbol')
471
+ liquidations = self.safe_value(self.liquidations, symbol)
472
+ if liquidations is None:
473
+ limit = self.safe_integer(self.options, 'liquidationsLimit', 1000)
474
+ liquidations = ArrayCache(limit)
475
+ liquidations.append(liquidation)
476
+ self.liquidations[symbol] = liquidations
477
+ client.resolve([liquidation], 'liquidations')
478
+ client.resolve([liquidation], 'liquidations::' + symbol)
479
+
480
+ async def watch_my_liquidations_for_symbols(self, symbols: List[str] = None, since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
481
+ """
482
+ watch the private liquidations of a trading pair
483
+ :see: https://www.okx.com/docs-v5/en/#trading-account-websocket-balance-and-position-channel
484
+ :param str symbol: unified CCXT market symbol
485
+ :param int [since]: the earliest time in ms to fetch liquidations for
486
+ :param int [limit]: the maximum number of liquidation structures to retrieve
487
+ :param dict [params]: exchange specific parameters for the okx api endpoint
488
+ :returns dict: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
489
+ """
490
+ await self.load_markets()
491
+ isStop = self.safe_value_2(params, 'stop', 'trigger', False)
492
+ params = self.omit(params, ['stop', 'trigger'])
493
+ await self.authenticate({'access': 'business' if isStop else 'private'})
494
+ symbols = self.market_symbols(symbols, None, True, True)
495
+ messageHash = 'myLiquidations'
496
+ if symbols is not None:
497
+ messageHash += '::' + ','.join(symbols)
498
+ channel = 'balance_and_position'
499
+ newLiquidations = await self.subscribe('private', messageHash, channel, None, params)
500
+ if self.newUpdates:
501
+ return newLiquidations
502
+ return self.filter_by_symbols_since_limit(self.liquidations, symbols, since, limit, True)
503
+
504
+ def handle_my_liquidation(self, client: Client, message):
505
+ #
506
+ # {
507
+ # "arg": {
508
+ # "channel": "balance_and_position",
509
+ # "uid": "77982378738415879"
510
+ # },
511
+ # "data": [{
512
+ # "pTime": "1597026383085",
513
+ # "eventType": "snapshot",
514
+ # "balData": [{
515
+ # "ccy": "BTC",
516
+ # "cashBal": "1",
517
+ # "uTime": "1597026383085"
518
+ # }],
519
+ # "posData": [{
520
+ # "posId": "1111111111",
521
+ # "tradeId": "2",
522
+ # "instId": "BTC-USD-191018",
523
+ # "instType": "FUTURES",
524
+ # "mgnMode": "cross",
525
+ # "posSide": "long",
526
+ # "pos": "10",
527
+ # "ccy": "BTC",
528
+ # "posCcy": "",
529
+ # "avgPx": "3320",
530
+ # "uTIme": "1597026383085"
531
+ # }],
532
+ # "trades": [{
533
+ # "instId": "BTC-USD-191018",
534
+ # "tradeId": "2",
535
+ # }]
536
+ # }]
537
+ # }
538
+ #
539
+ rawLiquidations = self.safe_list(message, 'data', [])
540
+ for i in range(0, len(rawLiquidations)):
541
+ rawLiquidation = rawLiquidations[i]
542
+ eventType = self.safe_string(rawLiquidation, 'eventType')
543
+ if eventType != 'liquidation':
544
+ return
545
+ liquidation = self.parse_ws_my_liquidation(rawLiquidation)
546
+ symbol = self.safe_string(liquidation, 'symbol')
547
+ liquidations = self.safe_value(self.liquidations, symbol)
548
+ if liquidations is None:
549
+ limit = self.safe_integer(self.options, 'myLiquidationsLimit', 1000)
550
+ liquidations = ArrayCache(limit)
551
+ liquidations.append(liquidation)
552
+ self.liquidations[symbol] = liquidations
553
+ client.resolve([liquidation], 'myLiquidations')
554
+ client.resolve([liquidation], 'myLiquidations::' + symbol)
555
+
556
+ def parse_ws_my_liquidation(self, liquidation, market=None):
557
+ #
558
+ # {
559
+ # "pTime": "1597026383085",
560
+ # "eventType": "snapshot",
561
+ # "balData": [{
562
+ # "ccy": "BTC",
563
+ # "cashBal": "1",
564
+ # "uTime": "1597026383085"
565
+ # }],
566
+ # "posData": [{
567
+ # "posId": "1111111111",
568
+ # "tradeId": "2",
569
+ # "instId": "BTC-USD-191018",
570
+ # "instType": "FUTURES",
571
+ # "mgnMode": "cross",
572
+ # "posSide": "long",
573
+ # "pos": "10",
574
+ # "ccy": "BTC",
575
+ # "posCcy": "",
576
+ # "avgPx": "3320",
577
+ # "uTIme": "1597026383085"
578
+ # }],
579
+ # "trades": [{
580
+ # "instId": "BTC-USD-191018",
581
+ # "tradeId": "2",
582
+ # }]
583
+ # }
584
+ #
585
+ posData = self.safe_list(liquidation, 'posData', [])
586
+ firstPosData = self.safe_dict(posData, 0, {})
587
+ marketId = self.safe_string(firstPosData, 'instId')
588
+ market = self.safe_market(marketId, market)
589
+ timestamp = self.safe_integer(firstPosData, 'uTIme')
590
+ return self.safe_liquidation({
591
+ 'info': liquidation,
592
+ 'symbol': self.safe_symbol(marketId, market),
593
+ 'contracts': self.safe_number(firstPosData, 'pos'),
594
+ 'contractSize': self.safe_number(market, 'contractSize'),
595
+ 'price': self.safe_number(liquidation, 'avgPx'),
596
+ 'baseValue': None,
597
+ 'quoteValue': None,
598
+ 'timestamp': timestamp,
599
+ 'datetime': self.iso8601(timestamp),
600
+ })
601
+
602
+ def parse_ws_liquidation(self, liquidation, market=None):
603
+ #
604
+ # public liquidation
605
+ # {
606
+ # "details": [
607
+ # {
608
+ # "bkLoss": "0",
609
+ # "bkPx": "0.007831",
610
+ # "ccy": "",
611
+ # "posSide": "short",
612
+ # "side": "buy",
613
+ # "sz": "13",
614
+ # "ts": "1692266434010"
615
+ # }
616
+ # ],
617
+ # "instFamily": "IOST-USDT",
618
+ # "instId": "IOST-USDT-SWAP",
619
+ # "instType": "SWAP",
620
+ # "uly": "IOST-USDT"
621
+ # }
622
+ #
623
+ details = self.safe_list(liquidation, 'details', [])
624
+ liquidationDetails = self.safe_dict(details, 0, {})
625
+ marketId = self.safe_string(liquidation, 'instId')
626
+ market = self.safe_market(marketId, market)
627
+ timestamp = self.safe_integer(liquidationDetails, 'ts')
628
+ return self.safe_liquidation({
629
+ 'info': liquidation,
630
+ 'symbol': self.safe_symbol(marketId, market),
631
+ 'contracts': self.safe_number(liquidationDetails, 'sz'),
632
+ 'contractSize': self.safe_number(market, 'contractSize'),
633
+ 'price': self.safe_number(liquidationDetails, 'bkPx'),
634
+ 'baseValue': None,
635
+ 'quoteValue': None,
636
+ 'timestamp': timestamp,
637
+ 'datetime': self.iso8601(timestamp),
638
+ })
639
+
640
+ async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
641
+ """
642
+ watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
643
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
644
+ :param str timeframe: the length of time each candle represents
645
+ :param int [since]: timestamp in ms of the earliest candle to fetch
646
+ :param int [limit]: the maximum amount of candles to fetch
647
+ :param dict [params]: extra parameters specific to the exchange API endpoint
648
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
649
+ """
650
+ await self.load_markets()
651
+ symbol = self.symbol(symbol)
652
+ interval = self.safe_string(self.timeframes, timeframe, timeframe)
653
+ name = 'candle' + interval
654
+ ohlcv = await self.subscribe('public', name, name, symbol, params)
655
+ if self.newUpdates:
656
+ limit = ohlcv.getLimit(symbol, limit)
657
+ return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
658
+
659
+ async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}):
660
+ """
661
+ watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
662
+ :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
663
+ :param int [since]: timestamp in ms of the earliest candle to fetch
664
+ :param int [limit]: the maximum amount of candles to fetch
665
+ :param dict [params]: extra parameters specific to the exchange API endpoint
666
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
667
+ """
668
+ symbolsLength = len(symbolsAndTimeframes)
669
+ if symbolsLength == 0 or not isinstance(symbolsAndTimeframes[0], list):
670
+ raise ArgumentsRequired(self.id + " watchOHLCVForSymbols() requires a an array of symbols and timeframes, like [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]")
671
+ await self.load_markets()
672
+ topics = []
673
+ messageHashes = []
674
+ for i in range(0, len(symbolsAndTimeframes)):
675
+ symbolAndTimeframe = symbolsAndTimeframes[i]
676
+ sym = symbolAndTimeframe[0]
677
+ tf = symbolAndTimeframe[1]
678
+ marketId = self.market_id(sym)
679
+ interval = self.safe_string(self.timeframes, tf, tf)
680
+ channel = 'candle' + interval
681
+ topic: dict = {
682
+ 'channel': channel,
683
+ 'instId': marketId,
684
+ }
685
+ topics.append(topic)
686
+ messageHashes.append('multi:' + channel + ':' + sym)
687
+ request: dict = {
688
+ 'op': 'subscribe',
689
+ 'args': topics,
690
+ }
691
+ url = self.get_url('candle', 'public')
692
+ symbol, timeframe, candles = await self.watch_multiple(url, messageHashes, request, messageHashes)
693
+ if self.newUpdates:
694
+ limit = candles.getLimit(symbol, limit)
695
+ filtered = self.filter_by_since_limit(candles, since, limit, 0, True)
696
+ return self.create_ohlcv_object(symbol, timeframe, filtered)
697
+
698
+ def handle_ohlcv(self, client: Client, message):
699
+ #
700
+ # {
701
+ # "arg": {channel: "candle1m", instId: "BTC-USDT"},
702
+ # "data": [
703
+ # [
704
+ # "1626690720000",
705
+ # "31334",
706
+ # "31334",
707
+ # "31334",
708
+ # "31334",
709
+ # "0.0077",
710
+ # "241.2718"
711
+ # ]
712
+ # ]
713
+ # }
714
+ #
715
+ arg = self.safe_value(message, 'arg', {})
716
+ channel = self.safe_string(arg, 'channel')
717
+ data = self.safe_value(message, 'data', [])
718
+ marketId = self.safe_string(arg, 'instId')
719
+ market = self.safe_market(marketId)
720
+ symbol = market['symbol']
721
+ interval = channel.replace('candle', '')
722
+ # use a reverse lookup in a static map instead
723
+ timeframe = self.find_timeframe(interval)
724
+ for i in range(0, len(data)):
725
+ parsed = self.parse_ohlcv(data[i], market)
726
+ self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
727
+ stored = self.safe_value(self.ohlcvs[symbol], timeframe)
728
+ if stored is None:
729
+ limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
730
+ stored = ArrayCacheByTimestamp(limit)
731
+ self.ohlcvs[symbol][timeframe] = stored
732
+ stored.append(parsed)
733
+ messageHash = channel + ':' + market['id']
734
+ client.resolve(stored, messageHash)
735
+ # for multiOHLCV we need special object, to other "multi"
736
+ # methods, because OHLCV response item does not contain symbol
737
+ # or timeframe, thus otherwise it would be unrecognizable
738
+ messageHashForMulti = 'multi:' + channel + ':' + symbol
739
+ client.resolve([symbol, timeframe, stored], messageHashForMulti)
740
+
741
+ async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
742
+ """
743
+ :see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-ws-order-book-channel
744
+ watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
745
+ :param str symbol: unified symbol of the market to fetch the order book for
746
+ :param int [limit]: the maximum amount of order book entries to return
747
+ :param dict [params]: extra parameters specific to the exchange API endpoint
748
+ :param str [params.depth]: okx order book depth, can be books, books5, books-l2-tbt, books50-l2-tbt, bbo-tbt
749
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
750
+ """
751
+ #
752
+ # bbo-tbt
753
+ # 1. Newly added channel that sends tick-by-tick Level 1 data
754
+ # 2. All API users can subscribe
755
+ # 3. Public depth channel, verification not required
756
+ #
757
+ # books-l2-tbt
758
+ # 1. Only users who're VIP5 and above can subscribe
759
+ # 2. Identity verification required before subscription
760
+ #
761
+ # books50-l2-tbt
762
+ # 1. Only users who're VIP4 and above can subscribe
763
+ # 2. Identity verification required before subscription
764
+ #
765
+ # books
766
+ # 1. All API users can subscribe
767
+ # 2. Public depth channel, verification not required
768
+ #
769
+ # books5
770
+ # 1. All API users can subscribe
771
+ # 2. Public depth channel, verification not required
772
+ # 3. Data feeds will be delivered every 100ms(vs. every 200ms now)
773
+ #
774
+ return await self.watch_order_book_for_symbols([symbol], limit, params)
775
+
776
+ async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
777
+ """
778
+ :see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-ws-order-book-channel
779
+ watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
780
+ :param str[] symbols: unified array of symbols
781
+ :param int [limit]: 1,5, 400, 50(l2-tbt, vip4+) or 40000(vip5+) the maximum amount of order book entries to return
782
+ :param dict [params]: extra parameters specific to the exchange API endpoint
783
+ :param str [params.depth]: okx order book depth, can be books, books5, books-l2-tbt, books50-l2-tbt, bbo-tbt
784
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
785
+ """
786
+ await self.load_markets()
787
+ symbols = self.market_symbols(symbols)
788
+ depth = None
789
+ depth, params = self.handle_option_and_params(params, 'watchOrderBook', 'depth', 'books')
790
+ if limit is not None:
791
+ if limit == 1:
792
+ depth = 'bbo-tbt'
793
+ elif limit > 1 and limit <= 5:
794
+ depth = 'books5'
795
+ elif limit == 50:
796
+ depth = 'books50-l2-tbt' # Make sure you have VIP4 and above
797
+ elif limit == 400:
798
+ depth = 'books'
799
+ if (depth == 'books-l2-tbt') or (depth == 'books50-l2-tbt'):
800
+ if not self.check_required_credentials(False):
801
+ raise AuthenticationError(self.id + ' watchOrderBook/watchOrderBookForSymbols requires authentication for self depth. Add credentials or change the depth option to books or books5')
802
+ await self.authenticate({'access': 'public'})
803
+ topics = []
804
+ messageHashes = []
805
+ for i in range(0, len(symbols)):
806
+ symbol = symbols[i]
807
+ messageHashes.append(depth + ':' + symbol)
808
+ marketId = self.market_id(symbol)
809
+ topic: dict = {
810
+ 'channel': depth,
811
+ 'instId': marketId,
812
+ }
813
+ topics.append(topic)
814
+ request: dict = {
815
+ 'op': 'subscribe',
816
+ 'args': topics,
817
+ }
818
+ url = self.get_url(depth, 'public')
819
+ orderbook = await self.watch_multiple(url, messageHashes, request, messageHashes)
820
+ return orderbook.limit()
821
+
822
+ def handle_delta(self, bookside, delta):
823
+ #
824
+ # [
825
+ # "31685", # price
826
+ # "0.78069158", # amount
827
+ # "0", # liquidated orders
828
+ # "17" # orders
829
+ # ]
830
+ #
831
+ price = self.safe_float(delta, 0)
832
+ amount = self.safe_float(delta, 1)
833
+ bookside.store(price, amount)
834
+
835
+ def handle_deltas(self, bookside, deltas):
836
+ for i in range(0, len(deltas)):
837
+ self.handle_delta(bookside, deltas[i])
838
+
839
+ def handle_order_book_message(self, client: Client, message, orderbook, messageHash):
840
+ #
841
+ # {
842
+ # "asks": [
843
+ # ['31738.3', '0.05973179', "0", "3"],
844
+ # ['31738.5', '0.11035404', "0", "2"],
845
+ # ['31739.6', '0.01', "0", "1"],
846
+ # ],
847
+ # "bids": [
848
+ # ['31738.2', '0.67557666', "0", "9"],
849
+ # ['31738', '0.02466947', "0", "2"],
850
+ # ['31736.3', '0.01705046', "0", "2"],
851
+ # ],
852
+ # "instId": "BTC-USDT",
853
+ # "ts": "1626537446491"
854
+ # }
855
+ #
856
+ asks = self.safe_value(message, 'asks', [])
857
+ bids = self.safe_value(message, 'bids', [])
858
+ storedAsks = orderbook['asks']
859
+ storedBids = orderbook['bids']
860
+ self.handle_deltas(storedAsks, asks)
861
+ self.handle_deltas(storedBids, bids)
862
+ marketId = self.safe_string(message, 'instId')
863
+ symbol = self.safe_symbol(marketId)
864
+ checksum = self.safe_bool(self.options, 'checksum', True)
865
+ if checksum:
866
+ asksLength = len(storedAsks)
867
+ bidsLength = len(storedBids)
868
+ payloadArray = []
869
+ for i in range(0, 25):
870
+ if i < bidsLength:
871
+ payloadArray.append(self.number_to_string(storedBids[i][0]))
872
+ payloadArray.append(self.number_to_string(storedBids[i][1]))
873
+ if i < asksLength:
874
+ payloadArray.append(self.number_to_string(storedAsks[i][0]))
875
+ payloadArray.append(self.number_to_string(storedAsks[i][1]))
876
+ payload = ':'.join(payloadArray)
877
+ responseChecksum = self.safe_integer(message, 'checksum')
878
+ localChecksum = self.crc32(payload, True)
879
+ if responseChecksum != localChecksum:
880
+ error = InvalidNonce(self.id + ' invalid checksum')
881
+ del client.subscriptions[messageHash]
882
+ del self.orderbooks[symbol]
883
+ client.reject(error, messageHash)
884
+ timestamp = self.safe_integer(message, 'ts')
885
+ orderbook['timestamp'] = timestamp
886
+ orderbook['datetime'] = self.iso8601(timestamp)
887
+ return orderbook
888
+
889
+ def handle_order_book(self, client: Client, message):
890
+ #
891
+ # snapshot
892
+ #
893
+ # {
894
+ # "arg": {channel: 'books-l2-tbt', instId: "BTC-USDT"},
895
+ # "action": "snapshot",
896
+ # "data": [
897
+ # {
898
+ # "asks": [
899
+ # ['31685', '0.78069158', "0", "17"],
900
+ # ['31685.1', '0.0001', "0", "1"],
901
+ # ['31685.6', '0.04543165', "0", "1"],
902
+ # ],
903
+ # "bids": [
904
+ # ['31684.9', '0.01', "0", "1"],
905
+ # ['31682.9', '0.0001', "0", "1"],
906
+ # ['31680.7', '0.01', "0", "1"],
907
+ # ],
908
+ # "ts": "1626532416403",
909
+ # "checksum": -1023440116
910
+ # }
911
+ # ]
912
+ # }
913
+ #
914
+ # update
915
+ #
916
+ # {
917
+ # "arg": {channel: 'books-l2-tbt', instId: "BTC-USDT"},
918
+ # "action": "update",
919
+ # "data": [
920
+ # {
921
+ # "asks": [
922
+ # ['31657.7', '0', "0", "0"],
923
+ # ['31659.7', '0.01', "0", "1"],
924
+ # ['31987.3', '0.01', "0", "1"]
925
+ # ],
926
+ # "bids": [
927
+ # ['31642.9', '0.50296385', "0", "4"],
928
+ # ['31639.9', '0', "0", "0"],
929
+ # ['31638.7', '0.01', "0", "1"],
930
+ # ],
931
+ # "ts": "1626535709008",
932
+ # "checksum": 830931827
933
+ # }
934
+ # ]
935
+ # }
936
+ #
937
+ # books5
938
+ #
939
+ # {
940
+ # "arg": {channel: "books5", instId: "BTC-USDT"},
941
+ # "data": [
942
+ # {
943
+ # "asks": [
944
+ # ['31738.3', '0.05973179', "0", "3"],
945
+ # ['31738.5', '0.11035404', "0", "2"],
946
+ # ['31739.6', '0.01', "0", "1"],
947
+ # ],
948
+ # "bids": [
949
+ # ['31738.2', '0.67557666', "0", "9"],
950
+ # ['31738', '0.02466947', "0", "2"],
951
+ # ['31736.3', '0.01705046', "0", "2"],
952
+ # ],
953
+ # "instId": "BTC-USDT",
954
+ # "ts": "1626537446491"
955
+ # }
956
+ # ]
957
+ # }
958
+ #
959
+ # bbo-tbt
960
+ #
961
+ # {
962
+ # "arg":{
963
+ # "channel":"bbo-tbt",
964
+ # "instId":"BTC-USDT"
965
+ # },
966
+ # "data":[
967
+ # {
968
+ # "asks":[["36232.2","1.8826134","0","17"]],
969
+ # "bids":[["36232.1","0.00572212","0","2"]],
970
+ # "ts":"1651826598363"
971
+ # }
972
+ # ]
973
+ # }
974
+ #
975
+ arg = self.safe_dict(message, 'arg', {})
976
+ channel = self.safe_string(arg, 'channel')
977
+ action = self.safe_string(message, 'action')
978
+ data = self.safe_list(message, 'data', [])
979
+ marketId = self.safe_string(arg, 'instId')
980
+ market = self.safe_market(marketId)
981
+ symbol = market['symbol']
982
+ depths: dict = {
983
+ 'bbo-tbt': 1,
984
+ 'books': 400,
985
+ 'books5': 5,
986
+ 'books-l2-tbt': 400,
987
+ 'books50-l2-tbt': 50,
988
+ }
989
+ limit = self.safe_integer(depths, channel)
990
+ messageHash = channel + ':' + symbol
991
+ if action == 'snapshot':
992
+ for i in range(0, len(data)):
993
+ update = data[i]
994
+ orderbook = self.order_book({}, limit)
995
+ self.orderbooks[symbol] = orderbook
996
+ orderbook['symbol'] = symbol
997
+ self.handle_order_book_message(client, update, orderbook, messageHash)
998
+ client.resolve(orderbook, messageHash)
999
+ elif action == 'update':
1000
+ if symbol in self.orderbooks:
1001
+ orderbook = self.orderbooks[symbol]
1002
+ for i in range(0, len(data)):
1003
+ update = data[i]
1004
+ self.handle_order_book_message(client, update, orderbook, messageHash)
1005
+ client.resolve(orderbook, messageHash)
1006
+ elif (channel == 'books5') or (channel == 'bbo-tbt'):
1007
+ if not (symbol in self.orderbooks):
1008
+ self.orderbooks[symbol] = self.order_book({}, limit)
1009
+ orderbook = self.orderbooks[symbol]
1010
+ for i in range(0, len(data)):
1011
+ update = data[i]
1012
+ timestamp = self.safe_integer(update, 'ts')
1013
+ snapshot = self.parse_order_book(update, symbol, timestamp, 'bids', 'asks', 0, 1)
1014
+ orderbook.reset(snapshot)
1015
+ client.resolve(orderbook, messageHash)
1016
+ return message
1017
+
1018
+ async def authenticate(self, params={}):
1019
+ self.check_required_credentials()
1020
+ access = self.safe_string(params, 'access', 'private')
1021
+ params = self.omit(params, ['access'])
1022
+ url = self.get_url('users', access)
1023
+ messageHash = 'authenticated'
1024
+ client = self.client(url)
1025
+ future = client.future(messageHash)
1026
+ authenticated = self.safe_value(client.subscriptions, messageHash)
1027
+ if authenticated is None:
1028
+ timestamp = str(self.seconds())
1029
+ method = 'GET'
1030
+ path = '/users/self/verify'
1031
+ auth = timestamp + method + path
1032
+ signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256, 'base64')
1033
+ operation = 'login'
1034
+ request: dict = {
1035
+ 'op': operation,
1036
+ 'args': [
1037
+ {
1038
+ 'apiKey': self.apiKey,
1039
+ 'passphrase': self.password,
1040
+ 'timestamp': timestamp,
1041
+ 'sign': signature,
1042
+ },
1043
+ ],
1044
+ }
1045
+ message = self.extend(request, params)
1046
+ self.watch(url, messageHash, message, messageHash)
1047
+ return await future
1048
+
1049
+ async def watch_balance(self, params={}) -> Balances:
1050
+ """
1051
+ watch balance and get the amount of funds available for trading or funds locked in orders
1052
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1053
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1054
+ """
1055
+ await self.load_markets()
1056
+ await self.authenticate()
1057
+ return await self.subscribe('private', 'account', 'account', None, params)
1058
+
1059
+ def handle_balance_and_position(self, client: Client, message):
1060
+ self.handle_my_liquidation(client, message)
1061
+
1062
+ def handle_balance(self, client: Client, message):
1063
+ #
1064
+ # {
1065
+ # "arg": {channel: "account"},
1066
+ # "data": [
1067
+ # {
1068
+ # "adjEq": '',
1069
+ # "details": [
1070
+ # {
1071
+ # "availBal": '',
1072
+ # "availEq": "8.21009913",
1073
+ # "cashBal": "8.21009913",
1074
+ # "ccy": "USDT",
1075
+ # "coinUsdPrice": "0.99994",
1076
+ # "crossLiab": '',
1077
+ # "disEq": "8.2096065240522",
1078
+ # "eq": "8.21009913",
1079
+ # "eqUsd": "8.2096065240522",
1080
+ # "frozenBal": "0",
1081
+ # "interest": '',
1082
+ # "isoEq": "0",
1083
+ # "isoLiab": '',
1084
+ # "liab": '',
1085
+ # "maxLoan": '',
1086
+ # "mgnRatio": '',
1087
+ # "notionalLever": "0",
1088
+ # "ordFrozen": "0",
1089
+ # "twap": "0",
1090
+ # "uTime": "1621927314996",
1091
+ # "upl": "0"
1092
+ # },
1093
+ # ],
1094
+ # "imr": '',
1095
+ # "isoEq": "0",
1096
+ # "mgnRatio": '',
1097
+ # "mmr": '',
1098
+ # "notionalUsd": '',
1099
+ # "ordFroz": '',
1100
+ # "totalEq": "22.1930992296832",
1101
+ # "uTime": "1626692120916"
1102
+ # }
1103
+ # ]
1104
+ # }
1105
+ #
1106
+ arg = self.safe_value(message, 'arg', {})
1107
+ channel = self.safe_string(arg, 'channel')
1108
+ type = 'spot'
1109
+ balance = self.parseTradingBalance(message)
1110
+ oldBalance = self.safe_value(self.balance, type, {})
1111
+ newBalance = self.deep_extend(oldBalance, balance)
1112
+ self.balance[type] = self.safe_balance(newBalance)
1113
+ client.resolve(self.balance[type], channel)
1114
+
1115
+ def order_to_trade(self, order, market=None):
1116
+ info = self.safe_value(order, 'info', {})
1117
+ timestamp = self.safe_integer(info, 'fillTime')
1118
+ feeMarketId = self.safe_string(info, 'fillFeeCcy')
1119
+ isTaker = self.safe_string(info, 'execType', '') == 'T'
1120
+ return self.safe_trade({
1121
+ 'info': info,
1122
+ 'timestamp': timestamp,
1123
+ 'datetime': self.iso8601(timestamp),
1124
+ 'symbol': self.safe_string(order, 'symbol'),
1125
+ 'id': self.safe_string(info, 'tradeId'),
1126
+ 'order': self.safe_string(order, 'id'),
1127
+ 'type': self.safe_string(order, 'type'),
1128
+ 'takerOrMaker': 'taker' if (isTaker) else 'maker',
1129
+ 'side': self.safe_string(order, 'side'),
1130
+ 'price': self.safe_number(info, 'fillPx'),
1131
+ 'amount': self.safe_number(info, 'fillSz'),
1132
+ 'cost': self.safe_number(order, 'cost'),
1133
+ 'fee': {
1134
+ 'cost': self.safe_number(info, 'fillFee'),
1135
+ 'currency': self.safe_currency_code(feeMarketId),
1136
+ },
1137
+ }, market)
1138
+
1139
+ async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1140
+ """
1141
+ watches information on multiple trades made by the user
1142
+ :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-order-channel
1143
+ :param str [symbol]: unified market symbol of the market trades were made in
1144
+ :param int [since]: the earliest time in ms to fetch trades for
1145
+ :param int [limit]: the maximum number of trade structures to retrieve
1146
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1147
+ :param bool [params.stop]: True if fetching trigger or conditional trades
1148
+ :param str [params.type]: 'spot', 'swap', 'future', 'option', 'ANY', 'SPOT', 'MARGIN', 'SWAP', 'FUTURES' or 'OPTION'
1149
+ :param str [params.marginMode]: 'cross' or 'isolated', for automatically setting the type to spot margin
1150
+ :returns dict[]: a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure
1151
+ """
1152
+ # By default, receive order updates from any instrument type
1153
+ type = None
1154
+ type, params = self.handle_option_and_params(params, 'watchMyTrades', 'type', 'ANY')
1155
+ isStop = self.safe_bool(params, 'stop', False)
1156
+ params = self.omit(params, ['stop'])
1157
+ await self.load_markets()
1158
+ await self.authenticate({'access': 'business' if isStop else 'private'})
1159
+ channel = 'orders-algo' if isStop else 'orders'
1160
+ messageHash = channel + '::myTrades'
1161
+ market = None
1162
+ if symbol is not None:
1163
+ market = self.market(symbol)
1164
+ symbol = market['symbol']
1165
+ type = market['type']
1166
+ messageHash = messageHash + '::' + symbol
1167
+ if type == 'future':
1168
+ type = 'futures'
1169
+ uppercaseType = type.upper()
1170
+ marginMode = None
1171
+ marginMode, params = self.handle_margin_mode_and_params('watchMyTrades', params)
1172
+ if uppercaseType == 'SPOT':
1173
+ if marginMode is not None:
1174
+ uppercaseType = 'MARGIN'
1175
+ request: dict = {
1176
+ 'instType': uppercaseType,
1177
+ }
1178
+ orders = await self.subscribe('private', messageHash, channel, None, self.extend(request, params))
1179
+ if self.newUpdates:
1180
+ limit = orders.getLimit(symbol, limit)
1181
+ return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
1182
+
1183
+ async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
1184
+ """
1185
+ :see: https://www.okx.com/docs-v5/en/#trading-account-websocket-positions-channel
1186
+ watch all open positions
1187
+ :param str[]|None symbols: list of unified market symbols
1188
+ :param dict params: extra parameters specific to the exchange API endpoint
1189
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
1190
+ """
1191
+ await self.load_markets()
1192
+ await self.authenticate(params)
1193
+ symbols = self.market_symbols(symbols)
1194
+ request: dict = {
1195
+ 'instType': 'ANY',
1196
+ }
1197
+ channel = 'positions'
1198
+ newPositions = None
1199
+ if symbols is None:
1200
+ arg: dict = {
1201
+ 'channel': 'positions',
1202
+ 'instType': 'ANY',
1203
+ }
1204
+ args = [arg]
1205
+ nonSymbolRequest: dict = {
1206
+ 'op': 'subscribe',
1207
+ 'args': args,
1208
+ }
1209
+ url = self.get_url(channel, 'private')
1210
+ newPositions = await self.watch(url, channel, nonSymbolRequest, channel)
1211
+ else:
1212
+ newPositions = await self.subscribe_multiple('private', channel, symbols, self.extend(request, params))
1213
+ if self.newUpdates:
1214
+ return newPositions
1215
+ return self.filter_by_symbols_since_limit(self.positions, symbols, since, limit, True)
1216
+
1217
+ def handle_positions(self, client, message):
1218
+ #
1219
+ # {
1220
+ # arg: {
1221
+ # channel: 'positions',
1222
+ # instType: 'ANY',
1223
+ # instId: 'XRP-USDT-SWAP',
1224
+ # uid: '464737184507959869'
1225
+ # },
1226
+ # data: [{
1227
+ # adl: '1',
1228
+ # availPos: '',
1229
+ # avgPx: '0.52668',
1230
+ # baseBal: '',
1231
+ # baseBorrowed: '',
1232
+ # baseInterest: '',
1233
+ # bizRefId: '',
1234
+ # bizRefType: '',
1235
+ # cTime: '1693151444408',
1236
+ # ccy: 'USDT',
1237
+ # closeOrderAlgo: [],
1238
+ # deltaBS: '',
1239
+ # deltaPA: '',
1240
+ # gammaBS: '',
1241
+ # gammaPA: '',
1242
+ # idxPx: '0.52683',
1243
+ # imr: '17.564000000000004',
1244
+ # instId: 'XRP-USDT-SWAP',
1245
+ # instType: 'SWAP',
1246
+ # interest: '',
1247
+ # last: '0.52691',
1248
+ # lever: '3',
1249
+ # liab: '',
1250
+ # liabCcy: '',
1251
+ # liqPx: '0.3287514731020614',
1252
+ # margin: '',
1253
+ # markPx: '0.52692',
1254
+ # mgnMode: 'cross',
1255
+ # mgnRatio: '69.00363001456147',
1256
+ # mmr: '0.26346',
1257
+ # notionalUsd: '52.68620388000001',
1258
+ # optVal: '',
1259
+ # pTime: '1693151906023',
1260
+ # pendingCloseOrdLiabVal: '',
1261
+ # pos: '1',
1262
+ # posCcy: '',
1263
+ # posId: '616057041198907393',
1264
+ # posSide: 'net',
1265
+ # quoteBal: '',
1266
+ # quoteBorrowed: '',
1267
+ # quoteInterest: '',
1268
+ # spotInUseAmt: '',
1269
+ # spotInUseCcy: '',
1270
+ # thetaBS: '',
1271
+ # thetaPA: '',
1272
+ # tradeId: '138745402',
1273
+ # uTime: '1693151444408',
1274
+ # upl: '0.0240000000000018',
1275
+ # uplLastPx: '0.0229999999999952',
1276
+ # uplRatio: '0.0013670539986328',
1277
+ # uplRatioLastPx: '0.001310093415356',
1278
+ # usdPx: '',
1279
+ # vegaBS: '',
1280
+ # vegaPA: ''
1281
+ # }]
1282
+ # }
1283
+ #
1284
+ arg = self.safe_value(message, 'arg', {})
1285
+ channel = self.safe_string(arg, 'channel', '')
1286
+ data = self.safe_value(message, 'data', [])
1287
+ if self.positions is None:
1288
+ self.positions = ArrayCacheBySymbolBySide()
1289
+ cache = self.positions
1290
+ newPositions = []
1291
+ for i in range(0, len(data)):
1292
+ rawPosition = data[i]
1293
+ position = self.parse_position(rawPosition)
1294
+ newPositions.append(position)
1295
+ cache.append(position)
1296
+ messageHashes = self.find_message_hashes(client, channel + '::')
1297
+ for i in range(0, len(messageHashes)):
1298
+ messageHash = messageHashes[i]
1299
+ parts = messageHash.split('::')
1300
+ symbolsString = parts[1]
1301
+ symbols = symbolsString.split(',')
1302
+ positions = self.filter_by_array(newPositions, 'symbol', symbols, False)
1303
+ if not self.is_empty(positions):
1304
+ client.resolve(positions, messageHash)
1305
+ client.resolve(newPositions, channel)
1306
+
1307
+ async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1308
+ """
1309
+ watches information on multiple orders made by the user
1310
+ :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-order-channel
1311
+ :param str [symbol]: unified market symbol of the market the orders were made in
1312
+ :param int [since]: the earliest time in ms to fetch orders for
1313
+ :param int [limit]: the maximum number of order structures to retrieve
1314
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1315
+ :param bool [params.stop]: True if fetching trigger or conditional orders
1316
+ :param str [params.type]: 'spot', 'swap', 'future', 'option', 'ANY', 'SPOT', 'MARGIN', 'SWAP', 'FUTURES' or 'OPTION'
1317
+ :param str [params.marginMode]: 'cross' or 'isolated', for automatically setting the type to spot margin
1318
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1319
+ """
1320
+ type = None
1321
+ # By default, receive order updates from any instrument type
1322
+ type, params = self.handle_option_and_params(params, 'watchOrders', 'type', 'ANY')
1323
+ isStop = self.safe_value_2(params, 'stop', 'trigger', False)
1324
+ params = self.omit(params, ['stop', 'trigger'])
1325
+ await self.load_markets()
1326
+ await self.authenticate({'access': 'business' if isStop else 'private'})
1327
+ market = None
1328
+ if symbol is not None:
1329
+ market = self.market(symbol)
1330
+ symbol = market['symbol']
1331
+ type = market['type']
1332
+ if type == 'future':
1333
+ type = 'futures'
1334
+ uppercaseType = type.upper()
1335
+ marginMode = None
1336
+ marginMode, params = self.handle_margin_mode_and_params('watchOrders', params)
1337
+ if uppercaseType == 'SPOT':
1338
+ if marginMode is not None:
1339
+ uppercaseType = 'MARGIN'
1340
+ request: dict = {
1341
+ 'instType': uppercaseType,
1342
+ }
1343
+ channel = 'orders-algo' if isStop else 'orders'
1344
+ orders = await self.subscribe('private', channel, channel, symbol, self.extend(request, params))
1345
+ if self.newUpdates:
1346
+ limit = orders.getLimit(symbol, limit)
1347
+ return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
1348
+
1349
+ def handle_orders(self, client: Client, message, subscription=None):
1350
+ #
1351
+ # {
1352
+ # "arg":{
1353
+ # "channel":"orders",
1354
+ # "instType":"SPOT"
1355
+ # },
1356
+ # "data":[
1357
+ # {
1358
+ # "accFillSz":"0",
1359
+ # "amendResult":"",
1360
+ # "avgPx":"",
1361
+ # "cTime":"1634548275191",
1362
+ # "category":"normal",
1363
+ # "ccy":"",
1364
+ # "clOrdId":"e847386590ce4dBC330547db94a08ba0",
1365
+ # "code":"0",
1366
+ # "execType":"",
1367
+ # "fee":"0",
1368
+ # "feeCcy":"USDT",
1369
+ # "fillFee":"0",
1370
+ # "fillFeeCcy":"",
1371
+ # "fillNotionalUsd":"",
1372
+ # "fillPx":"",
1373
+ # "fillSz":"0",
1374
+ # "fillTime":"",
1375
+ # "instId":"ETH-USDT",
1376
+ # "instType":"SPOT",
1377
+ # "lever":"",
1378
+ # "msg":"",
1379
+ # "notionalUsd":"451.4516256",
1380
+ # "ordId":"370257534141235201",
1381
+ # "ordType":"limit",
1382
+ # "pnl":"0",
1383
+ # "posSide":"",
1384
+ # "px":"60000",
1385
+ # "rebate":"0",
1386
+ # "rebateCcy":"ETH",
1387
+ # "reqId":"",
1388
+ # "side":"sell",
1389
+ # "slOrdPx":"",
1390
+ # "slTriggerPx":"",
1391
+ # "state":"live",
1392
+ # "sz":"0.007526",
1393
+ # "tag":"",
1394
+ # "tdMode":"cash",
1395
+ # "tgtCcy":"",
1396
+ # "tpOrdPx":"",
1397
+ # "tpTriggerPx":"",
1398
+ # "tradeId":"",
1399
+ # "uTime":"1634548275191"
1400
+ # }
1401
+ # ]
1402
+ # }
1403
+ #
1404
+ self.handle_my_trades(client, message)
1405
+ arg = self.safe_value(message, 'arg', {})
1406
+ channel = self.safe_string(arg, 'channel')
1407
+ orders = self.safe_value(message, 'data', [])
1408
+ ordersLength = len(orders)
1409
+ if ordersLength > 0:
1410
+ limit = self.safe_integer(self.options, 'ordersLimit', 1000)
1411
+ if self.orders is None:
1412
+ self.orders = ArrayCacheBySymbolById(limit)
1413
+ self.triggerOrders = ArrayCacheBySymbolById(limit)
1414
+ stored = self.triggerOrders if (channel == 'orders-algo') else self.orders
1415
+ marketIds = []
1416
+ parsed = self.parse_orders(orders)
1417
+ for i in range(0, len(parsed)):
1418
+ order = parsed[i]
1419
+ stored.append(order)
1420
+ symbol = order['symbol']
1421
+ market = self.market(symbol)
1422
+ marketIds.append(market['id'])
1423
+ client.resolve(stored, channel)
1424
+ for i in range(0, len(marketIds)):
1425
+ messageHash = channel + ':' + marketIds[i]
1426
+ client.resolve(stored, messageHash)
1427
+
1428
+ def handle_my_trades(self, client: Client, message):
1429
+ #
1430
+ # {
1431
+ # "arg":{
1432
+ # "channel":"orders",
1433
+ # "instType":"SPOT"
1434
+ # },
1435
+ # "data":[
1436
+ # {
1437
+ # "accFillSz":"0",
1438
+ # "amendResult":"",
1439
+ # "avgPx":"",
1440
+ # "cTime":"1634548275191",
1441
+ # "category":"normal",
1442
+ # "ccy":"",
1443
+ # "clOrdId":"e847386590ce4dBC330547db94a08ba0",
1444
+ # "code":"0",
1445
+ # "execType":"",
1446
+ # "fee":"0",
1447
+ # "feeCcy":"USDT",
1448
+ # "fillFee":"0",
1449
+ # "fillFeeCcy":"",
1450
+ # "fillNotionalUsd":"",
1451
+ # "fillPx":"",
1452
+ # "fillSz":"0",
1453
+ # "fillTime":"",
1454
+ # "instId":"ETH-USDT",
1455
+ # "instType":"SPOT",
1456
+ # "lever":"",
1457
+ # "msg":"",
1458
+ # "notionalUsd":"451.4516256",
1459
+ # "ordId":"370257534141235201",
1460
+ # "ordType":"limit",
1461
+ # "pnl":"0",
1462
+ # "posSide":"",
1463
+ # "px":"60000",
1464
+ # "rebate":"0",
1465
+ # "rebateCcy":"ETH",
1466
+ # "reqId":"",
1467
+ # "side":"sell",
1468
+ # "slOrdPx":"",
1469
+ # "slTriggerPx":"",
1470
+ # "state":"live",
1471
+ # "sz":"0.007526",
1472
+ # "tag":"",
1473
+ # "tdMode":"cash",
1474
+ # "tgtCcy":"",
1475
+ # "tpOrdPx":"",
1476
+ # "tpTriggerPx":"",
1477
+ # "tradeId":"",
1478
+ # "uTime":"1634548275191"
1479
+ # }
1480
+ # ]
1481
+ # }
1482
+ #
1483
+ arg = self.safe_value(message, 'arg', {})
1484
+ channel = self.safe_string(arg, 'channel')
1485
+ rawOrders = self.safe_value(message, 'data', [])
1486
+ filteredOrders = []
1487
+ # filter orders with no last trade id
1488
+ for i in range(0, len(rawOrders)):
1489
+ rawOrder = rawOrders[i]
1490
+ tradeId = self.safe_string(rawOrder, 'tradeId', '')
1491
+ if len(tradeId) > 0:
1492
+ order = self.parse_order(rawOrder)
1493
+ filteredOrders.append(order)
1494
+ tradesLength = len(filteredOrders)
1495
+ if tradesLength == 0:
1496
+ return
1497
+ if self.myTrades is None:
1498
+ limit = self.safe_integer(self.options, 'tradesLimit', 1000)
1499
+ self.myTrades = ArrayCacheBySymbolById(limit)
1500
+ myTrades = self.myTrades
1501
+ symbols: dict = {}
1502
+ for i in range(0, len(filteredOrders)):
1503
+ rawTrade = filteredOrders[i]
1504
+ trade = self.order_to_trade(rawTrade)
1505
+ myTrades.append(trade)
1506
+ symbol = trade['symbol']
1507
+ symbols[symbol] = True
1508
+ messageHash = channel + '::myTrades'
1509
+ client.resolve(self.myTrades, messageHash)
1510
+ tradeSymbols = list(symbols.keys())
1511
+ for i in range(0, len(tradeSymbols)):
1512
+ symbolMessageHash = messageHash + '::' + tradeSymbols[i]
1513
+ client.resolve(self.orders, symbolMessageHash)
1514
+
1515
+ async def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
1516
+ """
1517
+ :see: https://www.okx.com/docs-v5/en/#websocket-api-trade-place-order
1518
+ create a trade order
1519
+ :param str symbol: unified symbol of the market to create an order in
1520
+ :param str type: 'market' or 'limit'
1521
+ :param str side: 'buy' or 'sell'
1522
+ :param float amount: how much of currency you want to trade in units of base currency
1523
+ :param float|None [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1524
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1525
+ :param boolean params['test']: test order, default False
1526
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1527
+ """
1528
+ await self.load_markets()
1529
+ await self.authenticate()
1530
+ url = self.get_url('private', 'private')
1531
+ messageHash = str(self.nonce())
1532
+ op = None
1533
+ op, params = self.handle_option_and_params(params, 'createOrderWs', 'op', 'batch-orders')
1534
+ args = self.create_order_request(symbol, type, side, amount, price, params)
1535
+ ordType = self.safe_string(args, 'ordType')
1536
+ if (ordType == 'trigger') or (ordType == 'conditional') or (type == 'oco') or (type == 'move_order_stop') or (type == 'iceberg') or (type == 'twap'):
1537
+ raise BadRequest(self.id + ' createOrderWs() does not support algo trading. self.options["createOrderWs"]["op"] must be either order or batch-order')
1538
+ if (op != 'order') and (op != 'batch-orders'):
1539
+ raise BadRequest(self.id + ' createOrderWs() does not support algo trading. self.options["createOrderWs"]["op"] must be either order or privatePostTradeOrder or privatePostTradeOrderAlgo')
1540
+ request: dict = {
1541
+ 'id': messageHash,
1542
+ 'op': op,
1543
+ 'args': [args],
1544
+ }
1545
+ return await self.watch(url, messageHash, request, messageHash)
1546
+
1547
+ def handle_place_orders(self, client: Client, message):
1548
+ #
1549
+ # batch-orders/order/cancel-order
1550
+ # {
1551
+ # "id": "1689281055",
1552
+ # "op": "batch-orders",
1553
+ # "code": "0",
1554
+ # "msg": '',
1555
+ # "data": [{
1556
+ # "tag": "e847386590ce4dBC",
1557
+ # "ordId": "599823446566084608",
1558
+ # "clOrdId": "e847386590ce4dBCb939511604f394b0",
1559
+ # "sCode": "0",
1560
+ # "sMsg": "Order successfully placed."
1561
+ # },
1562
+ # ...
1563
+ # ]
1564
+ # }
1565
+ #
1566
+ messageHash = self.safe_string(message, 'id')
1567
+ args = self.safe_value(message, 'data', [])
1568
+ # filter out partial errors
1569
+ args = self.filter_by(args, 'sCode', '0')
1570
+ # if empty means request failed and handle error
1571
+ if self.is_empty(args):
1572
+ method = self.safe_string(message, 'op')
1573
+ stringMsg = self.json(message)
1574
+ self.handle_errors(None, None, client.url, method, None, stringMsg, stringMsg, None, None)
1575
+ orders = self.parse_orders(args, None, None, None)
1576
+ first = self.safe_dict(orders, 0, {})
1577
+ client.resolve(first, messageHash)
1578
+
1579
+ async def edit_order_ws(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}) -> Order:
1580
+ """
1581
+ edit a trade order
1582
+ :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-amend-order
1583
+ :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-amend-multiple-orders
1584
+ :param str id: order id
1585
+ :param str symbol: unified symbol of the market to create an order in
1586
+ :param str type: 'market' or 'limit'
1587
+ :param str side: 'buy' or 'sell'
1588
+ :param float amount: how much of the currency you want to trade in units of the base currency
1589
+ :param float|None [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1590
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1591
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1592
+ """
1593
+ await self.load_markets()
1594
+ await self.authenticate()
1595
+ url = self.get_url('private', 'private')
1596
+ messageHash = str(self.nonce())
1597
+ op = None
1598
+ op, params = self.handle_option_and_params(params, 'editOrderWs', 'op', 'amend-order')
1599
+ args = self.edit_order_request(id, symbol, type, side, amount, price, params)
1600
+ request: dict = {
1601
+ 'id': messageHash,
1602
+ 'op': op,
1603
+ 'args': [args],
1604
+ }
1605
+ return await self.watch(url, messageHash, self.extend(request, params), messageHash)
1606
+
1607
+ async def cancel_order_ws(self, id: str, symbol: Str = None, params={}) -> Order:
1608
+ """
1609
+ :see: https://okx-docs.github.io/apidocs/websocket_api/en/#cancel-order-trade
1610
+ cancel multiple orders
1611
+ :param str id: order id
1612
+ :param str symbol: unified market symbol, default is None
1613
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1614
+ :param str [params.clOrdId]: client order id
1615
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1616
+ """
1617
+ if symbol is None:
1618
+ raise BadRequest(self.id + ' cancelOrderWs() requires a symbol argument')
1619
+ await self.load_markets()
1620
+ await self.authenticate()
1621
+ url = self.get_url('private', 'private')
1622
+ messageHash = str(self.nonce())
1623
+ clientOrderId = self.safe_string_2(params, 'clOrdId', 'clientOrderId')
1624
+ params = self.omit(params, ['clientOrderId', 'clOrdId'])
1625
+ arg: dict = {
1626
+ 'instId': self.market_id(symbol),
1627
+ }
1628
+ if clientOrderId is not None:
1629
+ arg['clOrdId'] = clientOrderId
1630
+ else:
1631
+ arg['ordId'] = id
1632
+ request: dict = {
1633
+ 'id': messageHash,
1634
+ 'op': 'cancel-order',
1635
+ 'args': [self.extend(arg, params)],
1636
+ }
1637
+ return await self.watch(url, messageHash, request, messageHash)
1638
+
1639
+ async def cancel_orders_ws(self, ids: List[str], symbol: Str = None, params={}):
1640
+ """
1641
+ :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-mass-cancel-order
1642
+ cancel multiple orders
1643
+ :param str[] ids: order ids
1644
+ :param str symbol: unified market symbol, default is None
1645
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1646
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1647
+ """
1648
+ idsLength = len(ids)
1649
+ if idsLength > 20:
1650
+ raise BadRequest(self.id + ' cancelOrdersWs() accepts up to 20 ids at a time')
1651
+ if symbol is None:
1652
+ raise BadRequest(self.id + ' cancelOrdersWs() requires a symbol argument')
1653
+ await self.load_markets()
1654
+ await self.authenticate()
1655
+ url = self.get_url('private', 'private')
1656
+ messageHash = str(self.nonce())
1657
+ args = []
1658
+ for i in range(0, idsLength):
1659
+ arg: dict = {
1660
+ 'instId': self.market_id(symbol),
1661
+ 'ordId': ids[i],
1662
+ }
1663
+ args.append(arg)
1664
+ request: dict = {
1665
+ 'id': messageHash,
1666
+ 'op': 'batch-cancel-orders',
1667
+ 'args': args,
1668
+ }
1669
+ return await self.watch(url, messageHash, self.deep_extend(request, params), messageHash)
1670
+
1671
+ async def cancel_all_orders_ws(self, symbol: Str = None, params={}):
1672
+ """
1673
+ :see: https://docs.okx.com/websockets/#message-cancelAll
1674
+ cancel all open orders of a type. Only applicable to Option in Portfolio Margin mode, and MMP privilege is required.
1675
+ :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
1676
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1677
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1678
+ """
1679
+ if symbol is None:
1680
+ raise BadRequest(self.id + ' cancelAllOrdersWs() requires a symbol argument')
1681
+ await self.load_markets()
1682
+ await self.authenticate()
1683
+ market = self.market(symbol)
1684
+ if market['type'] != 'option':
1685
+ raise BadRequest(self.id + 'cancelAllOrdersWs is only applicable to Option in Portfolio Margin mode, and MMP privilege is required.')
1686
+ url = self.get_url('private', 'private')
1687
+ messageHash = str(self.nonce())
1688
+ request: dict = {
1689
+ 'id': messageHash,
1690
+ 'op': 'mass-cancel',
1691
+ 'args': [self.extend({
1692
+ 'instType': 'OPTION',
1693
+ 'instFamily': market['id'],
1694
+ }, params)],
1695
+ }
1696
+ return await self.watch(url, messageHash, request, messageHash)
1697
+
1698
+ def handle_cancel_all_orders(self, client: Client, message):
1699
+ #
1700
+ # {
1701
+ # "id": "1512",
1702
+ # "op": "mass-cancel",
1703
+ # "data": [
1704
+ # {
1705
+ # "result": True
1706
+ # }
1707
+ # ],
1708
+ # "code": "0",
1709
+ # "msg": ""
1710
+ # }
1711
+ #
1712
+ messageHash = self.safe_string(message, 'id')
1713
+ data = self.safe_value(message, 'data', [])
1714
+ client.resolve(data, messageHash)
1715
+
1716
+ def handle_subscription_status(self, client: Client, message):
1717
+ #
1718
+ # {event: 'subscribe', arg: {channel: "tickers", instId: "BTC-USDT"}}
1719
+ #
1720
+ # channel = self.safe_string(message, "channel")
1721
+ # client.subscriptions[channel] = message
1722
+ return message
1723
+
1724
+ def handle_authenticate(self, client: Client, message):
1725
+ #
1726
+ # {event: "login", success: True}
1727
+ #
1728
+ future = self.safe_value(client.futures, 'authenticated')
1729
+ future.resolve(True)
1730
+
1731
+ def ping(self, client):
1732
+ # okex does not support built-in ws protocol-level ping-pong
1733
+ # instead it requires custom text-based ping-pong
1734
+ return 'ping'
1735
+
1736
+ def handle_pong(self, client: Client, message):
1737
+ client.lastPong = self.milliseconds()
1738
+ return message
1739
+
1740
+ def handle_error_message(self, client: Client, message):
1741
+ #
1742
+ # {event: 'error', msg: "Illegal request: {"op":"subscribe","args":["spot/ticker:BTC-USDT"]}", code: "60012"}
1743
+ # {event: 'error", msg: "channel:ticker,instId:BTC-USDT doesn"t exist", code: "60018"}
1744
+ #
1745
+ errorCode = self.safe_string(message, 'code')
1746
+ try:
1747
+ if errorCode and errorCode != '0':
1748
+ feedback = self.id + ' ' + self.json(message)
1749
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
1750
+ messageString = self.safe_value(message, 'msg')
1751
+ if messageString is not None:
1752
+ self.throw_broadly_matched_exception(self.exceptions['broad'], messageString, feedback)
1753
+ raise ExchangeError(feedback)
1754
+ except Exception as e:
1755
+ client.reject(e)
1756
+ return False
1757
+ return message
1758
+
1759
+ def handle_message(self, client: Client, message):
1760
+ if not self.handle_error_message(client, message):
1761
+ return
1762
+ #
1763
+ # {event: 'subscribe', arg: {channel: "tickers", instId: "BTC-USDT"}}
1764
+ # {event: 'login", msg: '", code: "0"}
1765
+ #
1766
+ # {
1767
+ # "arg": {channel: "tickers", instId: "BTC-USDT"},
1768
+ # "data": [
1769
+ # {
1770
+ # "instType": "SPOT",
1771
+ # "instId": "BTC-USDT",
1772
+ # "last": "31500.1",
1773
+ # "lastSz": "0.00001754",
1774
+ # "askPx": "31500.1",
1775
+ # "askSz": "0.00998144",
1776
+ # "bidPx": "31500",
1777
+ # "bidSz": "3.05652439",
1778
+ # "open24h": "31697",
1779
+ # "high24h": "32248",
1780
+ # "low24h": "31165.6",
1781
+ # "sodUtc0": "31385.5",
1782
+ # "sodUtc8": "32134.9",
1783
+ # "volCcy24h": "503403597.38138519",
1784
+ # "vol24h": "15937.10781721",
1785
+ # "ts": "1626526618762"
1786
+ # }
1787
+ # ]
1788
+ # }
1789
+ #
1790
+ # {event: 'error', msg: "Illegal request: {"op":"subscribe","args":["spot/ticker:BTC-USDT"]}", code: "60012"}
1791
+ # {event: 'error", msg: "channel:ticker,instId:BTC-USDT doesn"t exist", code: "60018"}
1792
+ # {event: 'error', msg: "Invalid OK_ACCESS_KEY", code: "60005"}
1793
+ # {
1794
+ # "event": "error",
1795
+ # "msg": "Illegal request: {"op":"login","args":["de89b035-b233-44b2-9a13-0ccdd00bda0e","7KUcc8YzQhnxBE3K","1626691289","H57N99mBt5NvW8U19FITrPdOxycAERFMaapQWRqLaSE="]}",
1796
+ # "code": "60012"
1797
+ # }
1798
+ #
1799
+ #
1800
+ #
1801
+ if message == 'pong':
1802
+ self.handle_pong(client, message)
1803
+ return
1804
+ # table = self.safe_string(message, 'table')
1805
+ # if table is None:
1806
+ event = self.safe_string_2(message, 'event', 'op')
1807
+ if event is not None:
1808
+ methods: dict = {
1809
+ # 'info': self.handleSystemStatus,
1810
+ # 'book': 'handleOrderBook',
1811
+ 'login': self.handle_authenticate,
1812
+ 'subscribe': self.handle_subscription_status,
1813
+ 'order': self.handle_place_orders,
1814
+ 'batch-orders': self.handle_place_orders,
1815
+ 'amend-order': self.handle_place_orders,
1816
+ 'batch-amend-orders': self.handle_place_orders,
1817
+ 'cancel-order': self.handle_place_orders,
1818
+ 'mass-cancel': self.handle_cancel_all_orders,
1819
+ }
1820
+ method = self.safe_value(methods, event)
1821
+ if method is not None:
1822
+ method(client, message)
1823
+ else:
1824
+ arg = self.safe_value(message, 'arg', {})
1825
+ channel = self.safe_string(arg, 'channel')
1826
+ methods: dict = {
1827
+ 'bbo-tbt': self.handle_order_book, # newly added channel that sends tick-by-tick Level 1 data, all API users can subscribe, public depth channel, verification not required
1828
+ 'books': self.handle_order_book, # all API users can subscribe, public depth channel, verification not required
1829
+ 'books5': self.handle_order_book, # all API users can subscribe, public depth channel, verification not required, data feeds will be delivered every 100ms(vs. every 200ms now)
1830
+ 'books50-l2-tbt': self.handle_order_book, # only users who're VIP4 and above can subscribe, identity verification required before subscription
1831
+ 'books-l2-tbt': self.handle_order_book, # only users who're VIP5 and above can subscribe, identity verification required before subscription
1832
+ 'tickers': self.handle_ticker,
1833
+ 'positions': self.handle_positions,
1834
+ 'index-tickers': self.handle_ticker,
1835
+ 'sprd-tickers': self.handle_ticker,
1836
+ 'block-tickers': self.handle_ticker,
1837
+ 'trades': self.handle_trades,
1838
+ 'account': self.handle_balance,
1839
+ 'funding-rate': self.handle_funding_rate,
1840
+ # 'margin_account': self.handle_balance,
1841
+ 'orders': self.handle_orders,
1842
+ 'orders-algo': self.handle_orders,
1843
+ 'liquidation-orders': self.handle_liquidation,
1844
+ 'balance_and_position': self.handle_balance_and_position,
1845
+ }
1846
+ method = self.safe_value(methods, channel)
1847
+ if method is None:
1848
+ if channel.find('candle') == 0:
1849
+ self.handle_ohlcv(client, message)
1850
+ else:
1851
+ method(client, message)