ccxt-ir 4.3.46.0.2__py2.py3-none-any.whl → 4.5.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (528) hide show
  1. ccxt/__init__.py +39 -35
  2. ccxt/abantether.py +9 -9
  3. ccxt/abstract/alpaca.py +4 -0
  4. ccxt/abstract/apex.py +31 -0
  5. ccxt/abstract/bigone.py +1 -1
  6. ccxt/abstract/binance.py +106 -48
  7. ccxt/abstract/binancecoinm.py +106 -48
  8. ccxt/abstract/binanceus.py +141 -83
  9. ccxt/abstract/binanceusdm.py +106 -48
  10. ccxt/abstract/bingx.py +50 -1
  11. ccxt/abstract/bitbank.py +5 -0
  12. ccxt/abstract/bitfinex.py +136 -65
  13. ccxt/abstract/bitflyer.py +1 -0
  14. ccxt/abstract/bitget.py +67 -0
  15. ccxt/abstract/bitmart.py +19 -1
  16. ccxt/abstract/bitopro.py +1 -0
  17. ccxt/abstract/bitrue.py +68 -68
  18. ccxt/abstract/bitstamp.py +1 -0
  19. ccxt/abstract/blofin.py +30 -0
  20. ccxt/abstract/btcbox.py +2 -0
  21. ccxt/abstract/bybit.py +28 -13
  22. ccxt/abstract/cex.py +28 -29
  23. ccxt/abstract/coinbaseexchange.py +1 -0
  24. ccxt/abstract/coinbaseinternational.py +1 -1
  25. ccxt/abstract/cryptocom.py +16 -0
  26. ccxt/abstract/cryptomus.py +20 -0
  27. ccxt/abstract/defx.py +69 -0
  28. ccxt/abstract/deribit.py +1 -0
  29. ccxt/abstract/derive.py +117 -0
  30. ccxt/abstract/digifinex.py +1 -0
  31. ccxt/abstract/ellipx.py +25 -0
  32. ccxt/abstract/foxbit.py +26 -0
  33. ccxt/abstract/gate.py +19 -0
  34. ccxt/abstract/gateio.py +19 -0
  35. ccxt/abstract/gemini.py +1 -0
  36. ccxt/abstract/hibachi.py +26 -0
  37. ccxt/abstract/hyperliquid.py +1 -1
  38. ccxt/abstract/independentreserve.py +6 -0
  39. ccxt/abstract/kraken.py +1 -0
  40. ccxt/abstract/krakenfutures.py +4 -0
  41. ccxt/abstract/kucoin.py +10 -0
  42. ccxt/abstract/kucoinfutures.py +18 -0
  43. ccxt/abstract/lbank.py +2 -1
  44. ccxt/abstract/luno.py +1 -0
  45. ccxt/abstract/mexc.py +2 -0
  46. ccxt/abstract/modetrade.py +119 -0
  47. ccxt/abstract/myokx.py +349 -0
  48. ccxt/abstract/oceanex.py +5 -0
  49. ccxt/abstract/okx.py +25 -0
  50. ccxt/abstract/okxus.py +349 -0
  51. ccxt/abstract/onetrading.py +0 -12
  52. ccxt/abstract/paradex.py +23 -0
  53. ccxt/abstract/phemex.py +2 -0
  54. ccxt/abstract/poloniex.py +36 -0
  55. ccxt/abstract/tradeogre.py +3 -1
  56. ccxt/abstract/upbit.py +51 -34
  57. ccxt/abstract/whitebit.py +16 -0
  58. ccxt/abstract/woo.py +64 -6
  59. ccxt/abstract/xt.py +10 -5
  60. ccxt/afratether.py +7 -7
  61. ccxt/alpaca.py +828 -51
  62. ccxt/apex.py +1875 -0
  63. ccxt/arzinja.py +7 -7
  64. ccxt/arzplus.py +9 -9
  65. ccxt/ascendex.py +501 -306
  66. ccxt/async_support/__init__.py +39 -35
  67. ccxt/async_support/abantether.py +10 -10
  68. ccxt/async_support/afratether.py +9 -9
  69. ccxt/async_support/alpaca.py +828 -51
  70. ccxt/async_support/apex.py +1875 -0
  71. ccxt/async_support/arzinja.py +10 -10
  72. ccxt/async_support/arzplus.py +12 -12
  73. ccxt/async_support/ascendex.py +502 -306
  74. ccxt/async_support/base/exchange.py +303 -89
  75. ccxt/async_support/base/ws/cache.py +9 -3
  76. ccxt/async_support/base/ws/client.py +173 -38
  77. ccxt/async_support/base/ws/future.py +25 -37
  78. ccxt/async_support/bequant.py +5 -3
  79. ccxt/async_support/bigone.py +279 -144
  80. ccxt/async_support/binance.py +2347 -1158
  81. ccxt/async_support/binancecoinm.py +9 -3
  82. ccxt/async_support/binanceus.py +17 -3
  83. ccxt/async_support/binanceusdm.py +9 -4
  84. ccxt/async_support/bingx.py +2962 -920
  85. ccxt/async_support/bit2c.py +147 -27
  86. ccxt/async_support/bitbank.py +151 -23
  87. ccxt/async_support/bitbns.py +104 -30
  88. ccxt/async_support/bitfinex.py +3291 -1113
  89. ccxt/async_support/bitflyer.py +202 -27
  90. ccxt/async_support/bitget.py +3683 -1538
  91. ccxt/async_support/bithumb.py +195 -38
  92. ccxt/async_support/bitimen.py +12 -12
  93. ccxt/async_support/bitir.py +38 -38
  94. ccxt/async_support/bitmart.py +1288 -350
  95. ccxt/async_support/bitmex.py +260 -75
  96. ccxt/async_support/bitopro.py +262 -62
  97. ccxt/async_support/bitpin.py +17 -16
  98. ccxt/async_support/bitrue.py +459 -290
  99. ccxt/async_support/bitso.py +199 -54
  100. ccxt/async_support/bitstamp.py +230 -96
  101. ccxt/async_support/bitteam.py +167 -25
  102. ccxt/async_support/{huobijp.py → bittrade.py} +158 -30
  103. ccxt/async_support/bitvavo.py +213 -49
  104. ccxt/async_support/blockchaincom.py +160 -46
  105. ccxt/async_support/blofin.py +502 -120
  106. ccxt/async_support/btcalpha.py +169 -31
  107. ccxt/async_support/btcbox.py +292 -23
  108. ccxt/async_support/btcmarkets.py +211 -58
  109. ccxt/async_support/btcturk.py +161 -38
  110. ccxt/async_support/bybit.py +1775 -1030
  111. ccxt/async_support/cex.py +1440 -1303
  112. ccxt/async_support/coinbase.py +724 -212
  113. ccxt/async_support/coinbaseadvanced.py +2 -1
  114. ccxt/async_support/coinbaseexchange.py +388 -89
  115. ccxt/async_support/coinbaseinternational.py +412 -57
  116. ccxt/async_support/coincatch.py +177 -78
  117. ccxt/async_support/coincheck.py +135 -19
  118. ccxt/async_support/coinex.py +606 -232
  119. ccxt/async_support/coinmate.py +189 -63
  120. ccxt/async_support/coinmetro.py +195 -54
  121. ccxt/async_support/coinone.py +158 -51
  122. ccxt/async_support/coinsph.py +336 -61
  123. ccxt/async_support/coinspot.py +151 -52
  124. ccxt/async_support/cryptocom.py +661 -111
  125. ccxt/async_support/cryptomus.py +1137 -0
  126. ccxt/async_support/defx.py +2071 -0
  127. ccxt/async_support/delta.py +299 -99
  128. ccxt/async_support/deribit.py +348 -126
  129. ccxt/async_support/derive.py +2572 -0
  130. ccxt/async_support/digifinex.py +430 -214
  131. ccxt/async_support/ellipx.py +2029 -0
  132. ccxt/async_support/eterex.py +10 -10
  133. ccxt/async_support/excoino.py +31 -31
  134. ccxt/async_support/exir.py +14 -14
  135. ccxt/async_support/exmo.py +344 -131
  136. ccxt/async_support/exnovin.py +10 -10
  137. ccxt/async_support/farhadexchange.py +12 -12
  138. ccxt/async_support/fmfwio.py +2 -1
  139. ccxt/async_support/foxbit.py +1935 -0
  140. ccxt/async_support/gate.py +1351 -529
  141. ccxt/async_support/gateio.py +2 -1
  142. ccxt/async_support/gemini.py +144 -39
  143. ccxt/async_support/hashkey.py +152 -109
  144. ccxt/async_support/hibachi.py +2080 -0
  145. ccxt/async_support/hitbtc.py +395 -167
  146. ccxt/async_support/hitobit.py +12 -12
  147. ccxt/async_support/hollaex.py +307 -119
  148. ccxt/async_support/htx.py +851 -383
  149. ccxt/async_support/huobi.py +2 -1
  150. ccxt/async_support/hyperliquid.py +1848 -536
  151. ccxt/async_support/independentreserve.py +288 -15
  152. ccxt/async_support/indodax.py +190 -33
  153. ccxt/async_support/jibitex.py +12 -12
  154. ccxt/async_support/kraken.py +795 -351
  155. ccxt/async_support/krakenfutures.py +214 -62
  156. ccxt/async_support/kucoin.py +715 -396
  157. ccxt/async_support/kucoinfutures.py +652 -89
  158. ccxt/async_support/latoken.py +217 -113
  159. ccxt/async_support/lbank.py +425 -97
  160. ccxt/async_support/luno.py +382 -35
  161. ccxt/async_support/mercado.py +113 -6
  162. ccxt/async_support/mexc.py +874 -437
  163. ccxt/async_support/modetrade.py +2818 -0
  164. ccxt/async_support/myokx.py +54 -0
  165. ccxt/async_support/ndax.py +221 -64
  166. ccxt/async_support/nobitex.py +31 -37
  167. ccxt/async_support/novadax.py +190 -34
  168. ccxt/async_support/oceanex.py +217 -28
  169. ccxt/async_support/okcoin.py +253 -145
  170. ccxt/async_support/okexchange.py +11 -11
  171. ccxt/async_support/okx.py +1088 -351
  172. ccxt/async_support/okxus.py +54 -0
  173. ccxt/async_support/ompfinex.py +25 -24
  174. ccxt/async_support/onetrading.py +213 -392
  175. ccxt/async_support/oxfun.py +245 -166
  176. ccxt/async_support/p2b.py +151 -29
  177. ccxt/async_support/paradex.py +562 -49
  178. ccxt/async_support/paymium.py +82 -19
  179. ccxt/async_support/phemex.py +713 -172
  180. ccxt/async_support/poloniex.py +1602 -283
  181. ccxt/async_support/probit.py +224 -95
  182. ccxt/async_support/ramzinex.py +30 -27
  183. ccxt/async_support/sarmayex.py +9 -9
  184. ccxt/async_support/sarrafex.py +13 -13
  185. ccxt/async_support/tabdeal.py +14 -13
  186. ccxt/async_support/tetherland.py +9 -9
  187. ccxt/async_support/timex.py +210 -51
  188. ccxt/async_support/tokocrypto.py +167 -47
  189. ccxt/async_support/tradeogre.py +266 -31
  190. ccxt/async_support/twox.py +9 -9
  191. ccxt/async_support/ubitex.py +12 -12
  192. ccxt/async_support/upbit.py +568 -165
  193. ccxt/async_support/vertex.py +160 -32
  194. ccxt/async_support/wallex.py +12 -12
  195. ccxt/async_support/wavesexchange.py +165 -30
  196. ccxt/async_support/whitebit.py +975 -127
  197. ccxt/async_support/woo.py +1918 -1016
  198. ccxt/async_support/woofipro.py +433 -141
  199. ccxt/async_support/xt.py +649 -193
  200. ccxt/async_support/yobit.py +195 -70
  201. ccxt/async_support/zaif.py +91 -15
  202. ccxt/async_support/zonda.py +151 -36
  203. ccxt/base/decimal_to_precision.py +14 -10
  204. ccxt/base/errors.py +49 -18
  205. ccxt/base/exchange.py +1556 -450
  206. ccxt/base/precise.py +10 -0
  207. ccxt/base/types.py +114 -6
  208. ccxt/bequant.py +5 -3
  209. ccxt/bigone.py +279 -144
  210. ccxt/binance.py +2347 -1158
  211. ccxt/binancecoinm.py +9 -3
  212. ccxt/binanceus.py +17 -3
  213. ccxt/binanceusdm.py +9 -4
  214. ccxt/bingx.py +2962 -920
  215. ccxt/bit2c.py +147 -27
  216. ccxt/bitbank.py +151 -23
  217. ccxt/bitbns.py +104 -30
  218. ccxt/bitfinex.py +3290 -1113
  219. ccxt/bitflyer.py +202 -27
  220. ccxt/bitget.py +3683 -1538
  221. ccxt/bithumb.py +194 -38
  222. ccxt/bitimen.py +9 -9
  223. ccxt/bitir.py +35 -35
  224. ccxt/bitmart.py +1288 -350
  225. ccxt/bitmex.py +260 -75
  226. ccxt/bitopro.py +262 -62
  227. ccxt/bitpin.py +15 -14
  228. ccxt/bitrue.py +459 -290
  229. ccxt/bitso.py +199 -54
  230. ccxt/bitstamp.py +230 -96
  231. ccxt/bitteam.py +167 -25
  232. ccxt/{huobijp.py → bittrade.py} +158 -30
  233. ccxt/bitvavo.py +213 -49
  234. ccxt/blockchaincom.py +160 -46
  235. ccxt/blofin.py +502 -120
  236. ccxt/btcalpha.py +169 -31
  237. ccxt/btcbox.py +291 -23
  238. ccxt/btcmarkets.py +211 -58
  239. ccxt/btcturk.py +161 -38
  240. ccxt/bybit.py +1775 -1030
  241. ccxt/cex.py +1439 -1303
  242. ccxt/coinbase.py +724 -212
  243. ccxt/coinbaseadvanced.py +2 -1
  244. ccxt/coinbaseexchange.py +388 -89
  245. ccxt/coinbaseinternational.py +412 -57
  246. ccxt/coincatch.py +177 -78
  247. ccxt/coincheck.py +135 -19
  248. ccxt/coinex.py +606 -232
  249. ccxt/coinmate.py +189 -63
  250. ccxt/coinmetro.py +194 -54
  251. ccxt/coinone.py +158 -51
  252. ccxt/coinsph.py +336 -61
  253. ccxt/coinspot.py +151 -52
  254. ccxt/cryptocom.py +661 -111
  255. ccxt/cryptomus.py +1137 -0
  256. ccxt/defx.py +2070 -0
  257. ccxt/delta.py +299 -99
  258. ccxt/deribit.py +348 -126
  259. ccxt/derive.py +2571 -0
  260. ccxt/digifinex.py +430 -214
  261. ccxt/ellipx.py +2029 -0
  262. ccxt/eterex.py +7 -7
  263. ccxt/excoino.py +29 -29
  264. ccxt/exir.py +11 -11
  265. ccxt/exmo.py +343 -131
  266. ccxt/exnovin.py +8 -8
  267. ccxt/farhadexchange.py +10 -10
  268. ccxt/fmfwio.py +2 -1
  269. ccxt/foxbit.py +1935 -0
  270. ccxt/gate.py +1351 -529
  271. ccxt/gateio.py +2 -1
  272. ccxt/gemini.py +144 -39
  273. ccxt/hashkey.py +152 -109
  274. ccxt/hibachi.py +2079 -0
  275. ccxt/hitbtc.py +395 -167
  276. ccxt/hitobit.py +9 -9
  277. ccxt/hollaex.py +307 -119
  278. ccxt/htx.py +851 -383
  279. ccxt/huobi.py +2 -1
  280. ccxt/hyperliquid.py +1848 -536
  281. ccxt/independentreserve.py +287 -15
  282. ccxt/indodax.py +190 -33
  283. ccxt/jibitex.py +9 -9
  284. ccxt/kraken.py +794 -351
  285. ccxt/krakenfutures.py +214 -62
  286. ccxt/kucoin.py +715 -396
  287. ccxt/kucoinfutures.py +652 -89
  288. ccxt/latoken.py +217 -113
  289. ccxt/lbank.py +425 -97
  290. ccxt/luno.py +382 -35
  291. ccxt/mercado.py +113 -6
  292. ccxt/mexc.py +873 -437
  293. ccxt/modetrade.py +2818 -0
  294. ccxt/myokx.py +54 -0
  295. ccxt/ndax.py +221 -64
  296. ccxt/nobitex.py +29 -35
  297. ccxt/novadax.py +190 -34
  298. ccxt/oceanex.py +217 -28
  299. ccxt/okcoin.py +253 -145
  300. ccxt/okexchange.py +9 -9
  301. ccxt/okx.py +1088 -351
  302. ccxt/okxus.py +54 -0
  303. ccxt/ompfinex.py +22 -21
  304. ccxt/onetrading.py +213 -392
  305. ccxt/oxfun.py +245 -166
  306. ccxt/p2b.py +151 -29
  307. ccxt/paradex.py +562 -49
  308. ccxt/paymium.py +82 -19
  309. ccxt/phemex.py +712 -172
  310. ccxt/poloniex.py +1601 -283
  311. ccxt/pro/__init__.py +76 -17
  312. ccxt/pro/alpaca.py +21 -6
  313. ccxt/pro/apex.py +984 -0
  314. ccxt/pro/ascendex.py +58 -10
  315. ccxt/pro/bequant.py +6 -1
  316. ccxt/pro/binance.py +728 -156
  317. ccxt/pro/binancecoinm.py +6 -2
  318. ccxt/pro/binanceus.py +8 -4
  319. ccxt/pro/binanceusdm.py +7 -2
  320. ccxt/pro/bingx.py +333 -142
  321. ccxt/pro/bitfinex.py +727 -262
  322. ccxt/pro/bitget.py +570 -79
  323. ccxt/pro/bithumb.py +20 -6
  324. ccxt/pro/bitmart.py +216 -87
  325. ccxt/pro/bitmex.py +47 -9
  326. ccxt/pro/bitopro.py +26 -14
  327. ccxt/pro/bitrue.py +22 -22
  328. ccxt/pro/bitstamp.py +54 -21
  329. ccxt/pro/{huobijp.py → bittrade.py} +7 -6
  330. ccxt/pro/bitvavo.py +191 -67
  331. ccxt/pro/blockchaincom.py +21 -8
  332. ccxt/pro/blofin.py +9 -1
  333. ccxt/pro/bybit.py +632 -245
  334. ccxt/pro/cex.py +59 -24
  335. ccxt/pro/coinbase.py +102 -73
  336. ccxt/pro/coinbaseadvanced.py +2 -1
  337. ccxt/pro/coinbaseexchange.py +8 -8
  338. ccxt/pro/coinbaseinternational.py +181 -25
  339. ccxt/pro/coincatch.py +6 -7
  340. ccxt/pro/coincheck.py +11 -6
  341. ccxt/pro/coinex.py +967 -665
  342. ccxt/pro/coinone.py +16 -9
  343. ccxt/pro/cryptocom.py +448 -45
  344. ccxt/pro/defx.py +831 -0
  345. ccxt/pro/deribit.py +150 -14
  346. ccxt/pro/derive.py +704 -0
  347. ccxt/pro/exmo.py +239 -6
  348. ccxt/pro/gate.py +623 -65
  349. ccxt/pro/gateio.py +2 -1
  350. ccxt/pro/gemini.py +27 -11
  351. ccxt/pro/hashkey.py +2 -2
  352. ccxt/pro/hitbtc.py +196 -91
  353. ccxt/pro/hollaex.py +23 -7
  354. ccxt/pro/htx.py +51 -14
  355. ccxt/pro/huobi.py +2 -1
  356. ccxt/pro/hyperliquid.py +591 -27
  357. ccxt/pro/independentreserve.py +9 -6
  358. ccxt/pro/kraken.py +640 -320
  359. ccxt/pro/krakenfutures.py +62 -35
  360. ccxt/pro/kucoin.py +267 -46
  361. ccxt/pro/kucoinfutures.py +165 -21
  362. ccxt/pro/lbank.py +102 -21
  363. ccxt/pro/luno.py +12 -8
  364. ccxt/pro/mexc.py +877 -111
  365. ccxt/pro/modetrade.py +1271 -0
  366. ccxt/pro/myokx.py +38 -0
  367. ccxt/pro/ndax.py +15 -2
  368. ccxt/pro/okcoin.py +23 -4
  369. ccxt/pro/okx.py +573 -98
  370. ccxt/pro/okxus.py +38 -0
  371. ccxt/pro/onetrading.py +30 -13
  372. ccxt/pro/oxfun.py +131 -27
  373. ccxt/pro/p2b.py +88 -22
  374. ccxt/pro/paradex.py +3 -3
  375. ccxt/pro/phemex.py +75 -21
  376. ccxt/pro/poloniex.py +124 -41
  377. ccxt/pro/probit.py +87 -80
  378. ccxt/pro/tradeogre.py +272 -0
  379. ccxt/pro/upbit.py +152 -12
  380. ccxt/pro/vertex.py +8 -3
  381. ccxt/pro/whitebit.py +58 -5
  382. ccxt/pro/woo.py +228 -37
  383. ccxt/pro/woofipro.py +106 -18
  384. ccxt/pro/xt.py +111 -5
  385. ccxt/probit.py +224 -95
  386. ccxt/protobuf/__init__.py +0 -0
  387. ccxt/protobuf/mexc/PrivateAccountV3Api_pb2.py +37 -0
  388. ccxt/protobuf/mexc/PrivateDealsV3Api_pb2.py +37 -0
  389. ccxt/protobuf/mexc/PrivateOrdersV3Api_pb2.py +37 -0
  390. ccxt/protobuf/mexc/PublicAggreBookTickerV3Api_pb2.py +37 -0
  391. ccxt/protobuf/mexc/PublicAggreDealsV3Api_pb2.py +39 -0
  392. ccxt/protobuf/mexc/PublicAggreDepthsV3Api_pb2.py +39 -0
  393. ccxt/protobuf/mexc/PublicBookTickerBatchV3Api_pb2.py +38 -0
  394. ccxt/protobuf/mexc/PublicBookTickerV3Api_pb2.py +37 -0
  395. ccxt/protobuf/mexc/PublicDealsV3Api_pb2.py +39 -0
  396. ccxt/protobuf/mexc/PublicIncreaseDepthsBatchV3Api_pb2.py +38 -0
  397. ccxt/protobuf/mexc/PublicIncreaseDepthsV3Api_pb2.py +39 -0
  398. ccxt/protobuf/mexc/PublicLimitDepthsV3Api_pb2.py +39 -0
  399. ccxt/protobuf/mexc/PublicMiniTickerV3Api_pb2.py +37 -0
  400. ccxt/protobuf/mexc/PublicMiniTickersV3Api_pb2.py +38 -0
  401. ccxt/protobuf/mexc/PublicSpotKlineV3Api_pb2.py +37 -0
  402. ccxt/protobuf/mexc/PushDataV3ApiWrapper_pb2.py +52 -0
  403. ccxt/protobuf/mexc/__init__.py +0 -0
  404. ccxt/ramzinex.py +28 -25
  405. ccxt/sarmayex.py +7 -7
  406. ccxt/sarrafex.py +10 -10
  407. ccxt/static_dependencies/__init__.py +1 -1
  408. ccxt/static_dependencies/lark/py.typed +0 -0
  409. ccxt/static_dependencies/marshmallow/py.typed +0 -0
  410. ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
  411. ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
  412. ccxt/tabdeal.py +12 -11
  413. ccxt/test/tests_async.py +261 -57
  414. ccxt/test/tests_helpers.py +1 -3
  415. ccxt/test/tests_init.py +4 -3
  416. ccxt/test/tests_sync.py +261 -57
  417. ccxt/tetherland.py +7 -7
  418. ccxt/timex.py +210 -51
  419. ccxt/tokocrypto.py +167 -47
  420. ccxt/tradeogre.py +266 -31
  421. ccxt/twox.py +7 -7
  422. ccxt/ubitex.py +9 -9
  423. ccxt/upbit.py +568 -165
  424. ccxt/vertex.py +160 -32
  425. ccxt/wallex.py +9 -9
  426. ccxt/wavesexchange.py +165 -30
  427. ccxt/whitebit.py +975 -127
  428. ccxt/woo.py +1917 -1016
  429. ccxt/woofipro.py +432 -141
  430. ccxt/xt.py +649 -193
  431. ccxt/yobit.py +194 -70
  432. ccxt/zaif.py +91 -15
  433. ccxt/zonda.py +151 -36
  434. {ccxt_ir-4.3.46.0.2.dist-info → ccxt_ir-4.5.0.dist-info}/METADATA +225 -73
  435. ccxt_ir-4.5.0.dist-info/RECORD +743 -0
  436. {ccxt_ir-4.3.46.0.2.dist-info → ccxt_ir-4.5.0.dist-info}/WHEEL +1 -1
  437. ccxt/abstract/ace.py +0 -15
  438. ccxt/abstract/bitbay.py +0 -53
  439. ccxt/abstract/bitcoincom.py +0 -115
  440. ccxt/abstract/bitfinex2.py +0 -139
  441. ccxt/abstract/bitpanda.py +0 -35
  442. ccxt/abstract/bl3p.py +0 -19
  443. ccxt/abstract/coinlist.py +0 -54
  444. ccxt/abstract/currencycom.py +0 -68
  445. ccxt/abstract/hitbtc3.py +0 -115
  446. ccxt/abstract/idex.py +0 -26
  447. ccxt/abstract/kuna.py +0 -182
  448. ccxt/abstract/lykke.py +0 -29
  449. ccxt/abstract/poloniexfutures.py +0 -48
  450. ccxt/abstract/wazirx.py +0 -30
  451. ccxt/ace.py +0 -1012
  452. ccxt/async_support/ace.py +0 -1012
  453. ccxt/async_support/base/ws/aiohttp_client.py +0 -125
  454. ccxt/async_support/base/ws/fast_client.py +0 -96
  455. ccxt/async_support/bitbay.py +0 -17
  456. ccxt/async_support/bitcoincom.py +0 -17
  457. ccxt/async_support/bitfinex2.py +0 -3552
  458. ccxt/async_support/bitpanda.py +0 -16
  459. ccxt/async_support/bl3p.py +0 -485
  460. ccxt/async_support/coinlist.py +0 -2243
  461. ccxt/async_support/currencycom.py +0 -1950
  462. ccxt/async_support/hitbtc3.py +0 -16
  463. ccxt/async_support/idex.py +0 -1766
  464. ccxt/async_support/kuna.py +0 -1841
  465. ccxt/async_support/lykke.py +0 -1270
  466. ccxt/async_support/poloniexfutures.py +0 -1717
  467. ccxt/async_support/wazirx.py +0 -1224
  468. ccxt/bitbay.py +0 -17
  469. ccxt/bitcoincom.py +0 -17
  470. ccxt/bitfinex2.py +0 -3552
  471. ccxt/bitpanda.py +0 -16
  472. ccxt/bl3p.py +0 -485
  473. ccxt/coinlist.py +0 -2243
  474. ccxt/currencycom.py +0 -1950
  475. ccxt/hitbtc3.py +0 -16
  476. ccxt/idex.py +0 -1766
  477. ccxt/kuna.py +0 -1841
  478. ccxt/lykke.py +0 -1270
  479. ccxt/poloniexfutures.py +0 -1717
  480. ccxt/pro/bitcoincom.py +0 -34
  481. ccxt/pro/bitfinex2.py +0 -1083
  482. ccxt/pro/bitpanda.py +0 -15
  483. ccxt/pro/currencycom.py +0 -536
  484. ccxt/pro/idex.py +0 -672
  485. ccxt/pro/poloniexfutures.py +0 -990
  486. ccxt/pro/wazirx.py +0 -749
  487. ccxt/test/base/__init__.py +0 -29
  488. ccxt/test/base/test_account.py +0 -26
  489. ccxt/test/base/test_balance.py +0 -56
  490. ccxt/test/base/test_borrow_interest.py +0 -35
  491. ccxt/test/base/test_borrow_rate.py +0 -32
  492. ccxt/test/base/test_calculate_fee.py +0 -51
  493. ccxt/test/base/test_crypto.py +0 -127
  494. ccxt/test/base/test_currency.py +0 -76
  495. ccxt/test/base/test_datetime.py +0 -109
  496. ccxt/test/base/test_decimal_to_precision.py +0 -392
  497. ccxt/test/base/test_deep_extend.py +0 -68
  498. ccxt/test/base/test_deposit_withdrawal.py +0 -50
  499. ccxt/test/base/test_exchange_datetime_functions.py +0 -76
  500. ccxt/test/base/test_funding_rate_history.py +0 -29
  501. ccxt/test/base/test_last_price.py +0 -31
  502. ccxt/test/base/test_ledger_entry.py +0 -45
  503. ccxt/test/base/test_ledger_item.py +0 -48
  504. ccxt/test/base/test_leverage_tier.py +0 -33
  505. ccxt/test/base/test_liquidation.py +0 -50
  506. ccxt/test/base/test_margin_mode.py +0 -24
  507. ccxt/test/base/test_margin_modification.py +0 -35
  508. ccxt/test/base/test_market.py +0 -193
  509. ccxt/test/base/test_number.py +0 -411
  510. ccxt/test/base/test_ohlcv.py +0 -33
  511. ccxt/test/base/test_open_interest.py +0 -32
  512. ccxt/test/base/test_order.py +0 -64
  513. ccxt/test/base/test_order_book.py +0 -69
  514. ccxt/test/base/test_position.py +0 -60
  515. ccxt/test/base/test_shared_methods.py +0 -353
  516. ccxt/test/base/test_status.py +0 -24
  517. ccxt/test/base/test_throttle.py +0 -126
  518. ccxt/test/base/test_ticker.py +0 -92
  519. ccxt/test/base/test_trade.py +0 -47
  520. ccxt/test/base/test_trading_fee.py +0 -26
  521. ccxt/test/base/test_transaction.py +0 -39
  522. ccxt/test/test_async.py +0 -1649
  523. ccxt/test/test_sync.py +0 -1648
  524. ccxt/wazirx.py +0 -1224
  525. ccxt_ir-4.3.46.0.2.dist-info/RECORD +0 -772
  526. /ccxt/abstract/{huobijp.py → bittrade.py} +0 -0
  527. {ccxt_ir-4.3.46.0.2.dist-info → ccxt_ir-4.5.0.dist-info/licenses}/LICENSE.txt +0 -0
  528. {ccxt_ir-4.3.46.0.2.dist-info → ccxt_ir-4.5.0.dist-info}/top_level.txt +0 -0
ccxt/pro/kraken.py CHANGED
@@ -5,13 +5,14 @@
5
5
 
6
6
  import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
8
- from ccxt.base.types import Int, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade
8
+ from ccxt.base.types import Any, Balances, Bool, Int, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade
9
9
  from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import AuthenticationError
13
13
  from ccxt.base.errors import PermissionDenied
14
14
  from ccxt.base.errors import AccountSuspended
15
+ from ccxt.base.errors import ArgumentsRequired
15
16
  from ccxt.base.errors import BadRequest
16
17
  from ccxt.base.errors import BadSymbol
17
18
  from ccxt.base.errors import InsufficientFunds
@@ -20,17 +21,17 @@ from ccxt.base.errors import OrderNotFound
20
21
  from ccxt.base.errors import NotSupported
21
22
  from ccxt.base.errors import RateLimitExceeded
22
23
  from ccxt.base.errors import ExchangeNotAvailable
23
- from ccxt.base.errors import InvalidNonce
24
+ from ccxt.base.errors import ChecksumError
24
25
  from ccxt.base.precise import Precise
25
26
 
26
27
 
27
28
  class kraken(ccxt.async_support.kraken):
28
29
 
29
- def describe(self):
30
+ def describe(self) -> Any:
30
31
  return self.deep_extend(super(kraken, self).describe(), {
31
32
  'has': {
32
33
  'ws': True,
33
- 'watchBalance': False, # no such type of subscription 2021-01-05
34
+ 'watchBalance': True,
34
35
  'watchMyTrades': True,
35
36
  'watchOHLCV': True,
36
37
  'watchOrderBook': True,
@@ -38,6 +39,7 @@ class kraken(ccxt.async_support.kraken):
38
39
  'watchOrders': True,
39
40
  'watchTicker': True,
40
41
  'watchTickers': True,
42
+ 'watchBidsAsks': True,
41
43
  'watchTrades': True,
42
44
  'watchTradesForSymbols': True,
43
45
  'createOrderWs': True,
@@ -53,6 +55,8 @@ class kraken(ccxt.async_support.kraken):
53
55
  'ws': {
54
56
  'public': 'wss://ws.kraken.com',
55
57
  'private': 'wss://ws-auth.kraken.com',
58
+ 'privateV2': 'wss://ws-auth.kraken.com/v2',
59
+ 'publicV2': 'wss://ws.kraken.com/v2',
56
60
  'beta': 'wss://beta-ws.kraken.com',
57
61
  'beta-private': 'wss://beta-ws-auth.kraken.com',
58
62
  },
@@ -66,7 +70,13 @@ class kraken(ccxt.async_support.kraken):
66
70
  'OHLCVLimit': 1000,
67
71
  'ordersLimit': 1000,
68
72
  'symbolsByOrderId': {},
69
- 'checksum': True,
73
+ 'watchOrderBook': {
74
+ 'checksum': False,
75
+ },
76
+ },
77
+ 'streaming': {
78
+ 'ping': self.ping,
79
+ 'keepAlive': 6000,
70
80
  },
71
81
  'exceptions': {
72
82
  'ws': {
@@ -76,6 +86,7 @@ class kraken(ccxt.async_support.kraken):
76
86
  'broad': {
77
87
  'Already subscribed': BadRequest,
78
88
  'Currency pair not in ISO 4217-A3 format': BadSymbol,
89
+ 'Currency pair not supported': BadSymbol,
79
90
  'Malformed request': BadRequest,
80
91
  'Pair field must be an array': BadRequest,
81
92
  'Pair field unsupported for self subscription type': BadRequest,
@@ -118,159 +129,310 @@ class kraken(ccxt.async_support.kraken):
118
129
  'EService:Market in post_only mode': NotSupported,
119
130
  'EService:Unavailable': ExchangeNotAvailable,
120
131
  'ETrade:Invalid request': BadRequest,
132
+ 'ESession:Invalid session': AuthenticationError,
121
133
  },
122
134
  },
123
135
  },
124
136
  })
125
137
 
138
+ def order_request_ws(self, method: str, symbol: str, type: str, request: dict, amount: Num, price: Num = None, params={}):
139
+ isLimitOrder = type.endswith('limit') # supporting limit, stop-loss-limit, take-profit-limit, etc
140
+ if isLimitOrder:
141
+ if price is None:
142
+ raise ArgumentsRequired(self.id + ' limit orders require a price argument')
143
+ request['params']['limit_price'] = self.parse_to_numeric(self.price_to_precision(symbol, price))
144
+ isMarket = (type == 'market')
145
+ postOnly = None
146
+ postOnly, params = self.handle_post_only(isMarket, False, params)
147
+ if postOnly:
148
+ request['params']['post_only'] = True
149
+ clientOrderId = self.safe_string(params, 'clientOrderId')
150
+ if clientOrderId is not None:
151
+ request['params']['cl_ord_id'] = clientOrderId
152
+ cost = self.safe_string(params, 'cost')
153
+ if cost is not None:
154
+ request['params']['order_qty'] = self.parse_to_numeric(self.cost_to_precision(symbol, cost))
155
+ stopLoss = self.safe_dict(params, 'stopLoss', {})
156
+ takeProfit = self.safe_dict(params, 'takeProfit', {})
157
+ presetStopLoss = self.safe_string(stopLoss, 'triggerPrice')
158
+ presetTakeProfit = self.safe_string(takeProfit, 'triggerPrice')
159
+ presetStopLossLimit = self.safe_string(stopLoss, 'price')
160
+ presetTakeProfitLimit = self.safe_string(takeProfit, 'price')
161
+ isPresetStopLoss = presetStopLoss is not None
162
+ isPresetTakeProfit = presetTakeProfit is not None
163
+ stopLossPrice = self.safe_string(params, 'stopLossPrice')
164
+ takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
165
+ isStopLossPriceOrder = stopLossPrice is not None
166
+ isTakeProfitPriceOrder = takeProfitPrice is not None
167
+ trailingAmount = self.safe_string(params, 'trailingAmount')
168
+ trailingPercent = self.safe_string(params, 'trailingPercent')
169
+ trailingLimitAmount = self.safe_string(params, 'trailingLimitAmount')
170
+ trailingLimitPercent = self.safe_string(params, 'trailingLimitPercent')
171
+ isTrailingAmountOrder = trailingAmount is not None
172
+ isTrailingPercentOrder = trailingPercent is not None
173
+ isTrailingLimitAmountOrder = trailingLimitAmount is not None
174
+ isTrailingLimitPercentOrder = trailingLimitPercent is not None
175
+ offset = self.safe_string(params, 'offset', '') # can set self to - for minus
176
+ trailingAmountString = offset + self.number_to_string(trailingAmount) if (trailingAmount is not None) else None
177
+ trailingPercentString = offset + self.number_to_string(trailingPercent) if (trailingPercent is not None) else None
178
+ trailingLimitAmountString = offset + self.number_to_string(trailingLimitAmount) if (trailingLimitAmount is not None) else None
179
+ trailingLimitPercentString = offset + self.number_to_string(trailingLimitPercent) if (trailingLimitPercent is not None) else None
180
+ priceType = 'pct' if (isTrailingPercentOrder or isTrailingLimitPercentOrder) else 'quote'
181
+ if method == 'createOrderWs':
182
+ reduceOnly = self.safe_bool(params, 'reduceOnly')
183
+ if reduceOnly:
184
+ request['params']['reduce_only'] = True
185
+ timeInForce = self.safe_string_lower(params, 'timeInForce')
186
+ if timeInForce is not None:
187
+ request['params']['time_in_force'] = timeInForce
188
+ params = self.omit(params, ['reduceOnly', 'timeInForce'])
189
+ if isStopLossPriceOrder or isTakeProfitPriceOrder or isTrailingAmountOrder or isTrailingPercentOrder or isTrailingLimitAmountOrder or isTrailingLimitPercentOrder:
190
+ request['params']['triggers'] = {}
191
+ if isPresetStopLoss or isPresetTakeProfit:
192
+ request['params']['conditional'] = {}
193
+ if isPresetStopLoss:
194
+ request['params']['conditional']['order_type'] = 'stop-loss'
195
+ request['params']['conditional']['trigger_price'] = self.parse_to_numeric(self.price_to_precision(symbol, presetStopLoss))
196
+ elif isPresetTakeProfit:
197
+ request['params']['conditional']['order_type'] = 'take-profit'
198
+ request['params']['conditional']['trigger_price'] = self.parse_to_numeric(self.price_to_precision(symbol, presetTakeProfit))
199
+ if presetStopLossLimit is not None:
200
+ request['params']['conditional']['order_type'] = 'stop-loss-limit'
201
+ request['params']['conditional']['limit_price'] = self.parse_to_numeric(self.price_to_precision(symbol, presetStopLossLimit))
202
+ elif presetTakeProfitLimit is not None:
203
+ request['params']['conditional']['order_type'] = 'take-profit-limit'
204
+ request['params']['conditional']['limit_price'] = self.parse_to_numeric(self.price_to_precision(symbol, presetTakeProfitLimit))
205
+ params = self.omit(params, ['stopLoss', 'takeProfit'])
206
+ elif isStopLossPriceOrder or isTakeProfitPriceOrder:
207
+ if isStopLossPriceOrder:
208
+ request['params']['triggers']['price'] = self.parse_to_numeric(self.price_to_precision(symbol, stopLossPrice))
209
+ if isLimitOrder:
210
+ request['params']['order_type'] = 'stop-loss-limit'
211
+ else:
212
+ request['params']['order_type'] = 'stop-loss'
213
+ else:
214
+ request['params']['triggers']['price'] = self.parse_to_numeric(self.price_to_precision(symbol, takeProfitPrice))
215
+ if isLimitOrder:
216
+ request['params']['order_type'] = 'take-profit-limit'
217
+ else:
218
+ request['params']['order_type'] = 'take-profit'
219
+ elif isTrailingAmountOrder or isTrailingPercentOrder or isTrailingLimitAmountOrder or isTrailingLimitPercentOrder:
220
+ request['params']['triggers']['price_type'] = priceType
221
+ if not isLimitOrder and (isTrailingAmountOrder or isTrailingPercentOrder):
222
+ request['params']['order_type'] = 'trailing-stop'
223
+ if isTrailingAmountOrder:
224
+ request['params']['triggers']['price'] = self.parse_to_numeric(trailingAmountString)
225
+ else:
226
+ request['params']['triggers']['price'] = self.parse_to_numeric(trailingPercentString)
227
+ else:
228
+ # trailing limit orders are not conventionally supported because the static limit_price_type param is not available for trailing-stop-limit orders
229
+ request['params']['limit_price_type'] = priceType
230
+ request['params']['order_type'] = 'trailing-stop-limit'
231
+ if isTrailingLimitAmountOrder:
232
+ request['params']['triggers']['price'] = self.parse_to_numeric(trailingLimitAmountString)
233
+ else:
234
+ request['params']['triggers']['price'] = self.parse_to_numeric(trailingLimitPercentString)
235
+ elif method == 'editOrderWs':
236
+ if isPresetStopLoss or isPresetTakeProfit:
237
+ raise NotSupported(self.id + ' editing the stopLoss and takeProfit on existing orders is currently not supported')
238
+ if isStopLossPriceOrder or isTakeProfitPriceOrder:
239
+ if isStopLossPriceOrder:
240
+ request['params']['trigger_price'] = self.parse_to_numeric(self.price_to_precision(symbol, stopLossPrice))
241
+ else:
242
+ request['params']['trigger_price'] = self.parse_to_numeric(self.price_to_precision(symbol, takeProfitPrice))
243
+ elif isTrailingAmountOrder or isTrailingPercentOrder or isTrailingLimitAmountOrder or isTrailingLimitPercentOrder:
244
+ request['params']['trigger_price_type'] = priceType
245
+ if not isLimitOrder and (isTrailingAmountOrder or isTrailingPercentOrder):
246
+ if isTrailingAmountOrder:
247
+ request['params']['trigger_price'] = self.parse_to_numeric(trailingAmountString)
248
+ else:
249
+ request['params']['trigger_price'] = self.parse_to_numeric(trailingPercentString)
250
+ else:
251
+ request['params']['limit_price_type'] = priceType
252
+ if isTrailingLimitAmountOrder:
253
+ request['params']['trigger_price'] = self.parse_to_numeric(trailingLimitAmountString)
254
+ else:
255
+ request['params']['trigger_price'] = self.parse_to_numeric(trailingLimitPercentString)
256
+ params = self.omit(params, ['clientOrderId', 'cost', 'offset', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingLimitAmount', 'trailingLimitPercent'])
257
+ return [request, params]
258
+
126
259
  async def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
127
260
  """
128
- :see: https://docs.kraken.com/websockets/#message-addOrder
129
261
  create a trade order
262
+
263
+ https://docs.kraken.com/api/docs/websocket-v2/add_order
264
+
130
265
  :param str symbol: unified symbol of the market to create an order in
131
266
  :param str type: 'market' or 'limit'
132
267
  :param str side: 'buy' or 'sell'
133
268
  :param float amount: how much of currency you want to trade in units of base currency
134
- :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
269
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
135
270
  :param dict [params]: extra parameters specific to the exchange API endpoint
136
271
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
137
272
  """
138
273
  await self.load_markets()
139
274
  token = await self.authenticate()
140
275
  market = self.market(symbol)
141
- url = self.urls['api']['ws']['private']
276
+ url = self.urls['api']['ws']['privateV2']
142
277
  requestId = self.request_id()
143
278
  messageHash = requestId
144
279
  request: dict = {
145
- 'event': 'addOrder',
146
- 'token': token,
147
- 'reqid': requestId,
148
- 'ordertype': type,
149
- 'type': side,
150
- 'pair': market['wsId'],
151
- 'volume': self.amount_to_precision(symbol, amount),
280
+ 'method': 'add_order',
281
+ 'params': {
282
+ 'order_type': type,
283
+ 'side': side,
284
+ 'order_qty': self.parse_to_numeric(self.amount_to_precision(symbol, amount)),
285
+ 'symbol': market['symbol'],
286
+ 'token': token,
287
+ },
288
+ 'req_id': requestId,
152
289
  }
153
- request, params = self.orderRequest('createOrderWs', symbol, type, request, amount, price, params)
290
+ request, params = self.order_request_ws('createOrderWs', symbol, type, request, amount, price, params)
154
291
  return await self.watch(url, messageHash, self.extend(request, params), messageHash)
155
292
 
156
293
  def handle_create_edit_order(self, client, message):
157
294
  #
158
295
  # createOrder
159
- # {
160
- # "descr": "sell 0.00010000 XBTUSDT @ market",
161
- # "event": "addOrderStatus",
162
- # "reqid": 1,
163
- # "status": "ok",
164
- # "txid": "OAVXZH-XIE54-JCYYDG"
165
- # }
296
+ # {
297
+ # "method": "add_order",
298
+ # "req_id": 1,
299
+ # "result": {
300
+ # "order_id": "OXM2QD-EALR2-YBAVEU"
301
+ # },
302
+ # "success": True,
303
+ # "time_in": "2025-05-13T10:12:13.876173Z",
304
+ # "time_out": "2025-05-13T10:12:13.890137Z"
305
+ # }
306
+ #
166
307
  # editOrder
167
- # {
168
- # "descr": "order edited price = 9000.00000000",
169
- # "event": "editOrderStatus",
170
- # "originaltxid": "O65KZW-J4AW3-VFS74A",
171
- # "reqid": 3,
172
- # "status": "ok",
173
- # "txid": "OTI672-HJFAO-XOIPPK"
174
- # }
308
+ # {
309
+ # "method": "amend_order",
310
+ # "req_id": 1,
311
+ # "result": {
312
+ # "amend_id": "TYDLSQ-OYNYU-3MNRER",
313
+ # "order_id": "OGL7HR-SWFO4-NRQTHO"
314
+ # },
315
+ # "success": True,
316
+ # "time_in": "2025-05-14T13:54:10.840342Z",
317
+ # "time_out": "2025-05-14T13:54:10.855046Z"
318
+ # }
175
319
  #
176
- order = self.parse_order(message)
177
- messageHash = self.safe_value(message, 'reqid')
320
+ result = self.safe_dict(message, 'result', {})
321
+ order = self.parse_order(result)
322
+ messageHash = self.safe_value_2(message, 'reqid', 'req_id')
178
323
  client.resolve(order, messageHash)
179
324
 
180
325
  async def edit_order_ws(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}) -> Order:
181
326
  """
182
327
  edit a trade order
183
- :see: https://docs.kraken.com/websockets/#message-editOrder
328
+
329
+ https://docs.kraken.com/api/docs/websocket-v2/amend_order
330
+
184
331
  :param str id: order id
185
332
  :param str symbol: unified symbol of the market to create an order in
186
333
  :param str type: 'market' or 'limit'
187
334
  :param str side: 'buy' or 'sell'
188
335
  :param float amount: how much of the currency you want to trade in units of the base currency
189
- :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
336
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
190
337
  :param dict [params]: extra parameters specific to the exchange API endpoint
191
338
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
192
339
  """
193
340
  await self.load_markets()
194
341
  token = await self.authenticate()
195
- market = self.market(symbol)
196
- url = self.urls['api']['ws']['private']
342
+ url = self.urls['api']['ws']['privateV2']
197
343
  requestId = self.request_id()
198
344
  messageHash = requestId
199
345
  request: dict = {
200
- 'event': 'editOrder',
201
- 'token': token,
202
- 'reqid': requestId,
203
- 'orderid': id,
204
- 'pair': market['wsId'],
346
+ 'method': 'amend_order',
347
+ 'params': {
348
+ 'order_id': id,
349
+ 'order_qty': self.parse_to_numeric(self.amount_to_precision(symbol, amount)),
350
+ 'token': token,
351
+ },
352
+ 'req_id': requestId,
205
353
  }
206
- if amount is not None:
207
- request['volume'] = self.amount_to_precision(symbol, amount)
208
- request, params = self.orderRequest('editOrderWs', symbol, type, request, amount, price, params)
354
+ request, params = self.order_request_ws('editOrderWs', symbol, type, request, amount, price, params)
209
355
  return await self.watch(url, messageHash, self.extend(request, params), messageHash)
210
356
 
211
357
  async def cancel_orders_ws(self, ids: List[str], symbol: Str = None, params={}):
212
358
  """
213
- :see: https://docs.kraken.com/websockets/#message-cancelOrder
214
359
  cancel multiple orders
360
+
361
+ https://docs.kraken.com/api/docs/websocket-v2/cancel_order
362
+
215
363
  :param str[] ids: order ids
216
- :param str symbol: unified market symbol, default is None
364
+ :param str [symbol]: unified market symbol, default is None
217
365
  :param dict [params]: extra parameters specific to the exchange API endpoint
218
366
  :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
219
367
  """
368
+ if symbol is not None:
369
+ raise NotSupported(self.id + ' cancelOrdersWs() does not support cancelling orders for a specific symbol.')
220
370
  await self.load_markets()
221
371
  token = await self.authenticate()
222
- url = self.urls['api']['ws']['private']
372
+ url = self.urls['api']['ws']['privateV2']
223
373
  requestId = self.request_id()
224
374
  messageHash = requestId
225
375
  request: dict = {
226
- 'event': 'cancelOrder',
227
- 'token': token,
228
- 'reqid': requestId,
229
- 'txid': ids,
376
+ 'method': 'cancel_order',
377
+ 'params': {
378
+ 'order_id': ids,
379
+ 'token': token,
380
+ },
381
+ 'req_id': requestId,
230
382
  }
231
383
  return await self.watch(url, messageHash, self.extend(request, params), messageHash)
232
384
 
233
385
  async def cancel_order_ws(self, id: str, symbol: Str = None, params={}) -> Order:
234
386
  """
235
- :see: https://docs.kraken.com/websockets/#message-cancelOrder
236
387
  cancels an open order
388
+
389
+ https://docs.kraken.com/api/docs/websocket-v2/cancel_order
390
+
237
391
  :param str id: order id
238
- :param str symbol: unified symbol of the market the order was made in
392
+ :param str [symbol]: unified symbol of the market the order was made in
239
393
  :param dict [params]: extra parameters specific to the exchange API endpoint
240
394
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
241
395
  """
396
+ if symbol is not None:
397
+ raise NotSupported(self.id + ' cancelOrderWs() does not support cancelling orders for a specific symbol.')
242
398
  await self.load_markets()
243
399
  token = await self.authenticate()
244
- url = self.urls['api']['ws']['private']
400
+ url = self.urls['api']['ws']['privateV2']
245
401
  requestId = self.request_id()
246
402
  messageHash = requestId
247
- clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId', id)
248
- params = self.omit(params, ['userref', 'clientOrderId'])
249
403
  request: dict = {
250
- 'event': 'cancelOrder',
251
- 'token': token,
252
- 'reqid': requestId,
253
- 'txid': [clientOrderId],
404
+ 'method': 'cancel_order',
405
+ 'params': {
406
+ 'order_id': [id],
407
+ 'token': token,
408
+ },
409
+ 'req_id': requestId,
254
410
  }
255
411
  return await self.watch(url, messageHash, self.extend(request, params), messageHash)
256
412
 
257
413
  def handle_cancel_order(self, client, message):
258
414
  #
259
- # success
260
- # {
261
- # "event": "cancelOrderStatus",
262
- # "status": "ok"
263
- # "reqid": 1,
264
- # }
415
+ # {
416
+ # "method": "cancel_order",
417
+ # "req_id": 123456789,
418
+ # "result": {
419
+ # "order_id": "OKAGJC-YHIWK-WIOZWG"
420
+ # },
421
+ # "success": True,
422
+ # "time_in": "2023-09-21T14:36:57.428972Z",
423
+ # "time_out": "2023-09-21T14:36:57.437952Z"
424
+ # }
265
425
  #
266
- reqId = self.safe_value(message, 'reqid')
426
+ reqId = self.safe_value(message, 'req_id')
267
427
  client.resolve(message, reqId)
268
428
 
269
429
  async def cancel_all_orders_ws(self, symbol: Str = None, params={}):
270
430
  """
271
- :see: https://docs.kraken.com/websockets/#message-cancelAll
272
431
  cancel all open orders
273
- :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
432
+
433
+ https://docs.kraken.com/api/docs/websocket-v2/cancel_all
434
+
435
+ :param str [symbol]: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
274
436
  :param dict [params]: extra parameters specific to the exchange API endpoint
275
437
  :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
276
438
  """
@@ -278,75 +440,84 @@ class kraken(ccxt.async_support.kraken):
278
440
  raise NotSupported(self.id + ' cancelAllOrdersWs() does not support cancelling orders in a specific market.')
279
441
  await self.load_markets()
280
442
  token = await self.authenticate()
281
- url = self.urls['api']['ws']['private']
443
+ url = self.urls['api']['ws']['privateV2']
282
444
  requestId = self.request_id()
283
445
  messageHash = requestId
284
446
  request: dict = {
285
- 'event': 'cancelAll',
286
- 'token': token,
287
- 'reqid': requestId,
447
+ 'method': 'cancel_all',
448
+ 'params': {
449
+ 'token': token,
450
+ },
451
+ 'req_id': requestId,
288
452
  }
289
453
  return await self.watch(url, messageHash, self.extend(request, params), messageHash)
290
454
 
291
455
  def handle_cancel_all_orders(self, client, message):
292
456
  #
293
- # {
294
- # "count": 2,
295
- # "event": "cancelAllStatus",
296
- # "status": "ok",
297
- # "reqId": 1
298
- # }
457
+ # {
458
+ # "method": "cancel_all",
459
+ # "req_id": 123456789,
460
+ # "result": {
461
+ # "count": 1
462
+ # },
463
+ # "success": True,
464
+ # "time_in": "2023-09-21T14:36:57.428972Z",
465
+ # "time_out": "2023-09-21T14:36:57.437952Z"
466
+ # }
299
467
  #
300
- reqId = self.safe_value(message, 'reqid')
468
+ reqId = self.safe_value(message, 'req_id')
301
469
  client.resolve(message, reqId)
302
470
 
303
- def handle_ticker(self, client, message, subscription):
471
+ def handle_ticker(self, client, message):
304
472
  #
305
- # [
306
- # 0, # channelID
307
- # {
308
- # "a": ["5525.40000", 1, "1.000"], # ask, wholeAskVolume, askVolume
309
- # "b": ["5525.10000", 1, "1.000"], # bid, wholeBidVolume, bidVolume
310
- # "c": ["5525.10000", "0.00398963"], # closing price, volume
311
- # "h": ["5783.00000", "5783.00000"], # high price today, high price 24h ago
312
- # "l": ["5505.00000", "5505.00000"], # low price today, low price 24h ago
313
- # "o": ["5760.70000", "5763.40000"], # open price today, open price 24h ago
314
- # "p": ["5631.44067", "5653.78939"], # vwap today, vwap 24h ago
315
- # "t": [11493, 16267], # number of trades today, 24 hours ago
316
- # "v": ["2634.11501494", "3591.17907851"], # volume today, volume 24 hours ago
317
- # },
318
- # "ticker",
319
- # "XBT/USD"
320
- # ]
473
+ # {
474
+ # "channel": "ticker",
475
+ # "type": "snapshot",
476
+ # "data": [
477
+ # {
478
+ # "symbol": "BTC/USD",
479
+ # "bid": 108359.8,
480
+ # "bid_qty": 0.01362603,
481
+ # "ask": 108359.9,
482
+ # "ask_qty": 17.17988863,
483
+ # "last": 108359.8,
484
+ # "volume": 2158.32346723,
485
+ # "vwap": 108894.5,
486
+ # "low": 106824,
487
+ # "high": 111300,
488
+ # "change": -2679.9,
489
+ # "change_pct": -2.41
490
+ # }
491
+ # ]
492
+ # }
321
493
  #
322
- wsName = message[3]
323
- market = self.safe_value(self.options['marketsByWsName'], wsName)
324
- symbol = market['symbol']
494
+ data = self.safe_list(message, 'data', [])
495
+ ticker = data[0]
496
+ symbol = self.safe_string(ticker, 'symbol')
325
497
  messageHash = self.get_message_hash('ticker', None, symbol)
326
- ticker = message[1]
327
- vwap = self.safe_string(ticker['p'], 0)
498
+ vwap = self.safe_string(ticker, 'vwap')
328
499
  quoteVolume = None
329
- baseVolume = self.safe_string(ticker['v'], 0)
500
+ baseVolume = self.safe_string(ticker, 'volume')
330
501
  if baseVolume is not None and vwap is not None:
331
502
  quoteVolume = Precise.string_mul(baseVolume, vwap)
332
- last = self.safe_string(ticker['c'], 0)
503
+ last = self.safe_string(ticker, 'last')
333
504
  result = self.safe_ticker({
334
505
  'symbol': symbol,
335
506
  'timestamp': None,
336
507
  'datetime': None,
337
- 'high': self.safe_string(ticker['h'], 0),
338
- 'low': self.safe_string(ticker['l'], 0),
339
- 'bid': self.safe_string(ticker['b'], 0),
340
- 'bidVolume': self.safe_string(ticker['b'], 2),
341
- 'ask': self.safe_string(ticker['a'], 0),
342
- 'askVolume': self.safe_string(ticker['a'], 2),
508
+ 'high': self.safe_string(ticker, 'high'),
509
+ 'low': self.safe_string(ticker, 'low'),
510
+ 'bid': self.safe_string(ticker, 'bid'),
511
+ 'bidVolume': self.safe_string(ticker, 'bid_qty'),
512
+ 'ask': self.safe_string(ticker, 'ask'),
513
+ 'askVolume': self.safe_string(ticker, 'ask_qty'),
343
514
  'vwap': vwap,
344
- 'open': self.safe_string(ticker['o'], 0),
515
+ 'open': None,
345
516
  'close': last,
346
517
  'last': last,
347
518
  'previousClose': None,
348
- 'change': None,
349
- 'percentage': None,
519
+ 'change': self.safe_string(ticker, 'change'),
520
+ 'percentage': self.safe_string(ticker, 'change_pct'),
350
521
  'average': None,
351
522
  'baseVolume': baseVolume,
352
523
  'quoteVolume': quoteVolume,
@@ -355,30 +526,35 @@ class kraken(ccxt.async_support.kraken):
355
526
  self.tickers[symbol] = result
356
527
  client.resolve(result, messageHash)
357
528
 
358
- def handle_trades(self, client: Client, message, subscription):
529
+ def handle_trades(self, client: Client, message):
359
530
  #
360
- # [
361
- # 0, # channelID
362
- # [ # price volume time side type misc
363
- # ["5541.20000", "0.15850568", "1534614057.321596", "s", "l", ""],
364
- # ["6060.00000", "0.02455000", "1534614057.324998", "b", "l", ""],
365
- # ],
366
- # "trade",
367
- # "XBT/USD"
368
- # ]
531
+ # {
532
+ # "channel": "trade",
533
+ # "type": "update",
534
+ # "data": [
535
+ # {
536
+ # "symbol": "MATIC/USD",
537
+ # "side": "sell",
538
+ # "price": 0.5117,
539
+ # "qty": 40.0,
540
+ # "ord_type": "market",
541
+ # "trade_id": 4665906,
542
+ # "timestamp": "2023-09-25T07:49:37.708706Z"
543
+ # }
544
+ # ]
545
+ # }
369
546
  #
370
- wsName = self.safe_string(message, 3)
371
- name = self.safe_string(message, 2)
372
- market = self.safe_value(self.options['marketsByWsName'], wsName)
373
- symbol = market['symbol']
374
- messageHash = self.get_message_hash(name, None, symbol)
547
+ data = self.safe_list(message, 'data', [])
548
+ trade = data[0]
549
+ symbol = self.safe_string(trade, 'symbol')
550
+ messageHash = self.get_message_hash('trade', None, symbol)
375
551
  stored = self.safe_value(self.trades, symbol)
376
552
  if stored is None:
377
553
  limit = self.safe_integer(self.options, 'tradesLimit', 1000)
378
554
  stored = ArrayCache(limit)
379
555
  self.trades[symbol] = stored
380
- trades = self.safe_value(message, 1, [])
381
- parsed = self.parse_trades(trades, market)
556
+ market = self.market(symbol)
557
+ parsed = self.parse_trades(data, market)
382
558
  for i in range(0, len(parsed)):
383
559
  stored.append(parsed[i])
384
560
  client.resolve(stored, messageHash)
@@ -462,6 +638,9 @@ class kraken(ccxt.async_support.kraken):
462
638
  async def watch_ticker(self, symbol: str, params={}) -> Ticker:
463
639
  """
464
640
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
641
+
642
+ https://docs.kraken.com/api/docs/websocket-v2/ticker
643
+
465
644
  :param str symbol: unified symbol of the market to fetch the ticker for
466
645
  :param dict [params]: extra parameters specific to the exchange API endpoint
467
646
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -474,7 +653,10 @@ class kraken(ccxt.async_support.kraken):
474
653
  async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
475
654
  """
476
655
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
477
- :param str symbol: unified symbol of the market to fetch the ticker for
656
+
657
+ https://docs.kraken.com/api/docs/websocket-v2/ticker
658
+
659
+ :param str[] symbols:
478
660
  :param dict [params]: extra parameters specific to the exchange API endpoint
479
661
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
480
662
  """
@@ -487,10 +669,32 @@ class kraken(ccxt.async_support.kraken):
487
669
  return result
488
670
  return self.filter_by_array(self.tickers, 'symbol', symbols)
489
671
 
672
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
673
+ """
674
+ watches best bid & ask for symbols
675
+
676
+ https://docs.kraken.com/api/docs/websocket-v2/ticker
677
+
678
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
679
+ :param dict [params]: extra parameters specific to the exchange API endpoint
680
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
681
+ """
682
+ await self.load_markets()
683
+ symbols = self.market_symbols(symbols, None, False)
684
+ params['event_trigger'] = 'bbo'
685
+ ticker = await self.watch_multi_helper('bidask', 'ticker', symbols, None, params)
686
+ if self.newUpdates:
687
+ result: dict = {}
688
+ result[ticker['symbol']] = ticker
689
+ return result
690
+ return self.filter_by_array(self.bidsasks, 'symbol', symbols)
691
+
490
692
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
491
693
  """
492
694
  get the list of most recent trades for a particular symbol
493
- :see: https://docs.kraken.com/websockets/#message-trade
695
+
696
+ https://docs.kraken.com/api/docs/websocket-v2/trade
697
+
494
698
  :param str symbol: unified symbol of the market to fetch trades for
495
699
  :param int [since]: timestamp in ms of the earliest trade to fetch
496
700
  :param int [limit]: the maximum amount of trades to fetch
@@ -501,8 +705,10 @@ class kraken(ccxt.async_support.kraken):
501
705
 
502
706
  async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
503
707
  """
504
- :see: https://docs.kraken.com/websockets/#message-trade
505
708
  get the list of most recent trades for a list of symbols
709
+
710
+ https://docs.kraken.com/api/docs/websocket-v2/trade
711
+
506
712
  :param str[] symbols: unified symbol of the market to fetch trades for
507
713
  :param int [since]: timestamp in ms of the earliest trade to fetch
508
714
  :param int [limit]: the maximum amount of trades to fetch
@@ -519,7 +725,9 @@ class kraken(ccxt.async_support.kraken):
519
725
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
520
726
  """
521
727
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
522
- :see: https://docs.kraken.com/websockets/#message-book
728
+
729
+ https://docs.kraken.com/api/docs/websocket-v2/book
730
+
523
731
  :param str symbol: unified symbol of the market to fetch the order book for
524
732
  :param int [limit]: the maximum amount of order book entries to return
525
733
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -530,26 +738,29 @@ class kraken(ccxt.async_support.kraken):
530
738
  async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
531
739
  """
532
740
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
533
- :see: https://docs.kraken.com/websockets/#message-book
741
+
742
+ https://docs.kraken.com/api/docs/websocket-v2/book
743
+
534
744
  :param str[] symbols: unified array of symbols
535
745
  :param int [limit]: the maximum amount of order book entries to return
536
746
  :param dict [params]: extra parameters specific to the exchange API endpoint
537
747
  :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
538
748
  """
539
- request: dict = {}
749
+ requiredParams: dict = {}
540
750
  if limit is not None:
541
751
  if self.in_array(limit, [10, 25, 100, 500, 1000]):
542
- request['subscription'] = {
543
- 'depth': limit, # default 10, valid options 10, 25, 100, 500, 1000
544
- }
752
+ requiredParams['depth'] = limit # default 10, valid options 10, 25, 100, 500, 1000
545
753
  else:
546
754
  raise NotSupported(self.id + ' watchOrderBook accepts limit values of 10, 25, 100, 500 and 1000 only')
547
- orderbook = await self.watch_multi_helper('orderbook', 'book', symbols, {'limit': limit}, self.extend(request, params))
755
+ orderbook = await self.watch_multi_helper('orderbook', 'book', symbols, {'limit': limit}, self.extend(requiredParams, params))
548
756
  return orderbook.limit()
549
757
 
550
758
  async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
551
759
  """
552
760
  watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
761
+
762
+ https://docs.kraken.com/api/docs/websocket-v1/ohlc
763
+
553
764
  :param str symbol: unified symbol of the market to fetch OHLCV data for
554
765
  :param str timeframe: the length of time each candle represents
555
766
  :param int [since]: timestamp in ms of the earliest candle to fetch
@@ -590,18 +801,25 @@ class kraken(ccxt.async_support.kraken):
590
801
  for i in range(0, len(self.symbols)):
591
802
  symbol = self.symbols[i]
592
803
  market = self.markets[symbol]
593
- if market['darkpool']:
594
- info = self.safe_value(market, 'info', {})
595
- altname = self.safe_string(info, 'altname')
596
- wsName = altname[0:3] + '/' + altname[3:]
597
- marketsByWsName[wsName] = market
598
- else:
599
- info = self.safe_value(market, 'info', {})
600
- wsName = self.safe_string(info, 'wsname')
601
- marketsByWsName[wsName] = market
804
+ info = self.safe_value(market, 'info', {})
805
+ wsName = self.safe_string(info, 'wsname')
806
+ marketsByWsName[wsName] = market
602
807
  self.options['marketsByWsName'] = marketsByWsName
603
808
  return markets
604
809
 
810
+ def ping(self, client: Client):
811
+ url = client.url
812
+ request = {}
813
+ if url.find('v2') >= 0:
814
+ request['method'] = 'ping'
815
+ else:
816
+ request['event'] = 'ping'
817
+ return request
818
+
819
+ def handle_pong(self, client: Client, message):
820
+ client.lastPong = self.milliseconds()
821
+ return message
822
+
605
823
  async def watch_heartbeat(self, params={}):
606
824
  await self.load_markets()
607
825
  event = 'heartbeat'
@@ -617,157 +835,151 @@ class kraken(ccxt.async_support.kraken):
617
835
  event = self.safe_string(message, 'event')
618
836
  client.resolve(message, event)
619
837
 
620
- def handle_order_book(self, client: Client, message, subscription):
838
+ def handle_order_book(self, client: Client, message):
621
839
  #
622
840
  # first message(snapshot)
623
841
  #
624
- # [
625
- # 1234, # channelID
626
- # {
627
- # "as": [
628
- # ["5541.30000", "2.50700000", "1534614248.123678"],
629
- # ["5541.80000", "0.33000000", "1534614098.345543"],
630
- # ["5542.70000", "0.64700000", "1534614244.654432"]
631
- # ],
632
- # "bs": [
633
- # ["5541.20000", "1.52900000", "1534614248.765567"],
634
- # ["5539.90000", "0.30000000", "1534614241.769870"],
635
- # ["5539.50000", "5.00000000", "1534613831.243486"]
636
- # ]
637
- # },
638
- # "book-10",
639
- # "XBT/USD"
640
- # ]
842
+ # {
843
+ # "channel": "book",
844
+ # "type": "snapshot",
845
+ # "data": [
846
+ # {
847
+ # "symbol": "MATIC/USD",
848
+ # "bids": [
849
+ # {
850
+ # "price": 0.5666,
851
+ # "qty": 4831.75496356
852
+ # },
853
+ # {
854
+ # "price": 0.5665,
855
+ # "qty": 6658.22734739
856
+ # }
857
+ # ],
858
+ # "asks": [
859
+ # {
860
+ # "price": 0.5668,
861
+ # "qty": 4410.79769741
862
+ # },
863
+ # {
864
+ # "price": 0.5669,
865
+ # "qty": 4655.40412487
866
+ # }
867
+ # ],
868
+ # "checksum": 2439117997
869
+ # }
870
+ # ]
871
+ # }
641
872
  #
642
873
  # subsequent updates
643
874
  #
644
- # [
645
- # 1234,
646
- # { # optional
647
- # "a": [
648
- # ["5541.30000", "2.50700000", "1534614248.456738"],
649
- # ["5542.50000", "0.40100000", "1534614248.456738"]
650
- # ]
651
- # },
652
- # { # optional
653
- # "b": [
654
- # ["5541.30000", "0.00000000", "1534614335.345903"]
655
- # ]
656
- # },
657
- # "book-10",
658
- # "XBT/USD"
659
- # ]
875
+ # {
876
+ # "channel": "book",
877
+ # "type": "update",
878
+ # "data": [
879
+ # {
880
+ # "symbol": "MATIC/USD",
881
+ # "bids": [
882
+ # {
883
+ # "price": 0.5657,
884
+ # "qty": 1098.3947558
885
+ # }
886
+ # ],
887
+ # "asks": [],
888
+ # "checksum": 2114181697,
889
+ # "timestamp": "2023-10-06T17:35:55.440295Z"
890
+ # }
891
+ # ]
892
+ # }
660
893
  #
661
- messageLength = len(message)
662
- wsName = message[messageLength - 1]
663
- bookDepthString = message[messageLength - 2]
664
- parts = bookDepthString.split('-')
665
- depth = self.safe_integer(parts, 1, 10)
666
- market = self.safe_value(self.options['marketsByWsName'], wsName)
667
- symbol = market['symbol']
668
- timestamp = None
894
+ type = self.safe_string(message, 'type')
895
+ data = self.safe_list(message, 'data', [])
896
+ first = self.safe_dict(data, 0, {})
897
+ symbol = self.safe_string(first, 'symbol')
898
+ a = self.safe_value(first, 'asks', [])
899
+ b = self.safe_value(first, 'bids', [])
900
+ c = self.safe_integer(first, 'checksum')
669
901
  messageHash = self.get_message_hash('orderbook', None, symbol)
670
- # if self is a snapshot
671
- if 'as' in message[1]:
672
- # todo get depth from marketsByWsName
673
- self.orderbooks[symbol] = self.order_book({}, depth)
902
+ orderbook = None
903
+ if type == 'update':
674
904
  orderbook = self.orderbooks[symbol]
675
- sides: dict = {
676
- 'as': 'asks',
677
- 'bs': 'bids',
678
- }
679
- keys = list(sides.keys())
680
- for i in range(0, len(keys)):
681
- key = keys[i]
682
- side = sides[key]
683
- bookside = orderbook[side]
684
- deltas = self.safe_value(message[1], key, [])
685
- timestamp = self.custom_handle_deltas(bookside, deltas, timestamp)
686
- orderbook['symbol'] = symbol
687
- orderbook['timestamp'] = timestamp
688
- orderbook['datetime'] = self.iso8601(timestamp)
689
- client.resolve(orderbook, messageHash)
690
- else:
691
- orderbook = self.orderbooks[symbol]
692
- # else, if self is an orderbook update
693
- a = None
694
- b = None
695
- c = None
696
- if messageLength == 5:
697
- a = self.safe_value(message[1], 'a', [])
698
- b = self.safe_value(message[2], 'b', [])
699
- c = self.safe_integer(message[1], 'c')
700
- c = self.safe_integer(message[2], 'c', c)
701
- else:
702
- c = self.safe_integer(message[1], 'c')
703
- if 'a' in message[1]:
704
- a = self.safe_value(message[1], 'a', [])
705
- else:
706
- b = self.safe_value(message[1], 'b', [])
707
905
  storedAsks = orderbook['asks']
708
906
  storedBids = orderbook['bids']
709
- example = None
710
907
  if a is not None:
711
- timestamp = self.custom_handle_deltas(storedAsks, a, timestamp)
712
- example = self.safe_value(a, 0)
908
+ self.custom_handle_deltas(storedAsks, a)
713
909
  if b is not None:
714
- timestamp = self.custom_handle_deltas(storedBids, b, timestamp)
715
- example = self.safe_value(b, 0)
716
- # don't remove self line or I will poop on your face
717
- orderbook.limit()
718
- checksum = self.safe_bool(self.options, 'checksum', True)
719
- if checksum:
720
- priceString = self.safe_string(example, 0)
721
- amountString = self.safe_string(example, 1)
722
- priceParts = priceString.split('.')
723
- amountParts = amountString.split('.')
724
- priceLength = len(priceParts[1]) - 0
725
- amountLength = len(amountParts[1]) - 0
726
- payloadArray = []
727
- if c is not None:
728
- for i in range(0, 10):
729
- formatted = self.format_number(storedAsks[i][0], priceLength) + self.format_number(storedAsks[i][1], amountLength)
730
- payloadArray.append(formatted)
731
- for i in range(0, 10):
732
- formatted = self.format_number(storedBids[i][0], priceLength) + self.format_number(storedBids[i][1], amountLength)
733
- payloadArray.append(formatted)
734
- payload = ''.join(payloadArray)
735
- localChecksum = self.crc32(payload, False)
736
- if localChecksum != c:
737
- error = InvalidNonce(self.id + ' invalid checksum')
738
- del client.subscriptions[messageHash]
739
- del self.orderbooks[symbol]
740
- client.reject(error, messageHash)
741
- return
910
+ self.custom_handle_deltas(storedBids, b)
911
+ datetime = self.safe_string(first, 'timestamp')
912
+ orderbook['symbol'] = symbol
913
+ orderbook['timestamp'] = self.parse8601(datetime)
914
+ orderbook['datetime'] = datetime
915
+ else:
916
+ # snapshot
917
+ depth = len(a)
918
+ self.orderbooks[symbol] = self.order_book({}, depth)
919
+ orderbook = self.orderbooks[symbol]
920
+ keys = ['asks', 'bids']
921
+ for i in range(0, len(keys)):
922
+ key = keys[i]
923
+ bookside = orderbook[key]
924
+ deltas = self.safe_value(first, key, [])
925
+ if len(deltas) > 0:
926
+ self.custom_handle_deltas(bookside, deltas)
742
927
  orderbook['symbol'] = symbol
743
- orderbook['timestamp'] = timestamp
744
- orderbook['datetime'] = self.iso8601(timestamp)
745
- client.resolve(orderbook, messageHash)
928
+ orderbook.limit()
929
+ # checksum temporarily disabled because the exchange checksum was not reliable
930
+ checksum = self.handle_option('watchOrderBook', 'checksum', False)
931
+ if checksum:
932
+ payloadArray = []
933
+ if c is not None:
934
+ checkAsks = orderbook['asks']
935
+ checkBids = orderbook['bids']
936
+ # checkAsks = asks.map((elem) => [elem['price'], elem['qty']])
937
+ # checkBids = bids.map((elem) => [elem['price'], elem['qty']])
938
+ for i in range(0, 10):
939
+ currentAsk = self.safe_value(checkAsks, i, {})
940
+ formattedAsk = self.format_number(currentAsk[0]) + self.format_number(currentAsk[1])
941
+ payloadArray.append(formattedAsk)
942
+ for i in range(0, 10):
943
+ currentBid = self.safe_value(checkBids, i, {})
944
+ formattedBid = self.format_number(currentBid[0]) + self.format_number(currentBid[1])
945
+ payloadArray.append(formattedBid)
946
+ payload = ''.join(payloadArray)
947
+ localChecksum = self.crc32(payload, False)
948
+ if localChecksum != c:
949
+ error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
950
+ del client.subscriptions[messageHash]
951
+ del self.orderbooks[symbol]
952
+ client.reject(error, messageHash)
953
+ return
954
+ client.resolve(orderbook, messageHash)
746
955
 
747
- def format_number(self, n, length):
748
- stringNumber = self.number_to_string(n)
749
- parts = stringNumber.split('.')
956
+ def custom_handle_deltas(self, bookside, deltas):
957
+ # sortOrder = True if (key == 'bids') else False
958
+ for j in range(0, len(deltas)):
959
+ delta = deltas[j]
960
+ price = self.safe_number(delta, 'price')
961
+ amount = self.safe_number(delta, 'qty')
962
+ bookside.store(price, amount)
963
+ # if amount == 0:
964
+ # index = bookside.findIndex((x: Int) => x[0] == price)
965
+ # bookside.splice(index, 1)
966
+ # else:
967
+ # bookside.store(price, amount)
968
+ # }
969
+ # bookside = self.sort_by(bookside, 0, sortOrder)
970
+ # bookside[0:9]
971
+
972
+ def format_number(self, data):
973
+ parts = data.split('.')
750
974
  integer = self.safe_string(parts, 0)
751
975
  decimals = self.safe_string(parts, 1, '')
752
- paddedDecimals = decimals.ljust(length, '0')
753
- joined = integer + paddedDecimals
976
+ joinedResult = integer + decimals
754
977
  i = 0
755
- while(joined[i] == '0'):
978
+ while(joinedResult[i] == '0'):
756
979
  i += 1
757
980
  if i > 0:
758
- return joined[i:]
759
- else:
760
- return joined
761
-
762
- def custom_handle_deltas(self, bookside, deltas, timestamp=None):
763
- for j in range(0, len(deltas)):
764
- delta = deltas[j]
765
- price = self.parse_number(delta[0])
766
- amount = self.parse_number(delta[1])
767
- oldTimestamp = timestamp if timestamp else 0
768
- timestamp = max(oldTimestamp, self.parse_to_int(float(delta[2]) * 1000))
769
- bookside.store(price, amount)
770
- return timestamp
981
+ joinedResult = joinedResult[i:]
982
+ return joinedResult
771
983
 
772
984
  def handle_system_status(self, client: Client, message):
773
985
  #
@@ -782,6 +994,20 @@ class kraken(ccxt.async_support.kraken):
782
994
  # "version": "0.2.0"
783
995
  # }
784
996
  #
997
+ # v2
998
+ # {
999
+ # channel: 'status',
1000
+ # type: 'update',
1001
+ # data: [
1002
+ # {
1003
+ # version: '2.0.10',
1004
+ # system: 'online',
1005
+ # api_version: 'v2',
1006
+ # connection_id: 6447481662169813000
1007
+ # }
1008
+ # ]
1009
+ # }
1010
+ #
785
1011
  return message
786
1012
 
787
1013
  async def authenticate(self, params={}):
@@ -789,7 +1015,11 @@ class kraken(ccxt.async_support.kraken):
789
1015
  client = self.client(url)
790
1016
  authenticated = 'authenticated'
791
1017
  subscription = self.safe_value(client.subscriptions, authenticated)
792
- if subscription is None:
1018
+ now = self.seconds()
1019
+ start = self.safe_integer(subscription, 'start')
1020
+ expires = self.safe_integer(subscription, 'expires')
1021
+ if (subscription is None) or ((subscription is not None) and (start + expires) <= now):
1022
+ # https://docs.kraken.com/api/docs/rest-api/get-websockets-token
793
1023
  response = await self.privatePostGetWebSocketsToken(params)
794
1024
  #
795
1025
  # {
@@ -800,7 +1030,8 @@ class kraken(ccxt.async_support.kraken):
800
1030
  # }
801
1031
  # }
802
1032
  #
803
- subscription = self.safe_value(response, 'result')
1033
+ subscription = self.safe_dict(response, 'result')
1034
+ subscription['start'] = now
804
1035
  client.subscriptions[authenticated] = subscription
805
1036
  return self.safe_string(subscription, 'token')
806
1037
 
@@ -831,11 +1062,14 @@ class kraken(ccxt.async_support.kraken):
831
1062
  async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
832
1063
  """
833
1064
  watches information on multiple trades made by the user
1065
+
1066
+ https://docs.kraken.com/api/docs/websocket-v1/owntrades
1067
+
834
1068
  :param str symbol: unified market symbol of the market trades were made in
835
1069
  :param int [since]: the earliest time in ms to fetch trades for
836
1070
  :param int [limit]: the maximum number of trade structures to retrieve
837
1071
  :param dict [params]: extra parameters specific to the exchange API endpoint
838
- :returns dict[]: a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure
1072
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
839
1073
  """
840
1074
  return await self.watch_private('ownTrades', symbol, since, limit, params)
841
1075
 
@@ -979,7 +1213,9 @@ class kraken(ccxt.async_support.kraken):
979
1213
 
980
1214
  async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
981
1215
  """
982
- :see: https://docs.kraken.com/websockets/#message-openOrders
1216
+
1217
+ https://docs.kraken.com/api/docs/websocket-v1/openorders
1218
+
983
1219
  watches information on multiple orders made by the user
984
1220
  :param str symbol: unified market symbol of the market orders were made in
985
1221
  :param int [since]: the earliest time in ms to fetch orders for
@@ -1229,23 +1465,86 @@ class kraken(ccxt.async_support.kraken):
1229
1465
  symbols = self.market_symbols(symbols, None, False, True, False)
1230
1466
  messageHashes = []
1231
1467
  for i in range(0, len(symbols)):
1232
- messageHashes.append(self.get_message_hash(unifiedName, None, self.symbol(symbols[i])))
1233
- # for WS subscriptions, we can't use .marketIds(symbols), instead a custom is field needed
1234
- markets = self.markets_for_symbols(symbols)
1235
- wsMarketIds = []
1236
- for i in range(0, len(markets)):
1237
- wsMarketId = self.safe_string(markets[i]['info'], 'wsname')
1238
- wsMarketIds.append(wsMarketId)
1468
+ eventTrigger = self.safe_string(params, 'event_trigger')
1469
+ if eventTrigger is not None:
1470
+ messageHashes.append(self.get_message_hash(channelName, None, self.symbol(symbols[i])))
1471
+ else:
1472
+ messageHashes.append(self.get_message_hash(unifiedName, None, self.symbol(symbols[i])))
1239
1473
  request: dict = {
1240
- 'event': 'subscribe',
1241
- 'reqid': self.request_id(),
1242
- 'pair': wsMarketIds,
1243
- 'subscription': {
1244
- 'name': channelName,
1474
+ 'method': 'subscribe',
1475
+ 'params': {
1476
+ 'channel': channelName,
1477
+ 'symbol': symbols,
1245
1478
  },
1479
+ 'req_id': self.request_id(),
1246
1480
  }
1247
- url = self.urls['api']['ws']['public']
1248
- return await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), messageHashes, subscriptionArgs)
1481
+ request['params'] = self.deep_extend(request['params'], params)
1482
+ url = self.urls['api']['ws']['publicV2']
1483
+ return await self.watch_multiple(url, messageHashes, request, messageHashes, subscriptionArgs)
1484
+
1485
+ async def watch_balance(self, params={}) -> Balances:
1486
+ """
1487
+ watch balance and get the amount of funds available for trading or funds locked in orders
1488
+
1489
+ https://docs.kraken.com/api/docs/websocket-v2/balances
1490
+
1491
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1492
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1493
+ """
1494
+ await self.load_markets()
1495
+ token = await self.authenticate()
1496
+ messageHash = 'balances'
1497
+ url = self.urls['api']['ws']['privateV2']
1498
+ requestId = self.request_id()
1499
+ subscribe: dict = {
1500
+ 'method': 'subscribe',
1501
+ 'req_id': requestId,
1502
+ 'params': {
1503
+ 'channel': 'balances',
1504
+ 'token': token,
1505
+ },
1506
+ }
1507
+ request = self.deep_extend(subscribe, params)
1508
+ return await self.watch(url, messageHash, request, messageHash)
1509
+
1510
+ def handle_balance(self, client: Client, message):
1511
+ #
1512
+ # {
1513
+ # "channel": "balances",
1514
+ # "data": [
1515
+ # {
1516
+ # "asset": "BTC",
1517
+ # "asset_class": "currency",
1518
+ # "balance": 1.2,
1519
+ # "wallets": [
1520
+ # {
1521
+ # "type": "spot",
1522
+ # "id": "main",
1523
+ # "balance": 1.2
1524
+ # }
1525
+ # ]
1526
+ # }
1527
+ # ],
1528
+ # "type": "snapshot",
1529
+ # "sequence": 1
1530
+ # }
1531
+ #
1532
+ data = self.safe_list(message, 'data', [])
1533
+ result: dict = {'info': message}
1534
+ for i in range(0, len(data)):
1535
+ currencyId = self.safe_string(data[i], 'asset')
1536
+ code = self.safe_currency_code(currencyId)
1537
+ account = self.account()
1538
+ eq = self.safe_string(data[i], 'balance')
1539
+ account['total'] = eq
1540
+ result[code] = account
1541
+ type = 'spot'
1542
+ balance = self.safe_balance(result)
1543
+ oldBalance = self.safe_value(self.balance, type, {})
1544
+ newBalance = self.deep_extend(oldBalance, balance)
1545
+ self.balance[type] = self.safe_balance(newBalance)
1546
+ channel = self.safe_string(message, 'channel')
1547
+ client.resolve(self.balance[type], channel)
1249
1548
 
1250
1549
  def get_message_hash(self, unifiedElementName: str, subChannelName: Str = None, symbol: Str = None):
1251
1550
  # unifiedElementName can be : orderbook, trade, ticker, bidask ...
@@ -1292,7 +1591,7 @@ class kraken(ccxt.async_support.kraken):
1292
1591
  # del client.futures[requestId]
1293
1592
  # }
1294
1593
 
1295
- def handle_error_message(self, client: Client, message):
1594
+ def handle_error_message(self, client: Client, message) -> Bool:
1296
1595
  #
1297
1596
  # {
1298
1597
  # "errorMessage": "Currency pair not in ISO 4217-A3 format foobar",
@@ -1303,19 +1602,31 @@ class kraken(ccxt.async_support.kraken):
1303
1602
  # "subscription": {name: "ticker"}
1304
1603
  # }
1305
1604
  #
1306
- errorMessage = self.safe_string(message, 'errorMessage')
1605
+ # v2
1606
+ # {
1607
+ # "error": "Unsupported field: 'price' for the given msg type: add order",
1608
+ # "method": "add_order",
1609
+ # "success": False,
1610
+ # "time_in": "2025-05-13T08:59:44.803511Z",
1611
+ # "time_out": "2025-05-13T08:59:44.803542Z'
1612
+ # }
1613
+ #
1614
+ errorMessage = self.safe_string_2(message, 'errorMessage', 'error')
1307
1615
  if errorMessage is not None:
1308
- requestId = self.safe_value(message, 'reqid')
1309
- if requestId is not None:
1310
- broad = self.exceptions['ws']['broad']
1311
- broadKey = self.find_broadly_matched_key(broad, errorMessage)
1312
- exception = None
1313
- if broadKey is None:
1314
- exception = ExchangeError(errorMessage) # c# requirement to convert the errorMessage to string
1315
- else:
1316
- exception = broad[broadKey](errorMessage)
1317
- client.reject(exception, requestId)
1318
- return False
1616
+ # requestId = self.safe_value_2(message, 'reqid', 'req_id')
1617
+ broad = self.exceptions['ws']['broad']
1618
+ broadKey = self.find_broadly_matched_key(broad, errorMessage)
1619
+ exception = None
1620
+ if broadKey is None:
1621
+ exception = ExchangeError(errorMessage) # c# requirement to convert the errorMessage to string
1622
+ else:
1623
+ exception = broad[broadKey](errorMessage)
1624
+ # if requestId is not None:
1625
+ # client.reject(exception, requestId)
1626
+ # else:
1627
+ client.reject(exception)
1628
+ # }
1629
+ return False
1319
1630
  return True
1320
1631
 
1321
1632
  def handle_message(self, client: Client, message):
@@ -1328,10 +1639,7 @@ class kraken(ccxt.async_support.kraken):
1328
1639
  name = self.safe_string(info, 'name')
1329
1640
  methods: dict = {
1330
1641
  # public
1331
- 'book': self.handle_order_book,
1332
1642
  'ohlc': self.handle_ohlcv,
1333
- 'ticker': self.handle_ticker,
1334
- 'trade': self.handle_trades,
1335
1643
  # private
1336
1644
  'openOrders': self.handle_orders,
1337
1645
  'ownTrades': self.handle_my_trades,
@@ -1340,16 +1648,28 @@ class kraken(ccxt.async_support.kraken):
1340
1648
  if method is not None:
1341
1649
  method(client, message, subscription)
1342
1650
  else:
1651
+ channel = self.safe_string(message, 'channel')
1652
+ if channel is not None:
1653
+ methods: dict = {
1654
+ 'balances': self.handle_balance,
1655
+ 'book': self.handle_order_book,
1656
+ 'ticker': self.handle_ticker,
1657
+ 'trade': self.handle_trades,
1658
+ }
1659
+ method = self.safe_value(methods, channel)
1660
+ if method is not None:
1661
+ method(client, message)
1343
1662
  if self.handle_error_message(client, message):
1344
- event = self.safe_string(message, 'event')
1663
+ event = self.safe_string_2(message, 'event', 'method')
1345
1664
  methods: dict = {
1346
1665
  'heartbeat': self.handle_heartbeat,
1347
1666
  'systemStatus': self.handle_system_status,
1348
1667
  'subscriptionStatus': self.handle_subscription_status,
1349
- 'addOrderStatus': self.handle_create_edit_order,
1350
- 'editOrderStatus': self.handle_create_edit_order,
1351
- 'cancelOrderStatus': self.handle_cancel_order,
1352
- 'cancelAllStatus': self.handle_cancel_all_orders,
1668
+ 'add_order': self.handle_create_edit_order,
1669
+ 'amend_order': self.handle_create_edit_order,
1670
+ 'cancel_order': self.handle_cancel_order,
1671
+ 'cancel_all': self.handle_cancel_all_orders,
1672
+ 'pong': self.handle_pong,
1353
1673
  }
1354
1674
  method = self.safe_value(methods, event)
1355
1675
  if method is not None: