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

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