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
@@ -5,8 +5,9 @@
5
5
 
6
6
  from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.kraken import ImplicitAPI
8
+ import asyncio
8
9
  import hashlib
9
- from ccxt.base.types import Balances, Currencies, Currency, IndexType, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry
10
+ from ccxt.base.types import Any, Balances, Currencies, Currency, DepositAddress, IndexType, Int, LedgerEntry, Market, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry
10
11
  from typing import List
11
12
  from ccxt.base.errors import ExchangeError
12
13
  from ccxt.base.errors import AuthenticationError
@@ -19,13 +20,13 @@ from ccxt.base.errors import InsufficientFunds
19
20
  from ccxt.base.errors import InvalidAddress
20
21
  from ccxt.base.errors import InvalidOrder
21
22
  from ccxt.base.errors import OrderNotFound
22
- from ccxt.base.errors import CancelPending
23
23
  from ccxt.base.errors import NotSupported
24
24
  from ccxt.base.errors import DDoSProtection
25
25
  from ccxt.base.errors import RateLimitExceeded
26
26
  from ccxt.base.errors import ExchangeNotAvailable
27
27
  from ccxt.base.errors import OnMaintenance
28
28
  from ccxt.base.errors import InvalidNonce
29
+ from ccxt.base.errors import CancelPending
29
30
  from ccxt.base.decimal_to_precision import TRUNCATE
30
31
  from ccxt.base.decimal_to_precision import TICK_SIZE
31
32
  from ccxt.base.precise import Precise
@@ -33,7 +34,7 @@ from ccxt.base.precise import Precise
33
34
 
34
35
  class kraken(Exchange, ImplicitAPI):
35
36
 
36
- def describe(self):
37
+ def describe(self) -> Any:
37
38
  return self.deep_extend(super(kraken, self).describe(), {
38
39
  'id': 'kraken',
39
40
  'name': 'Kraken',
@@ -66,6 +67,7 @@ class kraken(Exchange, ImplicitAPI):
66
67
  'createStopMarketOrder': True,
67
68
  'createStopOrder': True,
68
69
  'createTrailingAmountOrder': True,
70
+ 'createTrailingPercentOrder': True,
69
71
  'editOrder': True,
70
72
  'fetchBalance': True,
71
73
  'fetchBorrowInterest': False,
@@ -76,6 +78,8 @@ class kraken(Exchange, ImplicitAPI):
76
78
  'fetchCrossBorrowRates': False,
77
79
  'fetchCurrencies': True,
78
80
  'fetchDepositAddress': True,
81
+ 'fetchDepositAddresses': False,
82
+ 'fetchDepositAddressesByNetwork': False,
79
83
  'fetchDeposits': True,
80
84
  'fetchFundingHistory': False,
81
85
  'fetchFundingRate': False,
@@ -98,6 +102,7 @@ class kraken(Exchange, ImplicitAPI):
98
102
  'fetchOrderTrades': 'emulated',
99
103
  'fetchPositions': True,
100
104
  'fetchPremiumIndexOHLCV': False,
105
+ 'fetchStatus': True,
101
106
  'fetchTicker': True,
102
107
  'fetchTickers': True,
103
108
  'fetchTime': True,
@@ -193,6 +198,7 @@ class kraken(Exchange, ImplicitAPI):
193
198
  'AddOrder': 0,
194
199
  'AddOrderBatch': 0,
195
200
  'AddExport': 3,
201
+ 'AmendOrder': 0,
196
202
  'Balance': 3,
197
203
  'CancelAll': 3,
198
204
  'CancelAllOrdersAfter': 3,
@@ -238,16 +244,18 @@ class kraken(Exchange, ImplicitAPI):
238
244
  },
239
245
  },
240
246
  'commonCurrencies': {
247
+ # about X & Z prefixes and .S & .M suffixes, see comment under fetchCurrencies
241
248
  'LUNA': 'LUNC',
242
249
  'LUNA2': 'LUNA',
243
250
  'REPV2': 'REP',
244
251
  'REP': 'REPV1',
245
252
  'UST': 'USTC',
246
253
  'XBT': 'BTC',
247
- 'XBT.M': 'BTC.M', # https://support.kraken.com/hc/en-us/articles/360039879471-What-is-Asset-S-and-Asset-M-
248
254
  'XDG': 'DOGE',
249
255
  },
250
256
  'options': {
257
+ 'timeDifference': 0, # the difference between system clock and Binance clock
258
+ 'adjustForTimeDifference': False, # controls the adjustment logic upon instantiation
251
259
  'marketsByAltname': {},
252
260
  'delistedMarketsById': {},
253
261
  # cannot withdraw/deposit these
@@ -257,100 +265,100 @@ class kraken(Exchange, ImplicitAPI):
257
265
  'TRX': 'TRC20',
258
266
  },
259
267
  'depositMethods': {
260
- '1INCH': '1inch(1INCH)',
268
+ '1INCH': '1inch' + ' ' + '(1INCH)',
261
269
  'AAVE': 'Aave',
262
270
  'ADA': 'ADA',
263
271
  'ALGO': 'Algorand',
264
- 'ANKR': 'ANKR(ANKR)',
265
- 'ANT': 'Aragon(ANT)',
272
+ 'ANKR': 'ANKR' + ' ' + '(ANKR)',
273
+ 'ANT': 'Aragon' + ' ' + '(ANT)',
266
274
  'ATOM': 'Cosmos',
267
- 'AXS': 'Axie Infinity Shards(AXS)',
268
- 'BADGER': 'Bager DAO(BADGER)',
269
- 'BAL': 'Balancer(BAL)',
270
- 'BAND': 'Band Protocol(BAND)',
275
+ 'AXS': 'Axie Infinity Shards' + ' ' + '(AXS)',
276
+ 'BADGER': 'Bager DAO' + ' ' + '(BADGER)',
277
+ 'BAL': 'Balancer' + ' ' + '(BAL)',
278
+ 'BAND': 'Band Protocol' + ' ' + '(BAND)',
271
279
  'BAT': 'BAT',
272
280
  'BCH': 'Bitcoin Cash',
273
- 'BNC': 'Bifrost(BNC)',
274
- 'BNT': 'Bancor(BNT)',
281
+ 'BNC': 'Bifrost' + ' ' + '(BNC)',
282
+ 'BNT': 'Bancor' + ' ' + '(BNT)',
275
283
  'BTC': 'Bitcoin',
276
- 'CHZ': 'Chiliz(CHZ)',
277
- 'COMP': 'Compound(COMP)',
278
- 'CQT': '\tCovalent Query Token(CQT)',
279
- 'CRV': 'Curve DAO Token(CRV)',
280
- 'CTSI': 'Cartesi(CTSI)',
284
+ 'CHZ': 'Chiliz' + ' ' + '(CHZ)',
285
+ 'COMP': 'Compound' + ' ' + '(COMP)',
286
+ 'CQT': '\tCovalent Query Token' + ' ' + '(CQT)',
287
+ 'CRV': 'Curve DAO Token' + ' ' + '(CRV)',
288
+ 'CTSI': 'Cartesi' + ' ' + '(CTSI)',
281
289
  'DAI': 'Dai',
282
290
  'DASH': 'Dash',
283
291
  'DOGE': 'Dogecoin',
284
292
  'DOT': 'Polkadot',
285
- 'DYDX': 'dYdX(DYDX)',
286
- 'ENJ': 'Enjin Coin(ENJ)',
293
+ 'DYDX': 'dYdX' + ' ' + '(DYDX)',
294
+ 'ENJ': 'Enjin Coin' + ' ' + '(ENJ)',
287
295
  'EOS': 'EOS',
288
- 'ETC': 'Ether Classic(Hex)',
289
- 'ETH': 'Ether(Hex)',
296
+ 'ETC': 'Ether Classic' + ' ' + '(Hex)',
297
+ 'ETH': 'Ether' + ' ' + '(Hex)',
290
298
  'EWT': 'Energy Web Token',
291
299
  'FEE': 'Kraken Fee Credit',
292
300
  'FIL': 'Filecoin',
293
301
  'FLOW': 'Flow',
294
- 'GHST': 'Aavegotchi(GHST)',
302
+ 'GHST': 'Aavegotchi' + ' ' + '(GHST)',
295
303
  'GNO': 'GNO',
296
304
  'GRT': 'GRT',
297
305
  'ICX': 'Icon',
298
- 'INJ': 'Injective Protocol(INJ)',
299
- 'KAR': 'Karura(KAR)',
306
+ 'INJ': 'Injective Protocol' + ' ' + '(INJ)',
307
+ 'KAR': 'Karura' + ' ' + '(KAR)',
300
308
  'KAVA': 'Kava',
301
- 'KEEP': 'Keep Token(KEEP)',
302
- 'KNC': 'Kyber Network(KNC)',
309
+ 'KEEP': 'Keep Token' + ' ' + '(KEEP)',
310
+ 'KNC': 'Kyber Network' + ' ' + '(KNC)',
303
311
  'KSM': 'Kusama',
304
312
  'LINK': 'Link',
305
- 'LPT': 'Livepeer Token(LPT)',
306
- 'LRC': 'Loopring(LRC)',
313
+ 'LPT': 'Livepeer Token' + ' ' + '(LPT)',
314
+ 'LRC': 'Loopring' + ' ' + '(LRC)',
307
315
  'LSK': 'Lisk',
308
316
  'LTC': 'Litecoin',
309
317
  'MANA': 'MANA',
310
- 'MATIC': 'Polygon(MATIC)',
318
+ 'MATIC': 'Polygon' + ' ' + '(MATIC)',
311
319
  'MINA': 'Mina', # inspected from webui
312
- 'MIR': 'Mirror Protocol(MIR)',
313
- 'MKR': 'Maker(MKR)',
320
+ 'MIR': 'Mirror Protocol' + ' ' + '(MIR)',
321
+ 'MKR': 'Maker' + ' ' + '(MKR)',
314
322
  'MLN': 'MLN',
315
- 'MOVR': 'Moonriver(MOVR)',
323
+ 'MOVR': 'Moonriver' + ' ' + '(MOVR)',
316
324
  'NANO': 'NANO',
317
325
  'OCEAN': 'OCEAN',
318
- 'OGN': 'Origin Protocol(OGN)',
326
+ 'OGN': 'Origin Protocol' + ' ' + '(OGN)',
319
327
  'OMG': 'OMG',
320
- 'OXT': 'Orchid(OXT)',
321
- 'OXY': 'Oxygen(OXY)',
322
- 'PAXG': 'PAX(Gold)',
323
- 'PERP': 'Perpetual Protocol(PERP)',
324
- 'PHA': 'Phala(PHA)',
328
+ 'OXT': 'Orchid' + ' ' + '(OXT)',
329
+ 'OXY': 'Oxygen' + ' ' + '(OXY)',
330
+ 'PAXG': 'PAX' + ' ' + '(Gold)',
331
+ 'PERP': 'Perpetual Protocol' + ' ' + '(PERP)',
332
+ 'PHA': 'Phala' + ' ' + '(PHA)',
325
333
  'QTUM': 'QTUM',
326
- 'RARI': 'Rarible(RARI)',
327
- 'RAY': 'Raydium(RAY)',
328
- 'REN': 'Ren Protocol(REN)',
334
+ 'RARI': 'Rarible' + ' ' + '(RARI)',
335
+ 'RAY': 'Raydium' + ' ' + '(RAY)',
336
+ 'REN': 'Ren Protocol' + ' ' + '(REN)',
329
337
  'REP': 'REPv2',
330
338
  'REPV1': 'REP',
331
- 'SAND': 'The Sandbox(SAND)',
339
+ 'SAND': 'The Sandbox' + ' ' + '(SAND)',
332
340
  'SC': 'Siacoin',
333
- 'SDN': 'Shiden(SDN)',
341
+ 'SDN': 'Shiden' + ' ' + '(SDN)',
334
342
  'SOL': 'Solana', # their deposit method api doesn't work for SOL - was guessed
335
- 'SNX': 'Synthetix Network(SNX)',
343
+ 'SNX': 'Synthetix Network' + ' ' + '(SNX)',
336
344
  'SRM': 'Serum', # inspected from webui
337
- 'STORJ': 'Storj(STORJ)',
338
- 'SUSHI': 'Sushiswap(SUSHI)',
345
+ 'STORJ': 'Storj' + ' ' + '(STORJ)',
346
+ 'SUSHI': 'Sushiswap' + ' ' + '(SUSHI)',
339
347
  'TBTC': 'tBTC',
340
348
  'TRX': 'Tron',
341
349
  'UNI': 'UNI',
342
350
  'USDC': 'USDC',
343
- 'USDT': 'Tether USD(ERC20)',
344
- 'USDT-TRC20': 'Tether USD(TRC20)',
351
+ 'USDT': 'Tether USD' + ' ' + '(ERC20)',
352
+ 'USDT-TRC20': 'Tether USD' + ' ' + '(TRC20)',
345
353
  'WAVES': 'Waves',
346
- 'WBTC': 'Wrapped Bitcoin(WBTC)',
354
+ 'WBTC': 'Wrapped Bitcoin' + ' ' + '(WBTC)',
347
355
  'XLM': 'Stellar XLM',
348
356
  'XMR': 'Monero',
349
357
  'XRP': 'Ripple XRP',
350
358
  'XTZ': 'XTZ',
351
359
  'YFI': 'YFI',
352
- 'ZEC': 'Zcash(Transparent)',
353
- 'ZRX': '0x(ZRX)',
360
+ 'ZEC': 'Zcash' + ' ' + '(Transparent)',
361
+ 'ZRX': '0x' + ' ' + '(ZRX)',
354
362
  },
355
363
  'withdrawMethods': { # keeping it here because deposit and withdraw return different networks codes
356
364
  'Lightning': 'Lightning',
@@ -438,31 +446,115 @@ class kraken(Exchange, ImplicitAPI):
438
446
  'Celestia': 'TIA',
439
447
  },
440
448
  },
449
+ 'features': {
450
+ 'spot': {
451
+ 'sandbox': False,
452
+ 'createOrder': {
453
+ 'marginMode': False,
454
+ 'triggerPrice': False, # todo
455
+ 'triggerPriceType': None,
456
+ 'triggerDirection': False,
457
+ 'stopLossPrice': True,
458
+ 'takeProfitPrice': True,
459
+ 'attachedStopLossTakeProfit': None,
460
+ 'timeInForce': {
461
+ 'IOC': True,
462
+ 'FOK': True,
463
+ 'PO': True,
464
+ 'GTD': False,
465
+ },
466
+ 'hedged': False,
467
+ 'trailing': True,
468
+ 'leverage': False,
469
+ 'marketBuyByCost': True,
470
+ 'marketBuyRequiresPrice': False,
471
+ 'selfTradePrevention': True, # todo implement
472
+ 'iceberg': True, # todo implement
473
+ },
474
+ 'createOrders': None,
475
+ 'fetchMyTrades': {
476
+ 'marginMode': False,
477
+ 'limit': None,
478
+ 'daysBack': None,
479
+ 'untilDays': None,
480
+ 'symbolRequired': False,
481
+ },
482
+ 'fetchOrder': {
483
+ 'marginMode': False,
484
+ 'trigger': False,
485
+ 'trailing': False,
486
+ 'symbolRequired': False,
487
+ },
488
+ 'fetchOpenOrders': {
489
+ 'marginMode': False,
490
+ 'limit': None,
491
+ 'trigger': False,
492
+ 'trailing': False,
493
+ 'symbolRequired': False,
494
+ },
495
+ 'fetchOrders': None,
496
+ 'fetchClosedOrders': {
497
+ 'marginMode': False,
498
+ 'limit': None,
499
+ 'daysBack': None,
500
+ 'daysBackCanceled': None,
501
+ 'untilDays': 100000,
502
+ 'trigger': False,
503
+ 'trailing': False,
504
+ 'symbolRequired': False,
505
+ },
506
+ 'fetchOHLCV': {
507
+ 'limit': 720,
508
+ },
509
+ },
510
+ 'swap': {
511
+ 'linear': None,
512
+ 'inverse': None,
513
+ },
514
+ 'future': {
515
+ 'linear': None,
516
+ 'inverse': None,
517
+ },
518
+ },
441
519
  'precisionMode': TICK_SIZE,
442
520
  'exceptions': {
443
- 'EQuery:Invalid asset pair': BadSymbol, # {"error":["EQuery:Invalid asset pair"]}
444
- 'EAPI:Invalid key': AuthenticationError,
445
- 'EFunding:Unknown withdraw key': InvalidAddress, # {"error":["EFunding:Unknown withdraw key"]}
446
- 'EFunding:Invalid amount': InsufficientFunds,
447
- 'EService:Unavailable': ExchangeNotAvailable,
448
- 'EDatabase:Internal error': ExchangeNotAvailable,
449
- 'EService:Busy': ExchangeNotAvailable,
450
- 'EQuery:Unknown asset': BadSymbol, # {"error":["EQuery:Unknown asset"]}
451
- 'EAPI:Rate limit exceeded': DDoSProtection,
452
- 'EOrder:Rate limit exceeded': DDoSProtection,
453
- 'EGeneral:Internal error': ExchangeNotAvailable,
454
- 'EGeneral:Temporary lockout': DDoSProtection,
455
- 'EGeneral:Permission denied': PermissionDenied,
456
- 'EOrder:Unknown order': InvalidOrder,
457
- 'EOrder:Order minimum not met': InvalidOrder,
458
- 'EGeneral:Invalid arguments': BadRequest,
459
- 'ESession:Invalid session': AuthenticationError,
460
- 'EAPI:Invalid nonce': InvalidNonce,
461
- 'EFunding:No funding method': BadRequest, # {"error":"EFunding:No funding method"}
462
- 'EFunding:Unknown asset': BadSymbol, # {"error":["EFunding:Unknown asset"]}
463
- 'EService:Market in post_only mode': OnMaintenance, # {"error":["EService:Market in post_only mode"]}
464
- 'EGeneral:Too many requests': DDoSProtection, # {"error":["EGeneral:Too many requests"]}
465
- 'ETrade:User Locked': AccountSuspended, # {"error":["ETrade:User Locked"]}
521
+ 'exact': {
522
+ 'EQuery:Invalid asset pair': BadSymbol, # {"error":["EQuery:Invalid asset pair"]}
523
+ 'EAPI:Invalid key': AuthenticationError,
524
+ 'EFunding:Unknown withdraw key': InvalidAddress, # {"error":["EFunding:Unknown withdraw key"]}
525
+ 'EFunding:Invalid amount': InsufficientFunds,
526
+ 'EService:Unavailable': ExchangeNotAvailable,
527
+ 'EDatabase:Internal error': ExchangeNotAvailable,
528
+ 'EService:Busy': ExchangeNotAvailable,
529
+ 'EQuery:Unknown asset': BadSymbol, # {"error":["EQuery:Unknown asset"]}
530
+ 'EAPI:Rate limit exceeded': DDoSProtection,
531
+ 'EOrder:Rate limit exceeded': DDoSProtection,
532
+ 'EGeneral:Internal error': ExchangeNotAvailable,
533
+ 'EGeneral:Temporary lockout': DDoSProtection,
534
+ 'EGeneral:Permission denied': PermissionDenied,
535
+ 'EGeneral:Invalid arguments:price': InvalidOrder,
536
+ 'EOrder:Unknown order': InvalidOrder,
537
+ 'EOrder:Invalid price:Invalid price argument': InvalidOrder,
538
+ 'EOrder:Order minimum not met': InvalidOrder,
539
+ 'EOrder:Insufficient funds': InsufficientFunds,
540
+ 'EGeneral:Invalid arguments': BadRequest,
541
+ 'ESession:Invalid session': AuthenticationError,
542
+ 'EAPI:Invalid nonce': InvalidNonce,
543
+ 'EFunding:No funding method': BadRequest, # {"error":"EFunding:No funding method"}
544
+ 'EFunding:Unknown asset': BadSymbol, # {"error":["EFunding:Unknown asset"]}
545
+ 'EService:Market in post_only mode': OnMaintenance, # {"error":["EService:Market in post_only mode"]}
546
+ 'EGeneral:Too many requests': DDoSProtection, # {"error":["EGeneral:Too many requests"]}
547
+ 'ETrade:User Locked': AccountSuspended, # {"error":["ETrade:User Locked"]}
548
+ },
549
+ 'broad': {
550
+ ':Invalid order': InvalidOrder,
551
+ ':Invalid arguments:volume': InvalidOrder,
552
+ ':Invalid arguments:viqc': InvalidOrder,
553
+ ':Invalid nonce': InvalidNonce,
554
+ ':IInsufficient funds': InsufficientFunds,
555
+ ':Cancel pending': CancelPending,
556
+ ':Rate limit exceeded': RateLimitExceeded,
557
+ },
466
558
  },
467
559
  })
468
560
 
@@ -472,11 +564,18 @@ class kraken(Exchange, ImplicitAPI):
472
564
  async def fetch_markets(self, params={}) -> List[Market]:
473
565
  """
474
566
  retrieves data on all markets for kraken
475
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTradableAssetPairs
567
+
568
+ https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTradableAssetPairs
569
+
476
570
  :param dict [params]: extra parameters specific to the exchange API endpoint
477
571
  :returns dict[]: an array of objects representing market data
478
572
  """
479
- response = await self.publicGetAssetPairs(params)
573
+ promises = []
574
+ promises.append(self.publicGetAssetPairs(params))
575
+ if self.options['adjustForTimeDifference']:
576
+ promises.append(self.load_time_difference())
577
+ responses = await asyncio.gather(*promises)
578
+ assetsResponse = responses[0]
480
579
  #
481
580
  # {
482
581
  # "error": [],
@@ -524,7 +623,8 @@ class kraken(Exchange, ImplicitAPI):
524
623
  # }
525
624
  # }
526
625
  #
527
- markets = self.safe_value(response, 'result', {})
626
+ markets = self.safe_dict(assetsResponse, 'result', {})
627
+ cachedCurrencies = self.safe_dict(self.options, 'cachedCurrencies', {})
528
628
  keys = list(markets.keys())
529
629
  result = []
530
630
  for i in range(0, len(keys)):
@@ -534,39 +634,45 @@ class kraken(Exchange, ImplicitAPI):
534
634
  quoteId = self.safe_string(market, 'quote')
535
635
  base = self.safe_currency_code(baseId)
536
636
  quote = self.safe_currency_code(quoteId)
537
- darkpool = id.find('.d') >= 0
538
- altname = self.safe_string(market, 'altname')
539
- makerFees = self.safe_value(market, 'fees_maker', [])
540
- firstMakerFee = self.safe_value(makerFees, 0, [])
637
+ makerFees = self.safe_list(market, 'fees_maker', [])
638
+ firstMakerFee = self.safe_list(makerFees, 0, [])
541
639
  firstMakerFeeRate = self.safe_string(firstMakerFee, 1)
542
640
  maker = None
543
641
  if firstMakerFeeRate is not None:
544
642
  maker = self.parse_number(Precise.string_div(firstMakerFeeRate, '100'))
545
- takerFees = self.safe_value(market, 'fees', [])
546
- firstTakerFee = self.safe_value(takerFees, 0, [])
643
+ takerFees = self.safe_list(market, 'fees', [])
644
+ firstTakerFee = self.safe_list(takerFees, 0, [])
547
645
  firstTakerFeeRate = self.safe_string(firstTakerFee, 1)
548
646
  taker = None
549
647
  if firstTakerFeeRate is not None:
550
648
  taker = self.parse_number(Precise.string_div(firstTakerFeeRate, '100'))
551
- leverageBuy = self.safe_value(market, 'leverage_buy', [])
649
+ leverageBuy = self.safe_list(market, 'leverage_buy', [])
552
650
  leverageBuyLength = len(leverageBuy)
553
651
  precisionPrice = self.parse_number(self.parse_precision(self.safe_string(market, 'pair_decimals')))
652
+ precisionAmount = self.parse_number(self.parse_precision(self.safe_string(market, 'lot_decimals')))
653
+ spot = True
654
+ # fix https://github.com/freqtrade/freqtrade/issues/11765#issuecomment-2894224103
655
+ if spot and (base in cachedCurrencies):
656
+ currency = cachedCurrencies[base]
657
+ currencyPrecision = self.safe_number(currency, 'precision')
658
+ # if currency precision is greater(e.g. 0.01) than market precision(e.g. 0.001)
659
+ if currencyPrecision > precisionAmount:
660
+ precisionAmount = currencyPrecision
554
661
  status = self.safe_string(market, 'status')
555
662
  isActive = status == 'online'
556
663
  result.append({
557
664
  'id': id,
558
665
  'wsId': self.safe_string(market, 'wsname'),
559
- 'symbol': altname if darkpool else (base + '/' + quote),
666
+ 'symbol': base + '/' + quote,
560
667
  'base': base,
561
668
  'quote': quote,
562
669
  'settle': None,
563
670
  'baseId': baseId,
564
671
  'quoteId': quoteId,
565
672
  'settleId': None,
566
- 'darkpool': darkpool,
567
673
  'altname': market['altname'],
568
674
  'type': 'spot',
569
- 'spot': True,
675
+ 'spot': spot,
570
676
  'margin': (leverageBuyLength > 0),
571
677
  'swap': False,
572
678
  'future': False,
@@ -583,7 +689,7 @@ class kraken(Exchange, ImplicitAPI):
583
689
  'strike': None,
584
690
  'optionType': None,
585
691
  'precision': {
586
- 'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'lot_decimals'))),
692
+ 'amount': precisionAmount,
587
693
  'price': precisionPrice,
588
694
  },
589
695
  'limits': {
@@ -596,7 +702,7 @@ class kraken(Exchange, ImplicitAPI):
596
702
  'max': None,
597
703
  },
598
704
  'price': {
599
- 'min': precisionPrice,
705
+ 'min': None,
600
706
  'max': None,
601
707
  },
602
708
  'cost': {
@@ -607,7 +713,6 @@ class kraken(Exchange, ImplicitAPI):
607
713
  'created': None,
608
714
  'info': market,
609
715
  })
610
- result = self.append_inactive_markets(result)
611
716
  self.options['marketsByAltname'] = self.index_by(result, 'altname')
612
717
  return result
613
718
 
@@ -615,40 +720,42 @@ class kraken(Exchange, ImplicitAPI):
615
720
  if currencyId is not None:
616
721
  if len(currencyId) > 3:
617
722
  if (currencyId.find('X') == 0) or (currencyId.find('Z') == 0):
618
- if not (currencyId.find('.') > 0):
723
+ if not (currencyId.find('.') > 0) and (currencyId != 'ZEUS'):
619
724
  currencyId = currencyId[1:]
620
725
  return super(kraken, self).safe_currency(currencyId, currency)
621
726
 
622
- def append_inactive_markets(self, result):
623
- # result should be an array to append to
624
- precision: dict = {
625
- 'amount': self.parse_number('1e-8'),
626
- 'price': self.parse_number('1e-8'),
627
- }
628
- costLimits: dict = {'min': None, 'max': None}
629
- priceLimits: dict = {'min': precision['price'], 'max': None}
630
- amountLimits: dict = {'min': precision['amount'], 'max': None}
631
- limits: dict = {'amount': amountLimits, 'price': priceLimits, 'cost': costLimits}
632
- defaults: dict = {
633
- 'darkpool': False,
634
- 'info': None,
635
- 'maker': None,
636
- 'taker': None,
637
- 'active': False,
638
- 'precision': precision,
639
- 'limits': limits,
727
+ async def fetch_status(self, params={}):
728
+ """
729
+ the latest known information on the availability of the exchange API
730
+
731
+ https://docs.kraken.com/api/docs/rest-api/get-system-status/
732
+
733
+ :param dict [params]: extra parameters specific to the exchange API endpoint
734
+ :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
735
+ """
736
+ response = await self.publicGetSystemStatus(params)
737
+ #
738
+ # {
739
+ # error: [],
740
+ # result: {status: 'online', timestamp: '2024-07-22T16:34:44Z'}
741
+ # }
742
+ #
743
+ result = self.safe_dict(response, 'result')
744
+ statusRaw = self.safe_string(result, 'status')
745
+ return {
746
+ 'status': 'ok' if (statusRaw == 'online') else 'maintenance',
747
+ 'updated': None,
748
+ 'eta': None,
749
+ 'url': None,
750
+ 'info': response,
640
751
  }
641
- markets = [
642
- # {'id': 'XXLMZEUR', 'symbol': 'XLM/EUR', 'base': 'XLM', 'quote': 'EUR', 'altname': 'XLMEUR'},
643
- ]
644
- for i in range(0, len(markets)):
645
- result.append(self.extend(defaults, markets[i]))
646
- return result
647
752
 
648
753
  async def fetch_currencies(self, params={}) -> Currencies:
649
754
  """
650
755
  fetches all available currencies on an exchange
651
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getAssetInfo
756
+
757
+ https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getAssetInfo
758
+
652
759
  :param dict [params]: extra parameters specific to the exchange API endpoint
653
760
  :returns dict: an associative dictionary of currencies
654
761
  """
@@ -657,9 +764,48 @@ class kraken(Exchange, ImplicitAPI):
657
764
  # {
658
765
  # "error": [],
659
766
  # "result": {
660
- # "BCH": {
767
+ # "ATOM": {
768
+ # "aclass": "currency",
769
+ # "altname": "ATOM",
770
+ # "collateral_value": "0.7",
771
+ # "decimals": 8,
772
+ # "display_decimals": 6,
773
+ # "margin_rate": 0.02,
774
+ # "status": "enabled",
775
+ # },
776
+ # "ATOM.S": {
661
777
  # "aclass": "currency",
662
- # "altname": "BCH",
778
+ # "altname": "ATOM.S",
779
+ # "decimals": 8,
780
+ # "display_decimals": 6,
781
+ # "status": "enabled",
782
+ # },
783
+ # "XXBT": {
784
+ # "aclass": "currency",
785
+ # "altname": "XBT",
786
+ # "decimals": 10,
787
+ # "display_decimals": 5,
788
+ # "margin_rate": 0.01,
789
+ # "status": "enabled",
790
+ # },
791
+ # "XETH": {
792
+ # "aclass": "currency",
793
+ # "altname": "ETH",
794
+ # "decimals": 10,
795
+ # "display_decimals": 5
796
+ # "margin_rate": 0.02,
797
+ # "status": "enabled",
798
+ # },
799
+ # "XBT.M": {
800
+ # "aclass": "currency",
801
+ # "altname": "XBT.M",
802
+ # "decimals": 10,
803
+ # "display_decimals": 5
804
+ # "status": "enabled",
805
+ # },
806
+ # "ETH.M": {
807
+ # "aclass": "currency",
808
+ # "altname": "ETH.M",
663
809
  # "decimals": 10,
664
810
  # "display_decimals": 5
665
811
  # "status": "enabled",
@@ -678,23 +824,42 @@ class kraken(Exchange, ImplicitAPI):
678
824
  # see: https://support.kraken.com/hc/en-us/articles/201893608-What-are-the-withdrawal-fees-
679
825
  # to add support for multiple withdrawal/deposit methods and
680
826
  # differentiated fees for each particular method
827
+ #
828
+ # Notes about abbreviations:
829
+ # Z and X prefixes: https://support.kraken.com/hc/en-us/articles/360001206766-Bitcoin-currency-code-XBT-vs-BTC
830
+ # S and M suffixes: https://support.kraken.com/hc/en-us/articles/360039879471-What-is-Asset-S-and-Asset-M-
831
+ #
681
832
  code = self.safe_currency_code(id)
682
- precision = self.parse_number(self.parse_precision(self.safe_string(currency, 'decimals')))
683
- # assumes all currencies are active except those listed above
684
- active = self.safe_string(currency, 'status') == 'enabled'
685
- result[code] = {
833
+ # the below can not be reliable done in `safeCurrencyCode`, so we have to do it here
834
+ if id.find('.') < 0:
835
+ altName = self.safe_string(currency, 'altname')
836
+ # handle cases like below:
837
+ #
838
+ # id | altname
839
+ # ---------------
840
+ # XXBT | XBT
841
+ # ZUSD | USD
842
+ if id != altName and (id.startswith('X') or id.startswith('Z')):
843
+ code = self.safe_currency_code(altName)
844
+ # also, add map in commonCurrencies:
845
+ self.commonCurrencies[id] = code
846
+ else:
847
+ code = self.safe_currency_code(id)
848
+ isFiat = code.find('.HOLD') >= 0
849
+ result[code] = self.safe_currency_structure({
686
850
  'id': id,
687
851
  'code': code,
688
852
  'info': currency,
689
853
  'name': self.safe_string(currency, 'altname'),
690
- 'active': active,
854
+ 'active': self.safe_string(currency, 'status') == 'enabled',
855
+ 'type': 'fiat' if isFiat else 'crypto',
691
856
  'deposit': None,
692
857
  'withdraw': None,
693
858
  'fee': None,
694
- 'precision': precision,
859
+ 'precision': self.parse_number(self.parse_precision(self.safe_string(currency, 'decimals'))),
695
860
  'limits': {
696
861
  'amount': {
697
- 'min': precision,
862
+ 'min': None,
698
863
  'max': None,
699
864
  },
700
865
  'withdraw': {
@@ -703,13 +868,26 @@ class kraken(Exchange, ImplicitAPI):
703
868
  },
704
869
  },
705
870
  'networks': {},
706
- }
871
+ })
707
872
  return result
708
873
 
874
+ def safe_currency_code(self, currencyId: Str, currency: Currency = None) -> Str:
875
+ if currencyId is None:
876
+ return currencyId
877
+ if currencyId.find('.') > 0:
878
+ # if ID contains .M, .S or .F, then it can't contain X or Z prefix. in such case, ID equals to ALTNAME
879
+ parts = currencyId.split('.')
880
+ firstPart = self.safe_string(parts, 0)
881
+ secondPart = self.safe_string(parts, 1)
882
+ return super(kraken, self).safe_currency_code(firstPart, currency) + '.' + secondPart
883
+ return super(kraken, self).safe_currency_code(currencyId, currency)
884
+
709
885
  async def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
710
886
  """
711
887
  fetch the trading fees for a market
712
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradeVolume
888
+
889
+ https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradeVolume
890
+
713
891
  :param str symbol: unified market symbol
714
892
  :param dict [params]: extra parameters specific to the exchange API endpoint
715
893
  :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
@@ -776,7 +954,9 @@ class kraken(Exchange, ImplicitAPI):
776
954
  async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
777
955
  """
778
956
  fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
779
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getOrderBook
957
+
958
+ https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getOrderBook
959
+
780
960
  :param str symbol: unified symbol of the market to fetch the order book for
781
961
  :param int [limit]: the maximum amount of order book entries to return
782
962
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -784,8 +964,6 @@ class kraken(Exchange, ImplicitAPI):
784
964
  """
785
965
  await self.load_markets()
786
966
  market = self.market(symbol)
787
- if market['darkpool']:
788
- raise ExchangeError(self.id + ' fetchOrderBook() does not provide an order book for darkpool symbol ' + symbol)
789
967
  request: dict = {
790
968
  'pair': market['id'],
791
969
  }
@@ -854,9 +1032,9 @@ class kraken(Exchange, ImplicitAPI):
854
1032
  'high': self.safe_string(high, 1),
855
1033
  'low': self.safe_string(low, 1),
856
1034
  'bid': self.safe_string(bid, 0),
857
- 'bidVolume': None,
1035
+ 'bidVolume': self.safe_string(bid, 2),
858
1036
  'ask': self.safe_string(ask, 0),
859
- 'askVolume': None,
1037
+ 'askVolume': self.safe_string(ask, 2),
860
1038
  'vwap': vwap,
861
1039
  'open': self.safe_string(ticker, 'o'),
862
1040
  'close': last,
@@ -873,7 +1051,9 @@ class kraken(Exchange, ImplicitAPI):
873
1051
  async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
874
1052
  """
875
1053
  fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
876
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTickerInformation
1054
+
1055
+ https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTickerInformation
1056
+
877
1057
  :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
878
1058
  :param dict [params]: extra parameters specific to the exchange API endpoint
879
1059
  :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -886,7 +1066,7 @@ class kraken(Exchange, ImplicitAPI):
886
1066
  for i in range(0, len(symbols)):
887
1067
  symbol = symbols[i]
888
1068
  market = self.markets[symbol]
889
- if market['active'] and not market['darkpool']:
1069
+ if market['active']:
890
1070
  marketIds.append(market['id'])
891
1071
  request['pair'] = ','.join(marketIds)
892
1072
  response = await self.publicGetTicker(self.extend(request, params))
@@ -904,15 +1084,14 @@ class kraken(Exchange, ImplicitAPI):
904
1084
  async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
905
1085
  """
906
1086
  fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
907
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTickerInformation
1087
+
1088
+ https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTickerInformation
1089
+
908
1090
  :param str symbol: unified symbol of the market to fetch the ticker for
909
1091
  :param dict [params]: extra parameters specific to the exchange API endpoint
910
1092
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
911
1093
  """
912
1094
  await self.load_markets()
913
- darkpool = symbol.find('.d') >= 0
914
- if darkpool:
915
- raise ExchangeError(self.id + ' fetchTicker() does not provide a ticker for darkpool symbol ' + symbol)
916
1095
  market = self.market(symbol)
917
1096
  request: dict = {
918
1097
  'pair': market['id'],
@@ -946,7 +1125,9 @@ class kraken(Exchange, ImplicitAPI):
946
1125
  async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
947
1126
  """
948
1127
  fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
949
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getOHLCData
1128
+
1129
+ https://docs.kraken.com/api/docs/rest-api/get-ohlc-data
1130
+
950
1131
  :param str symbol: unified symbol of the market to fetch OHLCV data for
951
1132
  :param str timeframe: the length of time each candle represents
952
1133
  :param int [since]: timestamp in ms of the earliest candle to fetch
@@ -1001,7 +1182,7 @@ class kraken(Exchange, ImplicitAPI):
1001
1182
  }
1002
1183
  return self.safe_string(types, type, type)
1003
1184
 
1004
- def parse_ledger_entry(self, item: dict, currency: Currency = None):
1185
+ def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
1005
1186
  #
1006
1187
  # {
1007
1188
  # 'LTFK7F-N2CUX-PNY4SX': {
@@ -1023,15 +1204,17 @@ class kraken(Exchange, ImplicitAPI):
1023
1204
  referenceId = self.safe_string(item, 'refid')
1024
1205
  referenceAccount = None
1025
1206
  type = self.parse_ledger_entry_type(self.safe_string(item, 'type'))
1026
- code = self.safe_currency_code(self.safe_string(item, 'asset'), currency)
1207
+ currencyId = self.safe_string(item, 'asset')
1208
+ code = self.safe_currency_code(currencyId, currency)
1209
+ currency = self.safe_currency(currencyId, currency)
1027
1210
  amount = self.safe_string(item, 'amount')
1028
1211
  if Precise.string_lt(amount, '0'):
1029
1212
  direction = 'out'
1030
1213
  amount = Precise.string_abs(amount)
1031
1214
  else:
1032
1215
  direction = 'in'
1033
- timestamp = self.safe_timestamp(item, 'time')
1034
- return {
1216
+ timestamp = self.safe_integer_product(item, 'time', 1000)
1217
+ return self.safe_ledger_entry({
1035
1218
  'info': item,
1036
1219
  'id': id,
1037
1220
  'direction': direction,
@@ -1050,18 +1233,21 @@ class kraken(Exchange, ImplicitAPI):
1050
1233
  'cost': self.safe_number(item, 'fee'),
1051
1234
  'currency': code,
1052
1235
  },
1053
- }
1236
+ }, currency)
1054
1237
 
1055
- async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
1238
+ async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
1056
1239
  """
1057
- fetch the history of changes, actions done by the user or operations that altered balance of the user
1058
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getLedgers
1059
- :param str code: unified currency code, default is None
1240
+ fetch the history of changes, actions done by the user or operations that altered the balance of the user
1241
+
1242
+ https://docs.kraken.com/rest/#tag/Account-Data/operation/getLedgers
1243
+
1244
+ :param str [code]: unified currency code, default is None
1060
1245
  :param int [since]: timestamp in ms of the earliest ledger entry, default is None
1061
- :param int [limit]: max number of ledger entrys to return, default is None
1246
+ :param int [limit]: max number of ledger entries to return, default is None
1062
1247
  :param dict [params]: extra parameters specific to the exchange API endpoint
1063
1248
  :param int [params.until]: timestamp in ms of the latest ledger entry
1064
- :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
1249
+ :param int [params.end]: timestamp in seconds of the latest ledger entry
1250
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
1065
1251
  """
1066
1252
  # https://www.kraken.com/features/api#get-ledgers-info
1067
1253
  await self.load_markets()
@@ -1072,7 +1258,11 @@ class kraken(Exchange, ImplicitAPI):
1072
1258
  request['asset'] = currency['id']
1073
1259
  if since is not None:
1074
1260
  request['start'] = self.parse_to_int(since / 1000)
1075
- request, params = self.handle_until_option('end', request, params)
1261
+ until = self.safe_string_n(params, ['until', 'till'])
1262
+ if until is not None:
1263
+ params = self.omit(params, ['until', 'till'])
1264
+ untilDivided = Precise.string_div(until, '1000')
1265
+ request['end'] = self.parse_to_int(Precise.string_add(untilDivided, '1'))
1076
1266
  response = await self.privatePostLedgers(self.extend(request, params))
1077
1267
  # { error: [],
1078
1268
  # "result": {ledger: {'LPUAIB-TS774-UKHP7X': { refid: "A2B4HBV-L4MDIE-JU4N3N",
@@ -1121,7 +1311,7 @@ class kraken(Exchange, ImplicitAPI):
1121
1311
  items.append(value)
1122
1312
  return self.parse_ledger(items)
1123
1313
 
1124
- async def fetch_ledger_entry(self, id: str, code: Str = None, params={}):
1314
+ async def fetch_ledger_entry(self, id: str, code: Str = None, params={}) -> LedgerEntry:
1125
1315
  items = await self.fetch_ledger_entries_by_ids([id], code, params)
1126
1316
  return items[0]
1127
1317
 
@@ -1156,7 +1346,40 @@ class kraken(Exchange, ImplicitAPI):
1156
1346
  # "misc": ''
1157
1347
  # }
1158
1348
  #
1349
+ # fetchMyTrades
1350
+ #
1351
+ # {
1352
+ # "ordertxid": "OSJVN7-A2AE-63WZV",
1353
+ # "postxid": "TBP7O6-PNXI-CONU",
1354
+ # "pair": "XXBTZUSD",
1355
+ # "time": 1710429248.3052235,
1356
+ # "type": "sell",
1357
+ # "ordertype": "liquidation market",
1358
+ # "price": "72026.50000",
1359
+ # "cost": "7.20265",
1360
+ # "fee": "0.01873",
1361
+ # "vol": "0.00010000",
1362
+ # "margin": "1.44053",
1363
+ # "leverage": "5",
1364
+ # "misc": "closing",
1365
+ # "trade_id": 68230622,
1366
+ # "maker": False
1367
+ # }
1368
+ #
1369
+ # watchTrades
1370
+ #
1371
+ # {
1372
+ # "symbol": "BTC/USD",
1373
+ # "side": "buy",
1374
+ # "price": 109601.2,
1375
+ # "qty": 0.04561994,
1376
+ # "ord_type": "market",
1377
+ # "trade_id": 83449369,
1378
+ # "timestamp": "2025-05-27T11:24:03.847761Z"
1379
+ # }
1380
+ #
1159
1381
  timestamp = None
1382
+ datetime = None
1160
1383
  side = None
1161
1384
  type = None
1162
1385
  price = None
@@ -1199,19 +1422,35 @@ class kraken(Exchange, ImplicitAPI):
1199
1422
  'cost': self.safe_string(trade, 'fee'),
1200
1423
  'currency': currency,
1201
1424
  }
1425
+ else:
1426
+ symbol = self.safe_string(trade, 'symbol')
1427
+ datetime = self.safe_string(trade, 'timestamp')
1428
+ id = self.safe_string(trade, 'trade_id')
1429
+ side = self.safe_string(trade, 'side')
1430
+ type = self.safe_string(trade, 'ord_type')
1431
+ price = self.safe_string(trade, 'price')
1432
+ amount = self.safe_string(trade, 'qty')
1202
1433
  if market is not None:
1203
1434
  symbol = market['symbol']
1204
1435
  cost = self.safe_string(trade, 'cost')
1436
+ maker = self.safe_bool(trade, 'maker')
1437
+ takerOrMaker = None
1438
+ if maker is not None:
1439
+ takerOrMaker = 'maker' if maker else 'taker'
1440
+ if datetime is None:
1441
+ datetime = self.iso8601(timestamp)
1442
+ else:
1443
+ timestamp = self.parse8601(datetime)
1205
1444
  return self.safe_trade({
1206
1445
  'id': id,
1207
1446
  'order': orderId,
1208
1447
  'info': trade,
1209
1448
  'timestamp': timestamp,
1210
- 'datetime': self.iso8601(timestamp),
1449
+ 'datetime': datetime,
1211
1450
  'symbol': symbol,
1212
1451
  'type': type,
1213
1452
  'side': side,
1214
- 'takerOrMaker': None,
1453
+ 'takerOrMaker': takerOrMaker,
1215
1454
  'price': price,
1216
1455
  'amount': amount,
1217
1456
  'cost': cost,
@@ -1221,7 +1460,9 @@ class kraken(Exchange, ImplicitAPI):
1221
1460
  async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1222
1461
  """
1223
1462
  get the list of most recent trades for a particular symbol
1224
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getRecentTrades
1463
+
1464
+ https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getRecentTrades
1465
+
1225
1466
  :param str symbol: unified symbol of the market to fetch trades for
1226
1467
  :param int [since]: timestamp in ms of the earliest trade to fetch
1227
1468
  :param int [limit]: the maximum amount of trades to fetch
@@ -1285,7 +1526,9 @@ class kraken(Exchange, ImplicitAPI):
1285
1526
  async def fetch_balance(self, params={}) -> Balances:
1286
1527
  """
1287
1528
  query for balance and get the amount of funds available for trading or funds locked in orders
1288
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getExtendedBalance
1529
+
1530
+ https://docs.kraken.com/rest/#tag/Account-Data/operation/getExtendedBalance
1531
+
1289
1532
  :param dict [params]: extra parameters specific to the exchange API endpoint
1290
1533
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1291
1534
  """
@@ -1311,7 +1554,9 @@ class kraken(Exchange, ImplicitAPI):
1311
1554
  async def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost: float, params={}):
1312
1555
  """
1313
1556
  create a market order by providing the symbol, side and cost
1314
- :see: https://docs.kraken.com/rest/#tag/Trading/operation/addOrder
1557
+
1558
+ https://docs.kraken.com/rest/#tag/Spot-Trading/operation/addOrder
1559
+
1315
1560
  :param str symbol: unified symbol of the market to create an order in(only USD markets are supported)
1316
1561
  :param str side: 'buy' or 'sell'
1317
1562
  :param float cost: how much you want to trade in units of the quote currency
@@ -1320,13 +1565,17 @@ class kraken(Exchange, ImplicitAPI):
1320
1565
  """
1321
1566
  await self.load_markets()
1322
1567
  # only buy orders are supported by the endpoint
1323
- params['cost'] = cost
1324
- return await self.create_order(symbol, 'market', side, cost, None, params)
1568
+ req = {
1569
+ 'cost': cost,
1570
+ }
1571
+ return await self.create_order(symbol, 'market', side, cost, None, self.extend(req, params))
1325
1572
 
1326
1573
  async def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
1327
1574
  """
1328
1575
  create a market buy order by providing the symbol, side and cost
1329
- :see: https://docs.kraken.com/rest/#tag/Trading/operation/addOrder
1576
+
1577
+ https://docs.kraken.com/rest/#tag/Spot-Trading/operation/addOrder
1578
+
1330
1579
  :param str symbol: unified symbol of the market to create an order in
1331
1580
  :param float cost: how much you want to trade in units of the quote currency
1332
1581
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -1337,20 +1586,24 @@ class kraken(Exchange, ImplicitAPI):
1337
1586
 
1338
1587
  async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1339
1588
  """
1340
- :see: https://docs.kraken.com/rest/#tag/Trading/operation/addOrder
1341
1589
  create a trade order
1590
+
1591
+ https://docs.kraken.com/api/docs/rest-api/add-order
1592
+
1342
1593
  :param str symbol: unified symbol of the market to create an order in
1343
1594
  :param str type: 'market' or 'limit'
1344
1595
  :param str side: 'buy' or 'sell'
1345
1596
  :param float amount: how much of currency you want to trade in units of base currency
1346
- :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1597
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1347
1598
  :param dict [params]: extra parameters specific to the exchange API endpoint
1348
1599
  :param bool [params.postOnly]: if True, the order will only be posted to the order book and not executed immediately
1349
1600
  :param bool [params.reduceOnly]: *margin only* indicates if self order is to reduce the size of a position
1350
1601
  :param float [params.stopLossPrice]: *margin only* the price that a stop loss order is triggered at
1351
1602
  :param float [params.takeProfitPrice]: *margin only* the price that a take profit order is triggered at
1352
1603
  :param str [params.trailingAmount]: *margin only* the quote amount to trail away from the current market price
1604
+ :param str [params.trailingPercent]: *margin only* the percent to trail away from the current market price
1353
1605
  :param str [params.trailingLimitAmount]: *margin only* the quote amount away from the trailingAmount
1606
+ :param str [params.trailingLimitPercent]: *margin only* the percent away from the trailingAmount
1354
1607
  :param str [params.offset]: *margin only* '+' or '-' whether you want the trailingLimitAmount value to be positive or negative, default is negative '-'
1355
1608
  :param str [params.trigger]: *margin only* the activation price type, 'last' or 'index', default is 'last'
1356
1609
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
@@ -1364,17 +1617,23 @@ class kraken(Exchange, ImplicitAPI):
1364
1617
  'volume': self.amount_to_precision(symbol, amount),
1365
1618
  }
1366
1619
  orderRequest = self.order_request('createOrder', symbol, type, request, amount, price, params)
1620
+ flags = self.safe_string(orderRequest[0], 'oflags', '')
1621
+ isUsingCost = flags.find('viqc') > -1
1367
1622
  response = await self.privatePostAddOrder(self.extend(orderRequest[0], orderRequest[1]))
1368
1623
  #
1369
1624
  # {
1370
1625
  # "error": [],
1371
1626
  # "result": {
1372
- # "descr": {order: 'buy 0.02100000 ETHUSDT @ limit 330.00'},
1627
+ # "descr": {order: 'buy 0.02100000 ETHUSDT @ limit 330.00'}, # see more examples in "parseOrder"
1373
1628
  # "txid": ['OEKVV2-IH52O-TPL6GZ']
1374
1629
  # }
1375
1630
  # }
1376
1631
  #
1377
1632
  result = self.safe_dict(response, 'result')
1633
+ result['usingCost'] = isUsingCost
1634
+ # it's impossible to know if the order was created using cost or base currency
1635
+ # becuase kraken only returns something like self: {order: 'buy 10.00000000 LTCUSD @ market'}
1636
+ # self usingCost flag is used to help the parsing but omited from the order
1378
1637
  return self.parse_order(result)
1379
1638
 
1380
1639
  def find_market_by_altname_or_id(self, id):
@@ -1429,9 +1688,10 @@ class kraken(Exchange, ImplicitAPI):
1429
1688
 
1430
1689
  def parse_order_type(self, status):
1431
1690
  statuses: dict = {
1691
+ # we dont add "space" delimited orders here(eg. stop loss) because they need separate parsing
1432
1692
  'take-profit': 'market',
1433
- 'stop-loss-limit': 'limit',
1434
1693
  'stop-loss': 'market',
1694
+ 'stop-loss-limit': 'limit',
1435
1695
  'take-profit-limit': 'limit',
1436
1696
  'trailing-stop-limit': 'limit',
1437
1697
  }
@@ -1439,61 +1699,36 @@ class kraken(Exchange, ImplicitAPI):
1439
1699
 
1440
1700
  def parse_order(self, order: dict, market: Market = None) -> Order:
1441
1701
  #
1442
- # createOrder for regular orders
1702
+ # createOrder
1443
1703
  #
1444
1704
  # {
1445
- # "descr": {order: 'buy 0.02100000 ETHUSDT @ limit 330.00'},
1705
+ # "descr": {
1706
+ # "order": "buy 0.02100000 ETHUSDT @ limit 330.00" # limit orders
1707
+ # "buy 0.12345678 ETHUSDT @ market" # market order
1708
+ # "sell 0.28002676 ETHUSDT @ stop loss 0.0123 -> limit 0.0.1222" # stop order
1709
+ # "sell 0.00100000 ETHUSDT @ stop loss 2677.00 -> limit 2577.00 with 5:1 leverage"
1710
+ # "buy 0.10000000 LTCUSDT @ take profit 75.00000 -> limit 74.00000"
1711
+ # "sell 10.00000000 XRPEUR @ trailing stop +50.0000%" # trailing stop
1712
+ # },
1446
1713
  # "txid": ['OEKVV2-IH52O-TPL6GZ']
1447
1714
  # }
1448
- # {
1449
- # "txid": ["TX_ID_HERE"],
1450
- # "descr": {"order":"buy 0.12345678 ETHEUR @ market"},
1451
- # }
1452
- #
1453
1715
  #
1454
- # createOrder for stop orders
1716
+ # editOrder
1455
1717
  #
1456
1718
  # {
1457
- # "txid":["OSILNC-VQI5Q-775ZDQ"],
1458
- # "descr":{"order":"sell 167.28002676 ADAXBT @ stop loss 0.00003280 -> limit 0.00003212"}
1719
+ # "amend_id": "TJSMEH-AA67V-YUSQ6O"
1459
1720
  # }
1460
1721
  #
1461
- #
1722
+ # ws - createOrder
1462
1723
  # {
1463
- # "txid":["OVHMJV-BZW2V-6NZFWF"],
1464
- # "descr":{"order":"sell 0.00100000 ETHUSD @ stop loss 2677.00 -> limit 2577.00 with 5:1 leverage"}
1724
+ # "order_id": "OXM2QD-EALR2-YBAVEU"
1465
1725
  # }
1466
1726
  #
1467
- # editOrder
1468
- #
1727
+ # ws - editOrder
1469
1728
  # {
1470
- # "status": "ok",
1471
- # "txid": "OAW2BO-7RWEK-PZY5UO",
1472
- # "originaltxid": "OXL6SS-UPNMC-26WBE7",
1473
- # "volume": "0.00075000",
1474
- # "price": "13500.0",
1475
- # "orders_cancelled": 1,
1476
- # "descr": {
1477
- # "order": "buy 0.00075000 XBTUSDT @ limit 13500.0"
1478
- # }
1729
+ # "amend_id": "TJSMEH-AA67V-YUSQ6O",
1730
+ # "order_id": "OXM2QD-EALR2-YBAVEU"
1479
1731
  # }
1480
- # ws - createOrder
1481
- # {
1482
- # "descr": 'sell 0.00010000 XBTUSDT @ market',
1483
- # "event": 'addOrderStatus',
1484
- # "reqid": 1,
1485
- # "status": 'ok',
1486
- # "txid": 'OAVXZH-XIE54-JCYYDG'
1487
- # }
1488
- # ws - editOrder
1489
- # {
1490
- # "descr": "order edited price = 9000.00000000",
1491
- # "event": "editOrderStatus",
1492
- # "originaltxid": "O65KZW-J4AW3-VFS74A",
1493
- # "reqid": 3,
1494
- # "status": "ok",
1495
- # "txid": "OTI672-HJFAO-XOIPPK"
1496
- # }
1497
1732
  #
1498
1733
  # {
1499
1734
  # "error": [],
@@ -1530,6 +1765,39 @@ class kraken(Exchange, ImplicitAPI):
1530
1765
  # }
1531
1766
  # }
1532
1767
  #
1768
+ # fetchOpenOrders
1769
+ #
1770
+ # {
1771
+ # "refid": null,
1772
+ # "userref": null,
1773
+ # "cl_ord_id": "1234",
1774
+ # "status": "open",
1775
+ # "opentm": 1733815269.370054,
1776
+ # "starttm": 0,
1777
+ # "expiretm": 0,
1778
+ # "descr": {
1779
+ # "pair": "XBTUSD",
1780
+ # "type": "buy",
1781
+ # "ordertype": "limit",
1782
+ # "price": "70000.0",
1783
+ # "price2": "0",
1784
+ # "leverage": "none",
1785
+ # "order": "buy 0.00010000 XBTUSD @ limit 70000.0",
1786
+ # "close": ""
1787
+ # },
1788
+ # "vol": "0.00010000",
1789
+ # "vol_exec": "0.00000000",
1790
+ # "cost": "0.00000",
1791
+ # "fee": "0.00000",
1792
+ # "price": "0.00000",
1793
+ # "stopprice": "0.00000",
1794
+ # "limitprice": "0.00000",
1795
+ # "misc": "",
1796
+ # "oflags": "fciq"
1797
+ # }
1798
+ #
1799
+ isUsingCost = self.safe_bool(order, 'usingCost', False)
1800
+ order = self.omit(order, 'usingCost')
1533
1801
  description = self.safe_dict(order, 'descr', {})
1534
1802
  orderDescriptionObj = self.safe_dict(order, 'descr') # can be null
1535
1803
  orderDescription = None
@@ -1538,24 +1806,33 @@ class kraken(Exchange, ImplicitAPI):
1538
1806
  else:
1539
1807
  orderDescription = self.safe_string(order, 'descr')
1540
1808
  side = None
1541
- type = None
1809
+ rawType = None
1542
1810
  marketId = None
1543
1811
  price = None
1544
1812
  amount = None
1545
- stopPrice = None
1813
+ cost = None
1814
+ triggerPrice = None
1546
1815
  if orderDescription is not None:
1547
1816
  parts = orderDescription.split(' ')
1548
1817
  side = self.safe_string(parts, 0)
1549
- amount = self.safe_string(parts, 1)
1818
+ if not isUsingCost:
1819
+ amount = self.safe_string(parts, 1)
1820
+ else:
1821
+ cost = self.safe_string(parts, 1)
1550
1822
  marketId = self.safe_string(parts, 2)
1551
- type = self.safe_string(parts, 4)
1552
- if type == 'stop':
1553
- stopPrice = self.safe_string(parts, 6)
1823
+ part4 = self.safe_string(parts, 4)
1824
+ part5 = self.safe_string(parts, 5)
1825
+ if part4 == 'limit' or part4 == 'market':
1826
+ rawType = part4 # eg, limit, market
1827
+ else:
1828
+ rawType = part4 + ' ' + part5 # eg. stop loss, take profit, trailing stop
1829
+ if rawType == 'stop loss' or rawType == 'take profit':
1830
+ triggerPrice = self.safe_string(parts, 6)
1554
1831
  price = self.safe_string(parts, 9)
1555
- elif type == 'limit':
1832
+ elif rawType == 'limit':
1556
1833
  price = self.safe_string(parts, 5)
1557
1834
  side = self.safe_string(description, 'type', side)
1558
- type = self.safe_string(description, 'ordertype', type)
1835
+ rawType = self.safe_string(description, 'ordertype', rawType) # orderType has dash, e.g. trailing-stop
1559
1836
  marketId = self.safe_string(description, 'pair', marketId)
1560
1837
  foundMarket = self.find_market_by_altname_or_id(marketId)
1561
1838
  symbol = None
@@ -1571,13 +1848,12 @@ class kraken(Exchange, ImplicitAPI):
1571
1848
  # kraken truncates the cost in the api response so we will ignore it and calculate it from average & filled
1572
1849
  # cost = self.safe_string(order, 'cost')
1573
1850
  price = self.safe_string(description, 'price', price)
1574
- # when type = trailling stop returns price = '+50.0000%'
1575
- if (price is not None) and price.endswith('%'):
1851
+ # when type = trailing stop returns price = '+50.0000%'
1852
+ if (price is not None) and (price.endswith('%') or Precise.string_equals(price, '0.00000') or Precise.string_equals(price, '0')):
1576
1853
  price = None # self is not the price we want
1577
- if (price is None) or Precise.string_equals(price, '0'):
1854
+ if price is None:
1578
1855
  price = self.safe_string(description, 'price2')
1579
- if (price is None) or Precise.string_equals(price, '0'):
1580
- price = self.safe_string(order, 'price', price)
1856
+ price = self.safe_string_2(order, 'limitprice', 'price', price)
1581
1857
  flags = self.safe_string(order, 'oflags', '')
1582
1858
  isPostOnly = flags.find('post') > -1
1583
1859
  average = self.safe_number(order, 'price')
@@ -1594,11 +1870,12 @@ class kraken(Exchange, ImplicitAPI):
1594
1870
  elif flags.find('fcib') >= 0:
1595
1871
  fee['currency'] = market['base']
1596
1872
  status = self.parse_order_status(self.safe_string(order, 'status'))
1597
- id = self.safe_string_2(order, 'id', 'txid')
1873
+ id = self.safe_string_n(order, ['id', 'txid', 'order_id', 'amend_id'])
1598
1874
  if (id is None) or (id.startswith('[')):
1599
1875
  txid = self.safe_list(order, 'txid')
1600
1876
  id = self.safe_string(txid, 0)
1601
- clientOrderId = self.safe_string(order, 'userref')
1877
+ userref = self.safe_string(order, 'userref')
1878
+ clientOrderId = self.safe_string(order, 'cl_ord_id', userref)
1602
1879
  rawTrades = self.safe_value(order, 'trades', [])
1603
1880
  trades = []
1604
1881
  for i in range(0, len(rawTrades)):
@@ -1607,15 +1884,32 @@ class kraken(Exchange, ImplicitAPI):
1607
1884
  trades.append(self.safe_trade({'id': rawTrade, 'orderId': id, 'symbol': symbol, 'info': {}}))
1608
1885
  else:
1609
1886
  trades.append(rawTrade)
1610
- stopPrice = self.omit_zero(self.safe_string(order, 'stopprice', stopPrice))
1887
+ # in #24192 PR, self field is not something consistent/actual
1888
+ # triggerPrice = self.omit_zero(self.safe_string(order, 'stopprice', triggerPrice))
1611
1889
  stopLossPrice = None
1612
1890
  takeProfitPrice = None
1613
- if type.startswith('take-profit'):
1614
- takeProfitPrice = self.safe_string(description, 'price')
1615
- price = self.omit_zero(self.safe_string(description, 'price2'))
1616
- elif type.startswith('stop-loss'):
1617
- stopLossPrice = self.safe_string(description, 'price')
1618
- price = self.omit_zero(self.safe_string(description, 'price2'))
1891
+ # the dashed strings are not provided from fields(eg. fetch order)
1892
+ # while spaced strings from "order" sentence(when other fields not available)
1893
+ if rawType is not None:
1894
+ if rawType.startswith('take-profit'):
1895
+ takeProfitPrice = self.safe_string(description, 'price')
1896
+ price = self.omit_zero(self.safe_string(description, 'price2'))
1897
+ elif rawType.startswith('stop-loss'):
1898
+ stopLossPrice = self.safe_string(description, 'price')
1899
+ price = self.omit_zero(self.safe_string(description, 'price2'))
1900
+ elif rawType == 'take profit':
1901
+ takeProfitPrice = triggerPrice
1902
+ elif rawType == 'stop loss':
1903
+ stopLossPrice = triggerPrice
1904
+ finalType = self.parse_order_type(rawType)
1905
+ # unlike from endpoints which provide eg: "take-profit-limit"
1906
+ # for "space-delimited" orders we dont have market/limit suffixes, their format is
1907
+ # eg: `stop loss > limit 123`, so we need to parse them manually
1908
+ if self.in_array(finalType, ['stop loss', 'take profit']):
1909
+ finalType = 'market' if (price is None) else 'limit'
1910
+ amendId = self.safe_string(order, 'amend_id')
1911
+ if amendId is not None:
1912
+ isPostOnly = None
1619
1913
  return self.safe_order({
1620
1914
  'id': id,
1621
1915
  'clientOrderId': clientOrderId,
@@ -1625,37 +1919,40 @@ class kraken(Exchange, ImplicitAPI):
1625
1919
  'lastTradeTimestamp': None,
1626
1920
  'status': status,
1627
1921
  'symbol': symbol,
1628
- 'type': self.parse_order_type(type),
1922
+ 'type': finalType,
1629
1923
  'timeInForce': None,
1630
1924
  'postOnly': isPostOnly,
1631
1925
  'side': side,
1632
1926
  'price': price,
1633
- 'stopPrice': stopPrice,
1634
- 'triggerPrice': stopPrice,
1927
+ 'triggerPrice': triggerPrice,
1635
1928
  'takeProfitPrice': takeProfitPrice,
1636
1929
  'stopLossPrice': stopLossPrice,
1637
- 'cost': None,
1930
+ 'cost': cost,
1638
1931
  'amount': amount,
1639
1932
  'filled': filled,
1640
1933
  'average': average,
1641
1934
  'remaining': None,
1935
+ 'reduceOnly': self.safe_bool_2(order, 'reduceOnly', 'reduce_only'),
1642
1936
  'fee': fee,
1643
1937
  'trades': trades,
1644
1938
  }, market)
1645
1939
 
1646
1940
  def order_request(self, method: str, symbol: str, type: str, request: dict, amount: Num, price: Num = None, params={}):
1647
- clientOrderId = self.safe_string_2(params, 'userref', 'clientOrderId')
1648
- params = self.omit(params, ['userref', 'clientOrderId'])
1941
+ clientOrderId = self.safe_string(params, 'clientOrderId')
1942
+ params = self.omit(params, ['clientOrderId'])
1649
1943
  if clientOrderId is not None:
1650
- request['userref'] = clientOrderId
1944
+ request['cl_ord_id'] = clientOrderId
1651
1945
  stopLossTriggerPrice = self.safe_string(params, 'stopLossPrice')
1652
1946
  takeProfitTriggerPrice = self.safe_string(params, 'takeProfitPrice')
1653
1947
  isStopLossTriggerOrder = stopLossTriggerPrice is not None
1654
1948
  isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
1655
1949
  isStopLossOrTakeProfitTrigger = isStopLossTriggerOrder or isTakeProfitTriggerOrder
1656
1950
  trailingAmount = self.safe_string(params, 'trailingAmount')
1951
+ trailingPercent = self.safe_string(params, 'trailingPercent')
1657
1952
  trailingLimitAmount = self.safe_string(params, 'trailingLimitAmount')
1953
+ trailingLimitPercent = self.safe_string(params, 'trailingLimitPercent')
1658
1954
  isTrailingAmountOrder = trailingAmount is not None
1955
+ isTrailingPercentOrder = trailingPercent is not None
1659
1956
  isLimitOrder = type.endswith('limit') # supporting limit, stop-loss-limit, take-profit-limit, etc
1660
1957
  isMarketOrder = type == 'market'
1661
1958
  cost = self.safe_string(params, 'cost')
@@ -1669,7 +1966,7 @@ class kraken(Exchange, ImplicitAPI):
1669
1966
  request['volume'] = self.cost_to_precision(symbol, cost)
1670
1967
  extendedOflags = flags + ',viqc' if (flags is not None) else 'viqc'
1671
1968
  request['oflags'] = extendedOflags
1672
- elif isLimitOrder and not isTrailingAmountOrder:
1969
+ elif isLimitOrder and not isTrailingAmountOrder and not isTrailingPercentOrder:
1673
1970
  request['price'] = self.price_to_precision(symbol, price)
1674
1971
  reduceOnly = self.safe_bool_2(params, 'reduceOnly', 'reduce_only')
1675
1972
  if isStopLossOrTakeProfitTrigger:
@@ -1687,19 +1984,30 @@ class kraken(Exchange, ImplicitAPI):
1687
1984
  request['ordertype'] = 'take-profit'
1688
1985
  if isLimitOrder:
1689
1986
  request['price2'] = self.price_to_precision(symbol, price)
1690
- elif isTrailingAmountOrder:
1987
+ elif isTrailingAmountOrder or isTrailingPercentOrder:
1988
+ trailingPercentString = None
1989
+ if trailingPercent is not None:
1990
+ trailingPercentString = ('+' + trailingPercent) if (trailingPercent.endswith('%')) else ('+' + trailingPercent + '%')
1991
+ trailingAmountString = '+' + trailingAmount if (trailingAmount is not None) else None # must use + for self
1992
+ offset = self.safe_string(params, 'offset', '-') # can use + or - for self
1993
+ trailingLimitAmountString = offset + self.number_to_string(trailingLimitAmount) if (trailingLimitAmount is not None) else None
1691
1994
  trailingActivationPriceType = self.safe_string(params, 'trigger', 'last')
1692
- trailingAmountString = '+' + trailingAmount
1693
1995
  request['trigger'] = trailingActivationPriceType
1694
- if isLimitOrder or (trailingLimitAmount is not None):
1695
- offset = self.safe_string(params, 'offset', '-')
1696
- trailingLimitAmountString = offset + self.number_to_string(trailingLimitAmount)
1697
- request['price'] = trailingAmountString
1698
- request['price2'] = trailingLimitAmountString
1996
+ if isLimitOrder or (trailingLimitAmount is not None) or (trailingLimitPercent is not None):
1699
1997
  request['ordertype'] = 'trailing-stop-limit'
1998
+ if trailingLimitPercent is not None:
1999
+ trailingLimitPercentString = (offset + trailingLimitPercent) if (trailingLimitPercent.endswith('%')) else (offset + trailingLimitPercent + '%')
2000
+ request['price'] = trailingPercentString
2001
+ request['price2'] = trailingLimitPercentString
2002
+ elif trailingLimitAmount is not None:
2003
+ request['price'] = trailingAmountString
2004
+ request['price2'] = trailingLimitAmountString
1700
2005
  else:
1701
- request['price'] = trailingAmountString
1702
2006
  request['ordertype'] = 'trailing-stop'
2007
+ if trailingPercent is not None:
2008
+ request['price'] = trailingPercentString
2009
+ else:
2010
+ request['price'] = trailingAmountString
1703
2011
  if reduceOnly:
1704
2012
  if method == 'createOrderWs':
1705
2013
  request['reduce_only'] = True # ws request can't have stringified bool
@@ -1724,26 +2032,33 @@ class kraken(Exchange, ImplicitAPI):
1724
2032
  if postOnly:
1725
2033
  extendedPostFlags = flags + ',post' if (flags is not None) else 'post'
1726
2034
  request['oflags'] = extendedPostFlags
1727
- params = self.omit(params, ['timeInForce', 'reduceOnly', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingLimitAmount', 'offset'])
2035
+ if (flags is not None) and not ('oflags' in request):
2036
+ request['oflags'] = flags
2037
+ params = self.omit(params, ['timeInForce', 'reduceOnly', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingLimitAmount', 'trailingLimitPercent', 'offset'])
1728
2038
  return [request, params]
1729
2039
 
1730
2040
  async def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
1731
2041
  """
1732
2042
  edit a trade order
1733
- :see: https://docs.kraken.com/rest/#tag/Trading/operation/editOrder
2043
+
2044
+ https://docs.kraken.com/api/docs/rest-api/amend-order
2045
+
1734
2046
  :param str id: order id
1735
2047
  :param str symbol: unified symbol of the market to create an order in
1736
2048
  :param str type: 'market' or 'limit'
1737
2049
  :param str side: 'buy' or 'sell'
1738
- :param float amount: how much of the currency you want to trade in units of the base currency
1739
- :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
2050
+ :param float [amount]: how much of the currency you want to trade in units of the base currency
2051
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1740
2052
  :param dict [params]: extra parameters specific to the exchange API endpoint
1741
- :param float [params.stopLossPrice]: *margin only* the price that a stop loss order is triggered at
1742
- :param float [params.takeProfitPrice]: *margin only* the price that a take profit order is triggered at
1743
- :param str [params.trailingAmount]: *margin only* the quote price away from the current market price
1744
- :param str [params.trailingLimitAmount]: *margin only* the quote amount away from the trailingAmount
1745
- :param str [params.offset]: *margin only* '+' or '-' whether you want the trailingLimitAmount value to be positive or negative, default is negative '-'
1746
- :param str [params.trigger]: *margin only* the activation price type, 'last' or 'index', default is 'last'
2053
+ :param float [params.stopLossPrice]: the price that a stop loss order is triggered at
2054
+ :param float [params.takeProfitPrice]: the price that a take profit order is triggered at
2055
+ :param str [params.trailingAmount]: the quote amount to trail away from the current market price
2056
+ :param str [params.trailingPercent]: the percent to trail away from the current market price
2057
+ :param str [params.trailingLimitAmount]: the quote amount away from the trailingAmount
2058
+ :param str [params.trailingLimitPercent]: the percent away from the trailingAmount
2059
+ :param str [params.offset]: '+' or '-' whether you want the trailingLimitAmount value to be positive or negative
2060
+ :param boolean [params.postOnly]: if True, the order will only be posted to the order book and not executed immediately
2061
+ :param str [params.clientOrderId]: the orders client order id
1747
2062
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1748
2063
  """
1749
2064
  await self.load_markets()
@@ -1752,35 +2067,49 @@ class kraken(Exchange, ImplicitAPI):
1752
2067
  raise NotSupported(self.id + ' editOrder() does not support ' + market['type'] + ' orders, only spot orders are accepted')
1753
2068
  request: dict = {
1754
2069
  'txid': id,
1755
- 'pair': market['id'],
1756
2070
  }
2071
+ clientOrderId = self.safe_string_2(params, 'clientOrderId', 'cl_ord_id')
2072
+ if clientOrderId is not None:
2073
+ request['cl_ord_id'] = clientOrderId
2074
+ params = self.omit(params, ['clientOrderId', 'cl_ord_id'])
2075
+ request = self.omit(request, 'txid')
2076
+ isMarket = (type == 'market')
2077
+ postOnly = None
2078
+ postOnly, params = self.handle_post_only(isMarket, False, params)
2079
+ if postOnly:
2080
+ request['post_only'] = 'true' # not using hasattr(self, boolean) case, because the urlencodedNested transforms it into 'True' string
1757
2081
  if amount is not None:
1758
- request['volume'] = self.amount_to_precision(symbol, amount)
1759
- orderRequest = self.order_request('editOrder', symbol, type, request, amount, price, params)
1760
- response = await self.privatePostEditOrder(self.extend(orderRequest[0], orderRequest[1]))
2082
+ request['order_qty'] = self.amount_to_precision(symbol, amount)
2083
+ if price is not None:
2084
+ request['limit_price'] = self.price_to_precision(symbol, price)
2085
+ allTriggerPrices = self.safe_string_n(params, ['stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingLimitAmount', 'trailingLimitPercent'])
2086
+ if allTriggerPrices is not None:
2087
+ offset = self.safe_string(params, 'offset')
2088
+ params = self.omit(params, ['stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingLimitAmount', 'trailingLimitPercent', 'offset'])
2089
+ if offset is not None:
2090
+ allTriggerPrices = offset + allTriggerPrices
2091
+ request['trigger_price'] = allTriggerPrices
2092
+ else:
2093
+ request['trigger_price'] = self.price_to_precision(symbol, allTriggerPrices)
2094
+ response = await self.privatePostAmendOrder(self.extend(request, params))
1761
2095
  #
1762
2096
  # {
1763
2097
  # "error": [],
1764
2098
  # "result": {
1765
- # "status": "ok",
1766
- # "txid": "OAW2BO-7RWEK-PZY5UO",
1767
- # "originaltxid": "OXL6SS-UPNMC-26WBE7",
1768
- # "volume": "0.00075000",
1769
- # "price": "13500.0",
1770
- # "orders_cancelled": 1,
1771
- # "descr": {
1772
- # "order": "buy 0.00075000 XBTUSDT @ limit 13500.0"
1773
- # }
2099
+ # "amend_id": "TJSMEH-AA67V-YUSQ6O"
1774
2100
  # }
1775
2101
  # }
1776
2102
  #
1777
- data = self.safe_dict(response, 'result', {})
1778
- return self.parse_order(data, market)
2103
+ result = self.safe_dict(response, 'result', {})
2104
+ return self.parse_order(result, market)
1779
2105
 
1780
2106
  async def fetch_order(self, id: str, symbol: Str = None, params={}):
1781
2107
  """
1782
2108
  fetches information on an order made by the user
1783
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getOrdersInfo
2109
+
2110
+ https://docs.kraken.com/rest/#tag/Account-Data/operation/getOrdersInfo
2111
+
2112
+ :param str id: order id
1784
2113
  :param str symbol: not used by kraken fetchOrder
1785
2114
  :param dict [params]: extra parameters specific to the exchange API endpoint
1786
2115
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
@@ -1789,15 +2118,13 @@ class kraken(Exchange, ImplicitAPI):
1789
2118
  clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId')
1790
2119
  request: dict = {
1791
2120
  'trades': True, # whether or not to include trades in output(optional, default False)
1792
- # 'txid': id, # do not comma separate a list of ids - use fetchOrdersByIds instead
2121
+ 'txid': id, # do not comma separate a list of ids - use fetchOrdersByIds instead
1793
2122
  # 'userref': 'optional', # restrict results to given user reference id(optional)
1794
2123
  }
1795
2124
  query = params
1796
2125
  if clientOrderId is not None:
1797
2126
  request['userref'] = clientOrderId
1798
2127
  query = self.omit(params, ['userref', 'clientOrderId'])
1799
- else:
1800
- request['txid'] = id
1801
2128
  response = await self.privatePostQueryOrders(self.extend(request, query))
1802
2129
  #
1803
2130
  # {
@@ -1844,7 +2171,9 @@ class kraken(Exchange, ImplicitAPI):
1844
2171
  async def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1845
2172
  """
1846
2173
  fetch all the trades made from a single order
1847
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradesInfo
2174
+
2175
+ https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradesInfo
2176
+
1848
2177
  :param str id: order id
1849
2178
  :param str symbol: unified market symbol
1850
2179
  :param int [since]: the earliest time in ms to fetch trades for
@@ -1915,8 +2244,11 @@ class kraken(Exchange, ImplicitAPI):
1915
2244
  async def fetch_orders_by_ids(self, ids, symbol: Str = None, params={}):
1916
2245
  """
1917
2246
  fetch orders by the list of order id
1918
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getClosedOrders
1919
- :param str[]|None ids: list of order id
2247
+
2248
+ https://docs.kraken.com/rest/#tag/Account-Data/operation/getClosedOrders
2249
+
2250
+ :param str[] [ids]: list of order id
2251
+ :param str [symbol]: unified ccxt market symbol
1920
2252
  :param dict [params]: extra parameters specific to the kraken api endpoint
1921
2253
  :returns dict[]: a list of `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1922
2254
  """
@@ -1938,11 +2270,15 @@ class kraken(Exchange, ImplicitAPI):
1938
2270
  async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1939
2271
  """
1940
2272
  fetch all trades made by the user
1941
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradeHistory
2273
+
2274
+ https://docs.kraken.com/api/docs/rest-api/get-trade-history
2275
+
1942
2276
  :param str symbol: unified market symbol
1943
2277
  :param int [since]: the earliest time in ms to fetch trades for
1944
2278
  :param int [limit]: the maximum number of trades structures to retrieve
1945
2279
  :param dict [params]: extra parameters specific to the exchange API endpoint
2280
+ :param int [params.until]: timestamp in ms of the latest trade entry
2281
+ :param int [params.end]: timestamp in seconds of the latest trade entry
1946
2282
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1947
2283
  """
1948
2284
  await self.load_markets()
@@ -1955,6 +2291,11 @@ class kraken(Exchange, ImplicitAPI):
1955
2291
  }
1956
2292
  if since is not None:
1957
2293
  request['start'] = self.parse_to_int(since / 1000)
2294
+ until = self.safe_string_n(params, ['until', 'till'])
2295
+ if until is not None:
2296
+ params = self.omit(params, ['until', 'till'])
2297
+ untilDivided = Precise.string_div(until, '1000')
2298
+ request['end'] = self.parse_to_int(Precise.string_add(untilDivided, '1'))
1958
2299
  response = await self.privatePostTradesHistory(self.extend(request, params))
1959
2300
  #
1960
2301
  # {
@@ -1973,7 +2314,10 @@ class kraken(Exchange, ImplicitAPI):
1973
2314
  # "fee": "0.000026",
1974
2315
  # "vol": "16.00000000",
1975
2316
  # "margin": "0.000000",
2317
+ # "leverage": "5",
1976
2318
  # "misc": ""
2319
+ # "trade_id": 68230622,
2320
+ # "maker": False
1977
2321
  # },
1978
2322
  # ...
1979
2323
  # },
@@ -1993,19 +2337,28 @@ class kraken(Exchange, ImplicitAPI):
1993
2337
  async def cancel_order(self, id: str, symbol: Str = None, params={}):
1994
2338
  """
1995
2339
  cancels an open order
1996
- :see: https://docs.kraken.com/rest/#tag/Trading/operation/cancelOrder
2340
+
2341
+ https://docs.kraken.com/api/docs/rest-api/cancel-order
2342
+
1997
2343
  :param str id: order id
1998
- :param str symbol: unified symbol of the market the order was made in
2344
+ :param str [symbol]: unified symbol of the market the order was made in
1999
2345
  :param dict [params]: extra parameters specific to the exchange API endpoint
2000
- :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2346
+ :param str [params.clientOrderId]: the orders client order id
2347
+ :param int [params.userref]: the orders user reference id
2348
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2001
2349
  """
2002
2350
  await self.load_markets()
2003
2351
  response = None
2004
- clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId', id)
2352
+ requestId = self.safe_value(params, 'userref', id) # string or integer
2353
+ params = self.omit(params, 'userref')
2005
2354
  request: dict = {
2006
- 'txid': clientOrderId, # order id or userref
2355
+ 'txid': requestId, # order id or userref
2007
2356
  }
2008
- params = self.omit(params, ['userref', 'clientOrderId'])
2357
+ clientOrderId = self.safe_string_2(params, 'clientOrderId', 'cl_ord_id')
2358
+ if clientOrderId is not None:
2359
+ request['cl_ord_id'] = clientOrderId
2360
+ params = self.omit(params, ['clientOrderId', 'cl_ord_id'])
2361
+ request = self.omit(request, 'txid')
2009
2362
  try:
2010
2363
  response = await self.privatePostCancelOrder(self.extend(request, params))
2011
2364
  #
@@ -2028,7 +2381,9 @@ class kraken(Exchange, ImplicitAPI):
2028
2381
  async def cancel_orders(self, ids, symbol: Str = None, params={}):
2029
2382
  """
2030
2383
  cancel multiple orders
2031
- :see: https://docs.kraken.com/rest/#tag/Trading/operation/cancelOrderBatch
2384
+
2385
+ https://docs.kraken.com/rest/#tag/Spot-Trading/operation/cancelOrderBatch
2386
+
2032
2387
  :param str[] ids: open orders transaction ID(txid) or user reference(userref)
2033
2388
  :param str symbol: unified market symbol
2034
2389
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -2055,7 +2410,9 @@ class kraken(Exchange, ImplicitAPI):
2055
2410
  async def cancel_all_orders(self, symbol: Str = None, params={}):
2056
2411
  """
2057
2412
  cancel all open orders
2058
- :see: https://docs.kraken.com/rest/#tag/Trading/operation/cancelAllOrders
2413
+
2414
+ https://docs.kraken.com/rest/#tag/Spot-Trading/operation/cancelAllOrders
2415
+
2059
2416
  :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
2060
2417
  :param dict [params]: extra parameters specific to the exchange API endpoint
2061
2418
  :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
@@ -2079,13 +2436,15 @@ class kraken(Exchange, ImplicitAPI):
2079
2436
  async def cancel_all_orders_after(self, timeout: Int, params={}):
2080
2437
  """
2081
2438
  dead man's switch, cancel all orders after the given timeout
2082
- :see: https://docs.kraken.com/rest/#tag/Spot-Trading/operation/cancelAllOrdersAfter
2439
+
2440
+ https://docs.kraken.com/rest/#tag/Spot-Trading/operation/cancelAllOrdersAfter
2441
+
2083
2442
  :param number timeout: time in milliseconds, 0 represents cancel the timer
2084
2443
  :param dict [params]: extra parameters specific to the exchange API endpoint
2085
2444
  :returns dict: the api result
2086
2445
  """
2087
2446
  if timeout > 86400000:
2088
- raise BadRequest(self.id + 'cancelAllOrdersAfter timeout should be less than 86400000 milliseconds')
2447
+ raise BadRequest(self.id + ' cancelAllOrdersAfter timeout should be less than 86400000 milliseconds')
2089
2448
  await self.load_markets()
2090
2449
  request: dict = {
2091
2450
  'timeout': (self.parse_to_int(timeout / 1000)) if (timeout > 0) else 0,
@@ -2105,52 +2464,109 @@ class kraken(Exchange, ImplicitAPI):
2105
2464
  async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2106
2465
  """
2107
2466
  fetch all unfilled currently open orders
2108
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getOpenOrders
2109
- :param str symbol: unified market symbol
2467
+
2468
+ https://docs.kraken.com/api/docs/rest-api/get-open-orders
2469
+
2470
+ :param str [symbol]: unified market symbol
2110
2471
  :param int [since]: the earliest time in ms to fetch open orders for
2111
2472
  :param int [limit]: the maximum number of open orders structures to retrieve
2112
2473
  :param dict [params]: extra parameters specific to the exchange API endpoint
2474
+ :param str [params.clientOrderId]: the orders client order id
2475
+ :param int [params.userref]: the orders user reference id
2113
2476
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2114
2477
  """
2115
2478
  await self.load_markets()
2116
2479
  request: dict = {}
2117
2480
  if since is not None:
2118
2481
  request['start'] = self.parse_to_int(since / 1000)
2119
- query = params
2120
- clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId')
2482
+ userref = self.safe_integer(params, 'userref')
2483
+ if userref is not None:
2484
+ request['userref'] = userref
2485
+ params = self.omit(params, 'userref')
2486
+ clientOrderId = self.safe_string(params, 'clientOrderId')
2121
2487
  if clientOrderId is not None:
2122
- request['userref'] = clientOrderId
2123
- query = self.omit(params, ['userref', 'clientOrderId'])
2124
- response = await self.privatePostOpenOrders(self.extend(request, query))
2488
+ request['cl_ord_id'] = clientOrderId
2489
+ params = self.omit(params, 'clientOrderId')
2490
+ response = await self.privatePostOpenOrders(self.extend(request, params))
2491
+ #
2492
+ # {
2493
+ # "error": [],
2494
+ # "result": {
2495
+ # "open": {
2496
+ # "O45M52-BFD5S-YXKQOU": {
2497
+ # "refid": null,
2498
+ # "userref": null,
2499
+ # "cl_ord_id": "1234",
2500
+ # "status": "open",
2501
+ # "opentm": 1733815269.370054,
2502
+ # "starttm": 0,
2503
+ # "expiretm": 0,
2504
+ # "descr": {
2505
+ # "pair": "XBTUSD",
2506
+ # "type": "buy",
2507
+ # "ordertype": "limit",
2508
+ # "price": "70000.0",
2509
+ # "price2": "0",
2510
+ # "leverage": "none",
2511
+ # "order": "buy 0.00010000 XBTUSD @ limit 70000.0",
2512
+ # "close": ""
2513
+ # },
2514
+ # "vol": "0.00010000",
2515
+ # "vol_exec": "0.00000000",
2516
+ # "cost": "0.00000",
2517
+ # "fee": "0.00000",
2518
+ # "price": "0.00000",
2519
+ # "stopprice": "0.00000",
2520
+ # "limitprice": "0.00000",
2521
+ # "misc": "",
2522
+ # "oflags": "fciq"
2523
+ # }
2524
+ # }
2525
+ # }
2526
+ # }
2527
+ #
2125
2528
  market = None
2126
2529
  if symbol is not None:
2127
2530
  market = self.market(symbol)
2128
2531
  result = self.safe_dict(response, 'result', {})
2129
- orders = self.safe_dict(result, 'open', {})
2532
+ open = self.safe_dict(result, 'open', {})
2533
+ orders = []
2534
+ orderIds = list(open.keys())
2535
+ for i in range(0, len(orderIds)):
2536
+ id = orderIds[i]
2537
+ item = open[id]
2538
+ orders.append(self.extend({'id': id}, item))
2130
2539
  return self.parse_orders(orders, market, since, limit)
2131
2540
 
2132
2541
  async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2133
2542
  """
2134
2543
  fetches information on multiple closed orders made by the user
2135
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getClosedOrders
2136
- :param str symbol: unified market symbol of the market orders were made in
2544
+
2545
+ https://docs.kraken.com/api/docs/rest-api/get-closed-orders
2546
+
2547
+ :param str [symbol]: unified market symbol of the market orders were made in
2137
2548
  :param int [since]: the earliest time in ms to fetch orders for
2138
2549
  :param int [limit]: the maximum number of order structures to retrieve
2139
2550
  :param dict [params]: extra parameters specific to the exchange API endpoint
2140
2551
  :param int [params.until]: timestamp in ms of the latest entry
2552
+ :param str [params.clientOrderId]: the orders client order id
2553
+ :param int [params.userref]: the orders user reference id
2141
2554
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2142
2555
  """
2143
2556
  await self.load_markets()
2144
2557
  request: dict = {}
2145
2558
  if since is not None:
2146
2559
  request['start'] = self.parse_to_int(since / 1000)
2147
- query = params
2148
- clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId')
2560
+ userref = self.safe_integer(params, 'userref')
2561
+ if userref is not None:
2562
+ request['userref'] = userref
2563
+ params = self.omit(params, 'userref')
2564
+ clientOrderId = self.safe_string(params, 'clientOrderId')
2149
2565
  if clientOrderId is not None:
2150
- request['userref'] = clientOrderId
2151
- query = self.omit(params, ['userref', 'clientOrderId'])
2566
+ request['cl_ord_id'] = clientOrderId
2567
+ params = self.omit(params, 'clientOrderId')
2152
2568
  request, params = self.handle_until_option('end', request, params)
2153
- response = await self.privatePostClosedOrders(self.extend(request, query))
2569
+ response = await self.privatePostClosedOrders(self.extend(request, params))
2154
2570
  #
2155
2571
  # {
2156
2572
  # "error":[],
@@ -2194,7 +2610,13 @@ class kraken(Exchange, ImplicitAPI):
2194
2610
  if symbol is not None:
2195
2611
  market = self.market(symbol)
2196
2612
  result = self.safe_dict(response, 'result', {})
2197
- orders = self.safe_dict(result, 'closed', {})
2613
+ closed = self.safe_dict(result, 'closed', {})
2614
+ orders = []
2615
+ orderIds = list(closed.keys())
2616
+ for i in range(0, len(orderIds)):
2617
+ id = orderIds[i]
2618
+ item = closed[id]
2619
+ orders.append(self.extend({'id': id}, item))
2198
2620
  return self.parse_orders(orders, market, since, limit)
2199
2621
 
2200
2622
  def parse_transaction_status(self, status: Str):
@@ -2331,23 +2753,31 @@ class kraken(Exchange, ImplicitAPI):
2331
2753
  async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2332
2754
  """
2333
2755
  fetch all deposits made to an account
2334
- :see: https://docs.kraken.com/rest/#tag/Funding/operation/getStatusRecentDeposits
2756
+
2757
+ https://docs.kraken.com/rest/#tag/Funding/operation/getStatusRecentDeposits
2758
+
2335
2759
  :param str code: unified currency code
2336
2760
  :param int [since]: the earliest time in ms to fetch deposits for
2337
2761
  :param int [limit]: the maximum number of deposits structures to retrieve
2338
2762
  :param dict [params]: extra parameters specific to the exchange API endpoint
2763
+ :param int [params.until]: timestamp in ms of the latest transaction entry
2764
+ :param int [params.end]: timestamp in seconds of the latest transaction entry
2339
2765
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2340
2766
  """
2341
2767
  # https://www.kraken.com/en-us/help/api#deposit-status
2342
- if code is None:
2343
- raise ArgumentsRequired(self.id + ' fetchDeposits() requires a currency code argument')
2344
2768
  await self.load_markets()
2345
- currency = self.currency(code)
2346
- request: dict = {
2347
- 'asset': currency['id'],
2348
- }
2769
+ request: dict = {}
2770
+ if code is not None:
2771
+ currency = self.currency(code)
2772
+ request['asset'] = currency['id']
2349
2773
  if since is not None:
2350
- request['start'] = since
2774
+ sinceString = self.number_to_string(since)
2775
+ request['start'] = Precise.string_div(sinceString, '1000')
2776
+ until = self.safe_string_n(params, ['until', 'till'])
2777
+ if until is not None:
2778
+ params = self.omit(params, ['until', 'till'])
2779
+ untilDivided = Precise.string_div(until, '1000')
2780
+ request['end'] = Precise.string_add(untilDivided, '1')
2351
2781
  response = await self.privatePostDepositStatus(self.extend(request, params))
2352
2782
  #
2353
2783
  # { error: [],
@@ -2364,10 +2794,12 @@ class kraken(Exchange, ImplicitAPI):
2364
2794
  #
2365
2795
  return self.parse_transactions_by_type('deposit', response['result'], code, since, limit)
2366
2796
 
2367
- async def fetch_time(self, params={}):
2797
+ async def fetch_time(self, params={}) -> Int:
2368
2798
  """
2369
2799
  fetches the current integer timestamp in milliseconds from the exchange server
2370
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getServerTime
2800
+
2801
+ https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getServerTime
2802
+
2371
2803
  :param dict [params]: extra parameters specific to the exchange API endpoint
2372
2804
  :returns int: the current integer timestamp in milliseconds from the exchange server
2373
2805
  """
@@ -2388,13 +2820,16 @@ class kraken(Exchange, ImplicitAPI):
2388
2820
  async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2389
2821
  """
2390
2822
  fetch all withdrawals made from an account
2391
- :see: https://docs.kraken.com/rest/#tag/Funding/operation/getStatusRecentWithdrawals
2823
+
2824
+ https://docs.kraken.com/rest/#tag/Funding/operation/getStatusRecentWithdrawals
2825
+
2392
2826
  :param str code: unified currency code
2393
2827
  :param int [since]: the earliest time in ms to fetch withdrawals for
2394
2828
  :param int [limit]: the maximum number of withdrawals structures to retrieve
2395
2829
  :param dict [params]: extra parameters specific to the exchange API endpoint
2396
- :param dict [params.end]: End timestamp, withdrawals created strictly after will be not be included in the response
2397
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times
2830
+ :param int [params.until]: timestamp in ms of the latest transaction entry
2831
+ :param int [params.end]: timestamp in seconds of the latest transaction entry
2832
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times
2398
2833
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2399
2834
  """
2400
2835
  await self.load_markets()
@@ -2408,7 +2843,13 @@ class kraken(Exchange, ImplicitAPI):
2408
2843
  currency = self.currency(code)
2409
2844
  request['asset'] = currency['id']
2410
2845
  if since is not None:
2411
- request['since'] = str(since)
2846
+ sinceString = self.number_to_string(since)
2847
+ request['start'] = Precise.string_div(sinceString, '1000')
2848
+ until = self.safe_string_n(params, ['until', 'till'])
2849
+ if until is not None:
2850
+ params = self.omit(params, ['until', 'till'])
2851
+ untilDivided = Precise.string_div(until, '1000')
2852
+ request['end'] = Precise.string_add(untilDivided, '1')
2412
2853
  response = await self.privatePostWithdrawStatus(self.extend(request, params))
2413
2854
  #
2414
2855
  # with no pagination
@@ -2466,10 +2907,12 @@ class kraken(Exchange, ImplicitAPI):
2466
2907
  data[dataLength - 1] = last
2467
2908
  return data
2468
2909
 
2469
- async def create_deposit_address(self, code: str, params={}):
2910
+ async def create_deposit_address(self, code: str, params={}) -> DepositAddress:
2470
2911
  """
2471
2912
  create a currency deposit address
2472
- :see: https://docs.kraken.com/rest/#tag/Funding/operation/getDepositAddresses
2913
+
2914
+ https://docs.kraken.com/rest/#tag/Funding/operation/getDepositAddresses
2915
+
2473
2916
  :param str code: unified currency code of the currency for the deposit address
2474
2917
  :param dict [params]: extra parameters specific to the exchange API endpoint
2475
2918
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
@@ -2482,7 +2925,9 @@ class kraken(Exchange, ImplicitAPI):
2482
2925
  async def fetch_deposit_methods(self, code: str, params={}):
2483
2926
  """
2484
2927
  fetch deposit methods for a currency associated with self account
2485
- :see: https://docs.kraken.com/rest/#tag/Funding/operation/getDepositMethods
2928
+
2929
+ https://docs.kraken.com/rest/#tag/Funding/operation/getDepositMethods
2930
+
2486
2931
  :param str code: unified currency code
2487
2932
  :param dict [params]: extra parameters specific to the kraken api endpoint
2488
2933
  :returns dict: of deposit methods
@@ -2518,10 +2963,12 @@ class kraken(Exchange, ImplicitAPI):
2518
2963
  #
2519
2964
  return self.safe_value(response, 'result')
2520
2965
 
2521
- async def fetch_deposit_address(self, code: str, params={}):
2966
+ async def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
2522
2967
  """
2523
2968
  fetch the deposit address for a currency associated with self account
2524
- :see: https://docs.kraken.com/rest/#tag/Funding/operation/getDepositAddresses
2969
+
2970
+ https://docs.kraken.com/rest/#tag/Funding/operation/getDepositAddresses
2971
+
2525
2972
  :param str code: unified currency code
2526
2973
  :param dict [params]: extra parameters specific to the exchange API endpoint
2527
2974
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
@@ -2571,7 +3018,7 @@ class kraken(Exchange, ImplicitAPI):
2571
3018
  raise InvalidAddress(self.id + ' privatePostDepositAddresses() returned no addresses for ' + code)
2572
3019
  return self.parse_deposit_address(firstResult, currency)
2573
3020
 
2574
- def parse_deposit_address(self, depositAddress, currency: Currency = None):
3021
+ def parse_deposit_address(self, depositAddress, currency: Currency = None) -> DepositAddress:
2575
3022
  #
2576
3023
  # {
2577
3024
  # "address":"0x77b5051f97efa9cc52c9ad5b023a53fc15c200d3",
@@ -2584,17 +3031,19 @@ class kraken(Exchange, ImplicitAPI):
2584
3031
  code = currency['code']
2585
3032
  self.check_address(address)
2586
3033
  return {
3034
+ 'info': depositAddress,
2587
3035
  'currency': code,
3036
+ 'network': None,
2588
3037
  'address': address,
2589
3038
  'tag': tag,
2590
- 'network': None,
2591
- 'info': depositAddress,
2592
3039
  }
2593
3040
 
2594
- async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
3041
+ async def withdraw(self, code: str, amount: float, address: str, tag: Str = None, params={}) -> Transaction:
2595
3042
  """
2596
3043
  make a withdrawal
2597
- :see: https://docs.kraken.com/rest/#tag/Funding/operation/withdrawFunds
3044
+
3045
+ https://docs.kraken.com/rest/#tag/Funding/operation/withdrawFunds
3046
+
2598
3047
  :param str code: unified currency code
2599
3048
  :param float amount: the amount to withdraw
2600
3049
  :param str address: the address to withdraw to
@@ -2625,10 +3074,12 @@ class kraken(Exchange, ImplicitAPI):
2625
3074
  return self.parse_transaction(result, currency)
2626
3075
  raise ExchangeError(self.id + " withdraw() requires a 'key' parameter(withdrawal key name, up on your account)")
2627
3076
 
2628
- async def fetch_positions(self, symbols: Strings = None, params={}):
3077
+ async def fetch_positions(self, symbols: Strings = None, params={}) -> List[Position]:
2629
3078
  """
2630
3079
  fetch all open positions
2631
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getOpenPositions
3080
+
3081
+ https://docs.kraken.com/rest/#tag/Account-Data/operation/getOpenPositions
3082
+
2632
3083
  :param str[] [symbols]: not used by kraken fetchPositions()
2633
3084
  :param dict [params]: extra parameters specific to the exchange API endpoint
2634
3085
  :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
@@ -2749,7 +3200,9 @@ class kraken(Exchange, ImplicitAPI):
2749
3200
  async def transfer_out(self, code: str, amount, params={}):
2750
3201
  """
2751
3202
  transfer from spot wallet to futures wallet
2752
- :see: https://docs.kraken.com/rest/#tag/User-Funding/operation/walletTransfer
3203
+
3204
+ https://docs.kraken.com/rest/#tag/User-Funding/operation/walletTransfer
3205
+
2753
3206
  :param str code: Unified currency code
2754
3207
  :param float amount: Size of the transfer
2755
3208
  :param dict [params]: Exchange specific parameters
@@ -2759,7 +3212,9 @@ class kraken(Exchange, ImplicitAPI):
2759
3212
 
2760
3213
  async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
2761
3214
  """
2762
- :see: https://docs.kraken.com/rest/#tag/User-Funding/operation/walletTransfer
3215
+
3216
+ https://docs.kraken.com/rest/#tag/User-Funding/operation/walletTransfer
3217
+
2763
3218
  transfers currencies between sub-accounts(only spot->swap direction is supported)
2764
3219
  :param str code: Unified currency code
2765
3220
  :param float amount: Size of the transfer
@@ -2830,11 +3285,15 @@ class kraken(Exchange, ImplicitAPI):
2830
3285
  # urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
2831
3286
  url += '?' + self.urlencode_nested(params)
2832
3287
  elif api == 'private':
3288
+ price = self.safe_string(params, 'price')
3289
+ isTriggerPercent = False
3290
+ if price is not None:
3291
+ isTriggerPercent = True if (price.endswith('%')) else False
2833
3292
  isCancelOrderBatch = (path == 'CancelOrderBatch')
2834
3293
  self.check_required_credentials()
2835
3294
  nonce = str(self.nonce())
2836
3295
  # urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
2837
- if isCancelOrderBatch:
3296
+ if isCancelOrderBatch or isTriggerPercent:
2838
3297
  body = self.json(self.extend({'nonce': nonce}, params))
2839
3298
  else:
2840
3299
  body = self.urlencode_nested(self.extend({'nonce': nonce}, params))
@@ -2847,9 +3306,8 @@ class kraken(Exchange, ImplicitAPI):
2847
3306
  headers = {
2848
3307
  'API-Key': self.apiKey,
2849
3308
  'API-Sign': signature,
2850
- # 'Content-Type': 'application/x-www-form-urlencoded',
2851
3309
  }
2852
- if isCancelOrderBatch:
3310
+ if isCancelOrderBatch or isTriggerPercent:
2853
3311
  headers['Content-Type'] = 'application/json'
2854
3312
  else:
2855
3313
  headers['Content-Type'] = 'application/x-www-form-urlencoded'
@@ -2859,26 +3317,11 @@ class kraken(Exchange, ImplicitAPI):
2859
3317
  return {'url': url, 'method': method, 'body': body, 'headers': headers}
2860
3318
 
2861
3319
  def nonce(self):
2862
- return self.milliseconds()
3320
+ return self.milliseconds() - self.options['timeDifference']
2863
3321
 
2864
3322
  def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
2865
3323
  if code == 520:
2866
3324
  raise ExchangeNotAvailable(self.id + ' ' + str(code) + ' ' + reason)
2867
- # todo: rewrite self for "broad" exceptions matching
2868
- if body.find('Invalid order') >= 0:
2869
- raise InvalidOrder(self.id + ' ' + body)
2870
- if body.find('Invalid nonce') >= 0:
2871
- raise InvalidNonce(self.id + ' ' + body)
2872
- if body.find('Insufficient funds') >= 0:
2873
- raise InsufficientFunds(self.id + ' ' + body)
2874
- if body.find('Cancel pending') >= 0:
2875
- raise CancelPending(self.id + ' ' + body)
2876
- if body.find('Invalid arguments:volume') >= 0:
2877
- raise InvalidOrder(self.id + ' ' + body)
2878
- if body.find('Invalid arguments:viqc') >= 0:
2879
- raise InvalidOrder(self.id + ' ' + body)
2880
- if body.find('Rate limit exceeded') >= 0:
2881
- raise RateLimitExceeded(self.id + ' ' + body)
2882
3325
  if response is None:
2883
3326
  return None
2884
3327
  if body[0] == '{':
@@ -2889,6 +3332,7 @@ class kraken(Exchange, ImplicitAPI):
2889
3332
  message = self.id + ' ' + body
2890
3333
  for i in range(0, len(response['error'])):
2891
3334
  error = response['error'][i]
2892
- self.throw_exactly_matched_exception(self.exceptions, error, message)
3335
+ self.throw_exactly_matched_exception(self.exceptions['exact'], error, message)
3336
+ self.throw_broadly_matched_exception(self.exceptions['broad'], error, message)
2893
3337
  raise ExchangeError(message)
2894
3338
  return None