ccxt 4.2.77__py2.py3-none-any.whl → 4.4.49__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 (546) hide show
  1. ccxt/__init__.py +36 -14
  2. ccxt/abstract/alpaca.py +4 -0
  3. ccxt/abstract/bigone.py +1 -1
  4. ccxt/abstract/binance.py +112 -48
  5. ccxt/abstract/binancecoinm.py +112 -48
  6. ccxt/abstract/binanceus.py +147 -83
  7. ccxt/abstract/binanceusdm.py +112 -48
  8. ccxt/abstract/bingx.py +133 -78
  9. ccxt/abstract/bitbank.py +5 -0
  10. ccxt/abstract/bitfinex.py +136 -65
  11. ccxt/abstract/bitfinex1.py +69 -0
  12. ccxt/abstract/bitflyer.py +1 -0
  13. ccxt/abstract/bitget.py +8 -1
  14. ccxt/abstract/bitmart.py +13 -1
  15. ccxt/abstract/bitopro.py +1 -0
  16. ccxt/abstract/bitpanda.py +0 -12
  17. ccxt/abstract/bitrue.py +3 -3
  18. ccxt/abstract/bitstamp.py +26 -3
  19. ccxt/abstract/blofin.py +24 -0
  20. ccxt/abstract/btcbox.py +1 -0
  21. ccxt/abstract/bybit.py +29 -14
  22. ccxt/abstract/cex.py +28 -29
  23. ccxt/abstract/coinbase.py +6 -0
  24. ccxt/abstract/coinbaseadvanced.py +94 -0
  25. ccxt/abstract/{coinbasepro.py → coinbaseexchange.py} +1 -0
  26. ccxt/abstract/coinbaseinternational.py +1 -1
  27. ccxt/abstract/coincatch.py +94 -0
  28. ccxt/abstract/coinex.py +233 -123
  29. ccxt/abstract/coinmetro.py +1 -0
  30. ccxt/abstract/cryptocom.py +14 -0
  31. ccxt/abstract/defx.py +69 -0
  32. ccxt/abstract/deribit.py +1 -0
  33. ccxt/abstract/digifinex.py +1 -0
  34. ccxt/abstract/ellipx.py +25 -0
  35. ccxt/abstract/gate.py +20 -0
  36. ccxt/abstract/gateio.py +20 -0
  37. ccxt/abstract/gemini.py +1 -0
  38. ccxt/abstract/hashkey.py +67 -0
  39. ccxt/abstract/hyperliquid.py +1 -1
  40. ccxt/abstract/independentreserve.py +6 -0
  41. ccxt/abstract/kraken.py +4 -3
  42. ccxt/abstract/krakenfutures.py +4 -0
  43. ccxt/abstract/kucoin.py +24 -0
  44. ccxt/abstract/kucoinfutures.py +34 -0
  45. ccxt/abstract/luno.py +2 -0
  46. ccxt/abstract/mexc.py +4 -0
  47. ccxt/abstract/myokx.py +340 -0
  48. ccxt/abstract/oceanex.py +5 -0
  49. ccxt/abstract/okx.py +30 -0
  50. ccxt/abstract/onetrading.py +0 -12
  51. ccxt/abstract/oxfun.py +34 -0
  52. ccxt/abstract/paradex.py +40 -0
  53. ccxt/abstract/phemex.py +1 -0
  54. ccxt/abstract/upbit.py +4 -0
  55. ccxt/abstract/vertex.py +19 -0
  56. ccxt/abstract/whitebit.py +31 -1
  57. ccxt/abstract/woo.py +6 -2
  58. ccxt/abstract/woofipro.py +119 -0
  59. ccxt/abstract/xt.py +153 -0
  60. ccxt/abstract/zonda.py +6 -0
  61. ccxt/ace.py +164 -60
  62. ccxt/alpaca.py +727 -63
  63. ccxt/ascendex.py +395 -249
  64. ccxt/async_support/__init__.py +36 -14
  65. ccxt/async_support/ace.py +164 -60
  66. ccxt/async_support/alpaca.py +727 -63
  67. ccxt/async_support/ascendex.py +396 -249
  68. ccxt/async_support/base/exchange.py +531 -155
  69. ccxt/async_support/base/ws/aiohttp_client.py +28 -5
  70. ccxt/async_support/base/ws/cache.py +3 -2
  71. ccxt/async_support/base/ws/client.py +26 -5
  72. ccxt/async_support/base/ws/fast_client.py +4 -3
  73. ccxt/async_support/base/ws/functions.py +1 -1
  74. ccxt/async_support/base/ws/future.py +40 -31
  75. ccxt/async_support/base/ws/order_book_side.py +3 -0
  76. ccxt/async_support/bequant.py +1 -1
  77. ccxt/async_support/bigone.py +329 -202
  78. ccxt/async_support/binance.py +3030 -1087
  79. ccxt/async_support/binancecoinm.py +2 -1
  80. ccxt/async_support/binanceus.py +12 -1
  81. ccxt/async_support/binanceusdm.py +3 -1
  82. ccxt/async_support/bingx.py +3205 -937
  83. ccxt/async_support/bit2c.py +119 -38
  84. ccxt/async_support/bitbank.py +215 -76
  85. ccxt/async_support/bitbns.py +124 -53
  86. ccxt/async_support/bitfinex.py +3236 -1078
  87. ccxt/async_support/bitfinex1.py +1711 -0
  88. ccxt/async_support/bitflyer.py +238 -49
  89. ccxt/async_support/bitget.py +1525 -573
  90. ccxt/async_support/bithumb.py +199 -65
  91. ccxt/async_support/bitmart.py +1320 -435
  92. ccxt/async_support/bitmex.py +308 -111
  93. ccxt/async_support/bitopro.py +256 -96
  94. ccxt/async_support/bitrue.py +365 -233
  95. ccxt/async_support/bitso.py +201 -89
  96. ccxt/async_support/bitstamp.py +438 -269
  97. ccxt/async_support/bitteam.py +179 -73
  98. ccxt/async_support/bitvavo.py +180 -70
  99. ccxt/async_support/bl3p.py +92 -25
  100. ccxt/async_support/blockchaincom.py +193 -79
  101. ccxt/async_support/blofin.py +392 -148
  102. ccxt/async_support/btcalpha.py +161 -55
  103. ccxt/async_support/btcbox.py +250 -34
  104. ccxt/async_support/btcmarkets.py +232 -85
  105. ccxt/async_support/btcturk.py +159 -60
  106. ccxt/async_support/bybit.py +2231 -1193
  107. ccxt/async_support/cex.py +1409 -1329
  108. ccxt/async_support/coinbase.py +1454 -287
  109. ccxt/async_support/coinbaseadvanced.py +17 -0
  110. ccxt/async_support/{coinbasepro.py → coinbaseexchange.py} +233 -99
  111. ccxt/async_support/coinbaseinternational.py +428 -88
  112. ccxt/async_support/coincatch.py +5152 -0
  113. ccxt/async_support/coincheck.py +121 -38
  114. ccxt/async_support/coinex.py +4020 -3339
  115. ccxt/async_support/coinlist.py +273 -116
  116. ccxt/async_support/coinmate.py +204 -97
  117. ccxt/async_support/coinmetro.py +203 -110
  118. ccxt/async_support/coinone.py +142 -68
  119. ccxt/async_support/coinsph.py +223 -97
  120. ccxt/async_support/coinspot.py +137 -62
  121. ccxt/async_support/cryptocom.py +515 -185
  122. ccxt/async_support/currencycom.py +203 -85
  123. ccxt/async_support/defx.py +2066 -0
  124. ccxt/async_support/delta.py +404 -109
  125. ccxt/async_support/deribit.py +639 -323
  126. ccxt/async_support/digifinex.py +465 -233
  127. ccxt/async_support/ellipx.py +1887 -0
  128. ccxt/async_support/exmo.py +317 -128
  129. ccxt/async_support/gate.py +1472 -463
  130. ccxt/async_support/gemini.py +206 -84
  131. ccxt/async_support/hashkey.py +4164 -0
  132. ccxt/async_support/hitbtc.py +433 -178
  133. ccxt/async_support/hollaex.py +207 -83
  134. ccxt/async_support/htx.py +1095 -563
  135. ccxt/async_support/huobijp.py +178 -56
  136. ccxt/async_support/hyperliquid.py +1678 -292
  137. ccxt/async_support/idex.py +219 -95
  138. ccxt/async_support/independentreserve.py +300 -31
  139. ccxt/async_support/indodax.py +226 -62
  140. ccxt/async_support/kraken.py +871 -354
  141. ccxt/async_support/krakenfutures.py +324 -100
  142. ccxt/async_support/kucoin.py +917 -357
  143. ccxt/async_support/kucoinfutures.py +1004 -149
  144. ccxt/async_support/kuna.py +198 -107
  145. ccxt/async_support/latoken.py +199 -79
  146. ccxt/async_support/lbank.py +360 -113
  147. ccxt/async_support/luno.py +185 -62
  148. ccxt/async_support/lykke.py +168 -55
  149. ccxt/async_support/mercado.py +101 -29
  150. ccxt/async_support/mexc.py +995 -429
  151. ccxt/async_support/myokx.py +53 -0
  152. ccxt/async_support/ndax.py +234 -82
  153. ccxt/async_support/novadax.py +195 -75
  154. ccxt/async_support/oceanex.py +244 -59
  155. ccxt/async_support/okcoin.py +301 -165
  156. ccxt/async_support/okx.py +1776 -454
  157. ccxt/async_support/onetrading.py +198 -414
  158. ccxt/async_support/oxfun.py +2898 -0
  159. ccxt/async_support/p2b.py +142 -52
  160. ccxt/async_support/paradex.py +2085 -0
  161. ccxt/async_support/paymium.py +56 -32
  162. ccxt/async_support/phemex.py +572 -196
  163. ccxt/async_support/poloniex.py +218 -95
  164. ccxt/async_support/poloniexfutures.py +260 -92
  165. ccxt/async_support/probit.py +143 -110
  166. ccxt/async_support/timex.py +123 -70
  167. ccxt/async_support/tokocrypto.py +129 -93
  168. ccxt/async_support/tradeogre.py +39 -25
  169. ccxt/async_support/upbit.py +322 -113
  170. ccxt/async_support/vertex.py +2983 -0
  171. ccxt/async_support/wavesexchange.py +227 -173
  172. ccxt/async_support/wazirx.py +145 -65
  173. ccxt/async_support/whitebit.py +533 -138
  174. ccxt/async_support/woo.py +1137 -296
  175. ccxt/async_support/woofipro.py +2716 -0
  176. ccxt/async_support/xt.py +4628 -0
  177. ccxt/async_support/yobit.py +160 -92
  178. ccxt/async_support/zaif.py +80 -33
  179. ccxt/async_support/zonda.py +140 -69
  180. ccxt/base/errors.py +51 -20
  181. ccxt/base/exchange.py +1722 -480
  182. ccxt/base/precise.py +10 -0
  183. ccxt/base/types.py +223 -4
  184. ccxt/bequant.py +1 -1
  185. ccxt/bigone.py +329 -202
  186. ccxt/binance.py +3030 -1087
  187. ccxt/binancecoinm.py +2 -1
  188. ccxt/binanceus.py +12 -1
  189. ccxt/binanceusdm.py +3 -1
  190. ccxt/bingx.py +3205 -937
  191. ccxt/bit2c.py +119 -38
  192. ccxt/bitbank.py +215 -76
  193. ccxt/bitbns.py +124 -53
  194. ccxt/bitfinex.py +3235 -1078
  195. ccxt/bitfinex1.py +1710 -0
  196. ccxt/bitflyer.py +238 -49
  197. ccxt/bitget.py +1525 -573
  198. ccxt/bithumb.py +198 -65
  199. ccxt/bitmart.py +1320 -435
  200. ccxt/bitmex.py +308 -111
  201. ccxt/bitopro.py +256 -96
  202. ccxt/bitrue.py +365 -233
  203. ccxt/bitso.py +201 -89
  204. ccxt/bitstamp.py +438 -269
  205. ccxt/bitteam.py +179 -73
  206. ccxt/bitvavo.py +180 -70
  207. ccxt/bl3p.py +92 -25
  208. ccxt/blockchaincom.py +193 -79
  209. ccxt/blofin.py +392 -148
  210. ccxt/btcalpha.py +161 -55
  211. ccxt/btcbox.py +250 -34
  212. ccxt/btcmarkets.py +232 -85
  213. ccxt/btcturk.py +159 -60
  214. ccxt/bybit.py +2231 -1193
  215. ccxt/cex.py +1408 -1329
  216. ccxt/coinbase.py +1454 -287
  217. ccxt/coinbaseadvanced.py +17 -0
  218. ccxt/{coinbasepro.py → coinbaseexchange.py} +233 -99
  219. ccxt/coinbaseinternational.py +428 -88
  220. ccxt/coincatch.py +5152 -0
  221. ccxt/coincheck.py +121 -38
  222. ccxt/coinex.py +4020 -3339
  223. ccxt/coinlist.py +273 -116
  224. ccxt/coinmate.py +204 -97
  225. ccxt/coinmetro.py +203 -110
  226. ccxt/coinone.py +142 -68
  227. ccxt/coinsph.py +223 -97
  228. ccxt/coinspot.py +137 -62
  229. ccxt/cryptocom.py +515 -185
  230. ccxt/currencycom.py +203 -85
  231. ccxt/defx.py +2065 -0
  232. ccxt/delta.py +404 -109
  233. ccxt/deribit.py +639 -323
  234. ccxt/digifinex.py +465 -233
  235. ccxt/ellipx.py +1887 -0
  236. ccxt/exmo.py +317 -128
  237. ccxt/gate.py +1472 -463
  238. ccxt/gemini.py +206 -84
  239. ccxt/hashkey.py +4164 -0
  240. ccxt/hitbtc.py +433 -178
  241. ccxt/hollaex.py +207 -83
  242. ccxt/htx.py +1095 -563
  243. ccxt/huobijp.py +178 -56
  244. ccxt/hyperliquid.py +1677 -292
  245. ccxt/idex.py +219 -95
  246. ccxt/independentreserve.py +299 -31
  247. ccxt/indodax.py +226 -62
  248. ccxt/kraken.py +871 -354
  249. ccxt/krakenfutures.py +324 -100
  250. ccxt/kucoin.py +917 -357
  251. ccxt/kucoinfutures.py +1004 -149
  252. ccxt/kuna.py +198 -107
  253. ccxt/latoken.py +199 -79
  254. ccxt/lbank.py +360 -113
  255. ccxt/luno.py +185 -62
  256. ccxt/lykke.py +168 -55
  257. ccxt/mercado.py +101 -29
  258. ccxt/mexc.py +994 -429
  259. ccxt/myokx.py +53 -0
  260. ccxt/ndax.py +234 -82
  261. ccxt/novadax.py +195 -75
  262. ccxt/oceanex.py +244 -59
  263. ccxt/okcoin.py +301 -165
  264. ccxt/okx.py +1776 -454
  265. ccxt/onetrading.py +198 -414
  266. ccxt/oxfun.py +2897 -0
  267. ccxt/p2b.py +142 -52
  268. ccxt/paradex.py +2085 -0
  269. ccxt/paymium.py +56 -32
  270. ccxt/phemex.py +572 -196
  271. ccxt/poloniex.py +218 -95
  272. ccxt/poloniexfutures.py +260 -92
  273. ccxt/pro/__init__.py +29 -5
  274. ccxt/pro/alpaca.py +32 -17
  275. ccxt/pro/ascendex.py +62 -14
  276. ccxt/pro/bequant.py +4 -0
  277. ccxt/pro/binance.py +1596 -329
  278. ccxt/pro/binancecoinm.py +1 -0
  279. ccxt/pro/binanceus.py +2 -9
  280. ccxt/pro/binanceusdm.py +2 -0
  281. ccxt/pro/bingx.py +527 -134
  282. ccxt/pro/bitcoincom.py +4 -1
  283. ccxt/pro/bitfinex.py +731 -266
  284. ccxt/pro/bitfinex1.py +635 -0
  285. ccxt/pro/bitget.py +726 -357
  286. ccxt/pro/bithumb.py +380 -0
  287. ccxt/pro/bitmart.py +143 -39
  288. ccxt/pro/bitmex.py +199 -40
  289. ccxt/pro/bitopro.py +25 -13
  290. ccxt/pro/bitrue.py +31 -32
  291. ccxt/pro/bitstamp.py +7 -6
  292. ccxt/pro/bitvavo.py +203 -81
  293. ccxt/pro/blockchaincom.py +30 -17
  294. ccxt/pro/blofin.py +692 -0
  295. ccxt/pro/bybit.py +791 -82
  296. ccxt/pro/cex.py +99 -51
  297. ccxt/pro/coinbase.py +220 -30
  298. ccxt/{async_support/hitbtc3.py → pro/coinbaseadvanced.py} +5 -5
  299. ccxt/pro/{coinbasepro.py → coinbaseexchange.py} +19 -19
  300. ccxt/pro/coinbaseinternational.py +193 -30
  301. ccxt/pro/coincatch.py +1464 -0
  302. ccxt/pro/coincheck.py +11 -6
  303. ccxt/pro/coinex.py +965 -665
  304. ccxt/pro/coinone.py +17 -10
  305. ccxt/pro/cryptocom.py +446 -66
  306. ccxt/pro/currencycom.py +11 -10
  307. ccxt/pro/defx.py +832 -0
  308. ccxt/pro/deribit.py +167 -31
  309. ccxt/pro/exmo.py +252 -20
  310. ccxt/pro/gate.py +729 -64
  311. ccxt/pro/gemini.py +44 -26
  312. ccxt/pro/hashkey.py +802 -0
  313. ccxt/pro/hitbtc.py +208 -103
  314. ccxt/pro/hollaex.py +25 -9
  315. ccxt/pro/htx.py +83 -39
  316. ccxt/pro/huobijp.py +17 -16
  317. ccxt/pro/hyperliquid.py +502 -31
  318. ccxt/pro/idex.py +28 -13
  319. ccxt/pro/independentreserve.py +21 -16
  320. ccxt/pro/kraken.py +298 -51
  321. ccxt/pro/krakenfutures.py +166 -75
  322. ccxt/pro/kucoin.py +395 -77
  323. ccxt/pro/kucoinfutures.py +400 -99
  324. ccxt/pro/lbank.py +52 -31
  325. ccxt/pro/luno.py +12 -10
  326. ccxt/pro/mexc.py +400 -50
  327. ccxt/pro/myokx.py +28 -0
  328. ccxt/pro/ndax.py +25 -12
  329. ccxt/pro/okcoin.py +28 -9
  330. ccxt/pro/okx.py +935 -124
  331. ccxt/pro/onetrading.py +41 -24
  332. ccxt/pro/oxfun.py +1054 -0
  333. ccxt/pro/p2b.py +100 -24
  334. ccxt/pro/paradex.py +352 -0
  335. ccxt/pro/phemex.py +92 -33
  336. ccxt/pro/poloniex.py +128 -49
  337. ccxt/pro/poloniexfutures.py +53 -32
  338. ccxt/pro/probit.py +92 -85
  339. ccxt/pro/upbit.py +401 -8
  340. ccxt/pro/vertex.py +943 -0
  341. ccxt/pro/wazirx.py +46 -28
  342. ccxt/pro/whitebit.py +65 -12
  343. ccxt/pro/woo.py +437 -65
  344. ccxt/pro/woofipro.py +1271 -0
  345. ccxt/pro/xt.py +1067 -0
  346. ccxt/probit.py +143 -110
  347. ccxt/static_dependencies/__init__.py +1 -1
  348. ccxt/static_dependencies/lark/__init__.py +38 -0
  349. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  350. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  351. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  352. ccxt/static_dependencies/lark/common.py +86 -0
  353. ccxt/static_dependencies/lark/exceptions.py +292 -0
  354. ccxt/static_dependencies/lark/grammar.py +130 -0
  355. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  356. ccxt/static_dependencies/lark/indenter.py +143 -0
  357. ccxt/static_dependencies/lark/lark.py +658 -0
  358. ccxt/static_dependencies/lark/lexer.py +678 -0
  359. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  360. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  361. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  362. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  363. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  364. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  365. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  366. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  367. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  368. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  369. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  370. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  371. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  372. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  373. ccxt/static_dependencies/lark/py.typed +0 -0
  374. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  375. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  376. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  377. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  378. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  379. ccxt/static_dependencies/lark/tree.py +267 -0
  380. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  381. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  382. ccxt/static_dependencies/lark/utils.py +343 -0
  383. ccxt/static_dependencies/lark/visitors.py +596 -0
  384. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  385. ccxt/static_dependencies/marshmallow/base.py +65 -0
  386. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  387. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  388. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  389. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  390. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  391. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  392. ccxt/static_dependencies/marshmallow/py.typed +0 -0
  393. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  394. ccxt/static_dependencies/marshmallow/types.py +12 -0
  395. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  396. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  397. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  398. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  399. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  400. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  401. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  402. ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
  403. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  404. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  405. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  406. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  407. ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
  408. ccxt/static_dependencies/starknet/__init__.py +0 -0
  409. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  410. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  411. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  412. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  413. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  414. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  415. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  416. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  417. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  418. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  419. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  420. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  421. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  422. ccxt/static_dependencies/starknet/common.py +15 -0
  423. ccxt/static_dependencies/starknet/constants.py +39 -0
  424. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  425. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  426. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  427. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  428. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  429. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  430. ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  431. ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  432. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  433. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  434. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  435. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  436. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  437. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  438. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  439. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  440. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  441. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  442. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  443. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  444. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  445. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  446. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  447. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  448. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  449. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  450. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  451. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  452. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  453. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  454. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  455. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  456. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  457. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  458. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  459. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  460. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  461. ccxt/static_dependencies/starkware/__init__.py +0 -0
  462. ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  463. ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  464. ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  465. ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  466. ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  467. ccxt/static_dependencies/sympy/__init__.py +0 -0
  468. ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  469. ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  470. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  471. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  472. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  473. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  474. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  475. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  476. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  477. ccxt/test/{test_async.py → tests_async.py} +456 -391
  478. ccxt/test/tests_helpers.py +285 -0
  479. ccxt/test/tests_init.py +39 -0
  480. ccxt/test/{test_sync.py → tests_sync.py} +456 -393
  481. ccxt/timex.py +123 -70
  482. ccxt/tokocrypto.py +129 -93
  483. ccxt/tradeogre.py +39 -25
  484. ccxt/upbit.py +322 -113
  485. ccxt/vertex.py +2983 -0
  486. ccxt/wavesexchange.py +227 -173
  487. ccxt/wazirx.py +145 -65
  488. ccxt/whitebit.py +533 -138
  489. ccxt/woo.py +1137 -296
  490. ccxt/woofipro.py +2716 -0
  491. ccxt/xt.py +4627 -0
  492. ccxt/yobit.py +159 -92
  493. ccxt/zaif.py +80 -33
  494. ccxt/zonda.py +140 -69
  495. ccxt-4.4.49.dist-info/LICENSE.txt +21 -0
  496. ccxt-4.4.49.dist-info/METADATA +646 -0
  497. ccxt-4.4.49.dist-info/RECORD +669 -0
  498. {ccxt-4.2.77.dist-info → ccxt-4.4.49.dist-info}/WHEEL +1 -1
  499. ccxt/abstract/bitbay.py +0 -47
  500. ccxt/abstract/bitfinex2.py +0 -139
  501. ccxt/abstract/hitbtc3.py +0 -115
  502. ccxt/async_support/bitbay.py +0 -17
  503. ccxt/async_support/bitfinex2.py +0 -3496
  504. ccxt/async_support/flowbtc.py +0 -34
  505. ccxt/bitbay.py +0 -17
  506. ccxt/bitfinex2.py +0 -3496
  507. ccxt/flowbtc.py +0 -34
  508. ccxt/hitbtc3.py +0 -16
  509. ccxt/pro/bitfinex2.py +0 -1081
  510. ccxt/test/base/__init__.py +0 -28
  511. ccxt/test/base/test_account.py +0 -26
  512. ccxt/test/base/test_balance.py +0 -56
  513. ccxt/test/base/test_borrow_interest.py +0 -35
  514. ccxt/test/base/test_borrow_rate.py +0 -32
  515. ccxt/test/base/test_calculate_fee.py +0 -51
  516. ccxt/test/base/test_crypto.py +0 -127
  517. ccxt/test/base/test_currency.py +0 -76
  518. ccxt/test/base/test_datetime.py +0 -103
  519. ccxt/test/base/test_decimal_to_precision.py +0 -392
  520. ccxt/test/base/test_deep_extend.py +0 -68
  521. ccxt/test/base/test_deposit_withdrawal.py +0 -50
  522. ccxt/test/base/test_exchange_datetime_functions.py +0 -76
  523. ccxt/test/base/test_funding_rate_history.py +0 -29
  524. ccxt/test/base/test_last_price.py +0 -32
  525. ccxt/test/base/test_ledger_entry.py +0 -45
  526. ccxt/test/base/test_ledger_item.py +0 -48
  527. ccxt/test/base/test_leverage_tier.py +0 -33
  528. ccxt/test/base/test_margin_mode.py +0 -24
  529. ccxt/test/base/test_margin_modification.py +0 -35
  530. ccxt/test/base/test_market.py +0 -190
  531. ccxt/test/base/test_number.py +0 -411
  532. ccxt/test/base/test_ohlcv.py +0 -32
  533. ccxt/test/base/test_open_interest.py +0 -32
  534. ccxt/test/base/test_order.py +0 -64
  535. ccxt/test/base/test_order_book.py +0 -63
  536. ccxt/test/base/test_position.py +0 -60
  537. ccxt/test/base/test_shared_methods.py +0 -345
  538. ccxt/test/base/test_status.py +0 -24
  539. ccxt/test/base/test_throttle.py +0 -126
  540. ccxt/test/base/test_ticker.py +0 -86
  541. ccxt/test/base/test_trade.py +0 -47
  542. ccxt/test/base/test_trading_fee.py +0 -26
  543. ccxt/test/base/test_transaction.py +0 -39
  544. ccxt-4.2.77.dist-info/METADATA +0 -626
  545. ccxt-4.2.77.dist-info/RECORD +0 -534
  546. {ccxt-4.2.77.dist-info → ccxt-4.4.49.dist-info}/top_level.txt +0 -0
ccxt/kraken.py CHANGED
@@ -6,9 +6,10 @@
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, Currency, IndexType, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
9
+ from ccxt.base.types import Balances, Currencies, Currency, DepositAddress, IndexType, Int, LedgerEntry, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
+ from ccxt.base.errors import AuthenticationError
12
13
  from ccxt.base.errors import PermissionDenied
13
14
  from ccxt.base.errors import AccountSuspended
14
15
  from ccxt.base.errors import ArgumentsRequired
@@ -18,14 +19,13 @@ from ccxt.base.errors import InsufficientFunds
18
19
  from ccxt.base.errors import InvalidAddress
19
20
  from ccxt.base.errors import InvalidOrder
20
21
  from ccxt.base.errors import OrderNotFound
21
- from ccxt.base.errors import CancelPending
22
22
  from ccxt.base.errors import NotSupported
23
23
  from ccxt.base.errors import DDoSProtection
24
24
  from ccxt.base.errors import RateLimitExceeded
25
25
  from ccxt.base.errors import ExchangeNotAvailable
26
26
  from ccxt.base.errors import OnMaintenance
27
27
  from ccxt.base.errors import InvalidNonce
28
- from ccxt.base.errors import AuthenticationError
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
@@ -54,14 +54,19 @@ class kraken(Exchange, ImplicitAPI):
54
54
  'option': False,
55
55
  'addMargin': False,
56
56
  'cancelAllOrders': True,
57
+ 'cancelAllOrdersAfter': True,
57
58
  'cancelOrder': True,
58
59
  'cancelOrders': True,
59
60
  'createDepositAddress': True,
61
+ 'createMarketBuyOrderWithCost': True,
62
+ 'createMarketOrderWithCost': False,
63
+ 'createMarketSellOrderWithCost': False,
60
64
  'createOrder': True,
61
65
  'createStopLimitOrder': True,
62
66
  'createStopMarketOrder': True,
63
67
  'createStopOrder': True,
64
68
  'createTrailingAmountOrder': True,
69
+ 'createTrailingPercentOrder': True,
65
70
  'editOrder': True,
66
71
  'fetchBalance': True,
67
72
  'fetchBorrowInterest': False,
@@ -72,6 +77,8 @@ class kraken(Exchange, ImplicitAPI):
72
77
  'fetchCrossBorrowRates': False,
73
78
  'fetchCurrencies': True,
74
79
  'fetchDepositAddress': True,
80
+ 'fetchDepositAddresses': False,
81
+ 'fetchDepositAddressesByNetwork': False,
75
82
  'fetchDeposits': True,
76
83
  'fetchFundingHistory': False,
77
84
  'fetchFundingRate': False,
@@ -94,6 +101,7 @@ class kraken(Exchange, ImplicitAPI):
94
101
  'fetchOrderTrades': 'emulated',
95
102
  'fetchPositions': True,
96
103
  'fetchPremiumIndexOHLCV': False,
104
+ 'fetchStatus': True,
97
105
  'fetchTicker': True,
98
106
  'fetchTickers': True,
99
107
  'fetchTime': True,
@@ -175,13 +183,13 @@ class kraken(Exchange, ImplicitAPI):
175
183
  # rate-limits explained in comment in the top of self file
176
184
  'Assets': 1,
177
185
  'AssetPairs': 1,
178
- 'Depth': 1,
179
- 'OHLC': 1,
186
+ 'Depth': 1.2,
187
+ 'OHLC': 1.2, # 1.2 because 1 triggers too many requests immediately
180
188
  'Spread': 1,
181
189
  'SystemStatus': 1,
182
190
  'Ticker': 1,
183
191
  'Time': 1,
184
- 'Trades': 1,
192
+ 'Trades': 1.2,
185
193
  },
186
194
  },
187
195
  'private': {
@@ -189,6 +197,7 @@ class kraken(Exchange, ImplicitAPI):
189
197
  'AddOrder': 0,
190
198
  'AddOrderBatch': 0,
191
199
  'AddExport': 3,
200
+ 'AmendOrder': 0,
192
201
  'Balance': 3,
193
202
  'CancelAll': 3,
194
203
  'CancelAllOrdersAfter': 3,
@@ -244,6 +253,8 @@ class kraken(Exchange, ImplicitAPI):
244
253
  'XDG': 'DOGE',
245
254
  },
246
255
  'options': {
256
+ 'timeDifference': 0, # the difference between system clock and Binance clock
257
+ 'adjustForTimeDifference': False, # controls the adjustment logic upon instantiation
247
258
  'marketsByAltname': {},
248
259
  'delistedMarketsById': {},
249
260
  # cannot withdraw/deposit these
@@ -253,100 +264,100 @@ class kraken(Exchange, ImplicitAPI):
253
264
  'TRX': 'TRC20',
254
265
  },
255
266
  'depositMethods': {
256
- '1INCH': '1inch(1INCH)',
267
+ '1INCH': '1inch' + ' ' + '(1INCH)',
257
268
  'AAVE': 'Aave',
258
269
  'ADA': 'ADA',
259
270
  'ALGO': 'Algorand',
260
- 'ANKR': 'ANKR(ANKR)',
261
- 'ANT': 'Aragon(ANT)',
271
+ 'ANKR': 'ANKR' + ' ' + '(ANKR)',
272
+ 'ANT': 'Aragon' + ' ' + '(ANT)',
262
273
  'ATOM': 'Cosmos',
263
- 'AXS': 'Axie Infinity Shards(AXS)',
264
- 'BADGER': 'Bager DAO(BADGER)',
265
- 'BAL': 'Balancer(BAL)',
266
- 'BAND': 'Band Protocol(BAND)',
274
+ 'AXS': 'Axie Infinity Shards' + ' ' + '(AXS)',
275
+ 'BADGER': 'Bager DAO' + ' ' + '(BADGER)',
276
+ 'BAL': 'Balancer' + ' ' + '(BAL)',
277
+ 'BAND': 'Band Protocol' + ' ' + '(BAND)',
267
278
  'BAT': 'BAT',
268
279
  'BCH': 'Bitcoin Cash',
269
- 'BNC': 'Bifrost(BNC)',
270
- 'BNT': 'Bancor(BNT)',
280
+ 'BNC': 'Bifrost' + ' ' + '(BNC)',
281
+ 'BNT': 'Bancor' + ' ' + '(BNT)',
271
282
  'BTC': 'Bitcoin',
272
- 'CHZ': 'Chiliz(CHZ)',
273
- 'COMP': 'Compound(COMP)',
274
- 'CQT': '\tCovalent Query Token(CQT)',
275
- 'CRV': 'Curve DAO Token(CRV)',
276
- '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)',
277
288
  'DAI': 'Dai',
278
289
  'DASH': 'Dash',
279
290
  'DOGE': 'Dogecoin',
280
291
  'DOT': 'Polkadot',
281
- 'DYDX': 'dYdX(DYDX)',
282
- 'ENJ': 'Enjin Coin(ENJ)',
292
+ 'DYDX': 'dYdX' + ' ' + '(DYDX)',
293
+ 'ENJ': 'Enjin Coin' + ' ' + '(ENJ)',
283
294
  'EOS': 'EOS',
284
- 'ETC': 'Ether Classic(Hex)',
285
- 'ETH': 'Ether(Hex)',
295
+ 'ETC': 'Ether Classic' + ' ' + '(Hex)',
296
+ 'ETH': 'Ether' + ' ' + '(Hex)',
286
297
  'EWT': 'Energy Web Token',
287
298
  'FEE': 'Kraken Fee Credit',
288
299
  'FIL': 'Filecoin',
289
300
  'FLOW': 'Flow',
290
- 'GHST': 'Aavegotchi(GHST)',
301
+ 'GHST': 'Aavegotchi' + ' ' + '(GHST)',
291
302
  'GNO': 'GNO',
292
303
  'GRT': 'GRT',
293
304
  'ICX': 'Icon',
294
- 'INJ': 'Injective Protocol(INJ)',
295
- 'KAR': 'Karura(KAR)',
305
+ 'INJ': 'Injective Protocol' + ' ' + '(INJ)',
306
+ 'KAR': 'Karura' + ' ' + '(KAR)',
296
307
  'KAVA': 'Kava',
297
- 'KEEP': 'Keep Token(KEEP)',
298
- 'KNC': 'Kyber Network(KNC)',
308
+ 'KEEP': 'Keep Token' + ' ' + '(KEEP)',
309
+ 'KNC': 'Kyber Network' + ' ' + '(KNC)',
299
310
  'KSM': 'Kusama',
300
311
  'LINK': 'Link',
301
- 'LPT': 'Livepeer Token(LPT)',
302
- 'LRC': 'Loopring(LRC)',
312
+ 'LPT': 'Livepeer Token' + ' ' + '(LPT)',
313
+ 'LRC': 'Loopring' + ' ' + '(LRC)',
303
314
  'LSK': 'Lisk',
304
315
  'LTC': 'Litecoin',
305
316
  'MANA': 'MANA',
306
- 'MATIC': 'Polygon(MATIC)',
317
+ 'MATIC': 'Polygon' + ' ' + '(MATIC)',
307
318
  'MINA': 'Mina', # inspected from webui
308
- 'MIR': 'Mirror Protocol(MIR)',
309
- 'MKR': 'Maker(MKR)',
319
+ 'MIR': 'Mirror Protocol' + ' ' + '(MIR)',
320
+ 'MKR': 'Maker' + ' ' + '(MKR)',
310
321
  'MLN': 'MLN',
311
- 'MOVR': 'Moonriver(MOVR)',
322
+ 'MOVR': 'Moonriver' + ' ' + '(MOVR)',
312
323
  'NANO': 'NANO',
313
324
  'OCEAN': 'OCEAN',
314
- 'OGN': 'Origin Protocol(OGN)',
325
+ 'OGN': 'Origin Protocol' + ' ' + '(OGN)',
315
326
  'OMG': 'OMG',
316
- 'OXT': 'Orchid(OXT)',
317
- 'OXY': 'Oxygen(OXY)',
318
- 'PAXG': 'PAX(Gold)',
319
- 'PERP': 'Perpetual Protocol(PERP)',
320
- 'PHA': 'Phala(PHA)',
327
+ 'OXT': 'Orchid' + ' ' + '(OXT)',
328
+ 'OXY': 'Oxygen' + ' ' + '(OXY)',
329
+ 'PAXG': 'PAX' + ' ' + '(Gold)',
330
+ 'PERP': 'Perpetual Protocol' + ' ' + '(PERP)',
331
+ 'PHA': 'Phala' + ' ' + '(PHA)',
321
332
  'QTUM': 'QTUM',
322
- 'RARI': 'Rarible(RARI)',
323
- 'RAY': 'Raydium(RAY)',
324
- 'REN': 'Ren Protocol(REN)',
333
+ 'RARI': 'Rarible' + ' ' + '(RARI)',
334
+ 'RAY': 'Raydium' + ' ' + '(RAY)',
335
+ 'REN': 'Ren Protocol' + ' ' + '(REN)',
325
336
  'REP': 'REPv2',
326
337
  'REPV1': 'REP',
327
- 'SAND': 'The Sandbox(SAND)',
338
+ 'SAND': 'The Sandbox' + ' ' + '(SAND)',
328
339
  'SC': 'Siacoin',
329
- 'SDN': 'Shiden(SDN)',
340
+ 'SDN': 'Shiden' + ' ' + '(SDN)',
330
341
  'SOL': 'Solana', # their deposit method api doesn't work for SOL - was guessed
331
- 'SNX': 'Synthetix Network(SNX)',
342
+ 'SNX': 'Synthetix Network' + ' ' + '(SNX)',
332
343
  'SRM': 'Serum', # inspected from webui
333
- 'STORJ': 'Storj(STORJ)',
334
- 'SUSHI': 'Sushiswap(SUSHI)',
344
+ 'STORJ': 'Storj' + ' ' + '(STORJ)',
345
+ 'SUSHI': 'Sushiswap' + ' ' + '(SUSHI)',
335
346
  'TBTC': 'tBTC',
336
347
  'TRX': 'Tron',
337
348
  'UNI': 'UNI',
338
349
  'USDC': 'USDC',
339
- 'USDT': 'Tether USD(ERC20)',
340
- 'USDT-TRC20': 'Tether USD(TRC20)',
350
+ 'USDT': 'Tether USD' + ' ' + '(ERC20)',
351
+ 'USDT-TRC20': 'Tether USD' + ' ' + '(TRC20)',
341
352
  'WAVES': 'Waves',
342
- 'WBTC': 'Wrapped Bitcoin(WBTC)',
353
+ 'WBTC': 'Wrapped Bitcoin' + ' ' + '(WBTC)',
343
354
  'XLM': 'Stellar XLM',
344
355
  'XMR': 'Monero',
345
356
  'XRP': 'Ripple XRP',
346
357
  'XTZ': 'XTZ',
347
358
  'YFI': 'YFI',
348
- 'ZEC': 'Zcash(Transparent)',
349
- 'ZRX': '0x(ZRX)',
359
+ 'ZEC': 'Zcash' + ' ' + '(Transparent)',
360
+ 'ZRX': '0x' + ' ' + '(ZRX)',
350
361
  },
351
362
  'withdrawMethods': { # keeping it here because deposit and withdraw return different networks codes
352
363
  'Lightning': 'Lightning',
@@ -434,44 +445,128 @@ class kraken(Exchange, ImplicitAPI):
434
445
  'Celestia': 'TIA',
435
446
  },
436
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
+ },
480
+ 'fetchOrder': {
481
+ 'marginMode': False,
482
+ 'trigger': False,
483
+ 'trailing': False,
484
+ },
485
+ 'fetchOpenOrders': {
486
+ 'marginMode': False,
487
+ 'limit': None,
488
+ 'trigger': False,
489
+ 'trailing': False,
490
+ },
491
+ 'fetchOrders': None,
492
+ 'fetchClosedOrders': {
493
+ 'marginMode': False,
494
+ 'limit': None,
495
+ 'daysBack': None,
496
+ 'daysBackCanceled': None,
497
+ 'untilDays': 100000,
498
+ 'trigger': False,
499
+ 'trailing': False,
500
+ },
501
+ 'fetchOHLCV': {
502
+ 'limit': 720,
503
+ },
504
+ },
505
+ 'swap': {
506
+ 'linear': None,
507
+ 'inverse': None,
508
+ },
509
+ 'future': {
510
+ 'linear': None,
511
+ 'inverse': None,
512
+ },
513
+ },
437
514
  'precisionMode': TICK_SIZE,
438
515
  'exceptions': {
439
- 'EQuery:Invalid asset pair': BadSymbol, # {"error":["EQuery:Invalid asset pair"]}
440
- 'EAPI:Invalid key': AuthenticationError,
441
- 'EFunding:Unknown withdraw key': InvalidAddress, # {"error":["EFunding:Unknown withdraw key"]}
442
- 'EFunding:Invalid amount': InsufficientFunds,
443
- 'EService:Unavailable': ExchangeNotAvailable,
444
- 'EDatabase:Internal error': ExchangeNotAvailable,
445
- 'EService:Busy': ExchangeNotAvailable,
446
- 'EQuery:Unknown asset': BadSymbol, # {"error":["EQuery:Unknown asset"]}
447
- 'EAPI:Rate limit exceeded': DDoSProtection,
448
- 'EOrder:Rate limit exceeded': DDoSProtection,
449
- 'EGeneral:Internal error': ExchangeNotAvailable,
450
- 'EGeneral:Temporary lockout': DDoSProtection,
451
- 'EGeneral:Permission denied': PermissionDenied,
452
- 'EOrder:Unknown order': InvalidOrder,
453
- 'EOrder:Order minimum not met': InvalidOrder,
454
- 'EGeneral:Invalid arguments': BadRequest,
455
- 'ESession:Invalid session': AuthenticationError,
456
- 'EAPI:Invalid nonce': InvalidNonce,
457
- 'EFunding:No funding method': BadRequest, # {"error":"EFunding:No funding method"}
458
- 'EFunding:Unknown asset': BadSymbol, # {"error":["EFunding:Unknown asset"]}
459
- 'EService:Market in post_only mode': OnMaintenance, # {"error":["EService:Market in post_only mode"]}
460
- 'EGeneral:Too many requests': DDoSProtection, # {"error":["EGeneral:Too many requests"]}
461
- 'ETrade:User Locked': AccountSuspended, # {"error":["ETrade:User Locked"]}
516
+ 'exact': {
517
+ 'EQuery:Invalid asset pair': BadSymbol, # {"error":["EQuery:Invalid asset pair"]}
518
+ 'EAPI:Invalid key': AuthenticationError,
519
+ 'EFunding:Unknown withdraw key': InvalidAddress, # {"error":["EFunding:Unknown withdraw key"]}
520
+ 'EFunding:Invalid amount': InsufficientFunds,
521
+ 'EService:Unavailable': ExchangeNotAvailable,
522
+ 'EDatabase:Internal error': ExchangeNotAvailable,
523
+ 'EService:Busy': ExchangeNotAvailable,
524
+ 'EQuery:Unknown asset': BadSymbol, # {"error":["EQuery:Unknown asset"]}
525
+ 'EAPI:Rate limit exceeded': DDoSProtection,
526
+ 'EOrder:Rate limit exceeded': DDoSProtection,
527
+ 'EGeneral:Internal error': ExchangeNotAvailable,
528
+ 'EGeneral:Temporary lockout': DDoSProtection,
529
+ 'EGeneral:Permission denied': PermissionDenied,
530
+ 'EGeneral:Invalid arguments:price': InvalidOrder,
531
+ 'EOrder:Unknown order': InvalidOrder,
532
+ 'EOrder:Invalid price:Invalid price argument': InvalidOrder,
533
+ 'EOrder:Order minimum not met': InvalidOrder,
534
+ 'EOrder:Insufficient funds': InsufficientFunds,
535
+ 'EGeneral:Invalid arguments': BadRequest,
536
+ 'ESession:Invalid session': AuthenticationError,
537
+ 'EAPI:Invalid nonce': InvalidNonce,
538
+ 'EFunding:No funding method': BadRequest, # {"error":"EFunding:No funding method"}
539
+ 'EFunding:Unknown asset': BadSymbol, # {"error":["EFunding:Unknown asset"]}
540
+ 'EService:Market in post_only mode': OnMaintenance, # {"error":["EService:Market in post_only mode"]}
541
+ 'EGeneral:Too many requests': DDoSProtection, # {"error":["EGeneral:Too many requests"]}
542
+ 'ETrade:User Locked': AccountSuspended, # {"error":["ETrade:User Locked"]}
543
+ },
544
+ 'broad': {
545
+ ':Invalid order': InvalidOrder,
546
+ ':Invalid arguments:volume': InvalidOrder,
547
+ ':Invalid arguments:viqc': InvalidOrder,
548
+ ':Invalid nonce': InvalidNonce,
549
+ ':IInsufficient funds': InsufficientFunds,
550
+ ':Cancel pending': CancelPending,
551
+ ':Rate limit exceeded': RateLimitExceeded,
552
+ },
462
553
  },
463
554
  })
464
555
 
465
556
  def fee_to_precision(self, symbol, fee):
466
557
  return self.decimal_to_precision(fee, TRUNCATE, self.markets[symbol]['precision']['amount'], self.precisionMode)
467
558
 
468
- def fetch_markets(self, params={}):
559
+ def fetch_markets(self, params={}) -> List[Market]:
469
560
  """
470
561
  retrieves data on all markets for kraken
471
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTradableAssetPairs
562
+
563
+ https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTradableAssetPairs
564
+
472
565
  :param dict [params]: extra parameters specific to the exchange API endpoint
473
566
  :returns dict[]: an array of objects representing market data
474
567
  """
568
+ if self.options['adjustForTimeDifference']:
569
+ self.load_time_difference()
475
570
  response = self.publicGetAssetPairs(params)
476
571
  #
477
572
  # {
@@ -547,6 +642,8 @@ class kraken(Exchange, ImplicitAPI):
547
642
  leverageBuy = self.safe_value(market, 'leverage_buy', [])
548
643
  leverageBuyLength = len(leverageBuy)
549
644
  precisionPrice = self.parse_number(self.parse_precision(self.safe_string(market, 'pair_decimals')))
645
+ status = self.safe_string(market, 'status')
646
+ isActive = status == 'online'
550
647
  result.append({
551
648
  'id': id,
552
649
  'wsId': self.safe_string(market, 'wsname'),
@@ -565,7 +662,7 @@ class kraken(Exchange, ImplicitAPI):
565
662
  'swap': False,
566
663
  'future': False,
567
664
  'option': False,
568
- 'active': True,
665
+ 'active': isActive,
569
666
  'contract': False,
570
667
  'linear': None,
571
668
  'inverse': None,
@@ -609,23 +706,21 @@ class kraken(Exchange, ImplicitAPI):
609
706
  if currencyId is not None:
610
707
  if len(currencyId) > 3:
611
708
  if (currencyId.find('X') == 0) or (currencyId.find('Z') == 0):
612
- if currencyId.find('.') > 0:
613
- return super(kraken, self).safe_currency(currencyId, currency)
614
- else:
709
+ if not (currencyId.find('.') > 0) and (currencyId != 'ZEUS'):
615
710
  currencyId = currencyId[1:]
616
711
  return super(kraken, self).safe_currency(currencyId, currency)
617
712
 
618
713
  def append_inactive_markets(self, result):
619
714
  # result should be an array to append to
620
- precision = {
715
+ precision: dict = {
621
716
  'amount': self.parse_number('1e-8'),
622
717
  'price': self.parse_number('1e-8'),
623
718
  }
624
- costLimits = {'min': None, 'max': None}
625
- priceLimits = {'min': precision['price'], 'max': None}
626
- amountLimits = {'min': precision['amount'], 'max': None}
627
- limits = {'amount': amountLimits, 'price': priceLimits, 'cost': costLimits}
628
- defaults = {
719
+ costLimits: dict = {'min': None, 'max': None}
720
+ priceLimits: dict = {'min': precision['price'], 'max': None}
721
+ amountLimits: dict = {'min': precision['amount'], 'max': None}
722
+ limits: dict = {'amount': amountLimits, 'price': priceLimits, 'cost': costLimits}
723
+ defaults: dict = {
629
724
  'darkpool': False,
630
725
  'info': None,
631
726
  'maker': None,
@@ -641,10 +736,38 @@ class kraken(Exchange, ImplicitAPI):
641
736
  result.append(self.extend(defaults, markets[i]))
642
737
  return result
643
738
 
644
- def fetch_currencies(self, params={}):
739
+ def fetch_status(self, params={}):
740
+ """
741
+ the latest known information on the availability of the exchange API
742
+
743
+ https://docs.kraken.com/api/docs/rest-api/get-system-status/
744
+
745
+ :param dict [params]: extra parameters specific to the exchange API endpoint
746
+ :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
747
+ """
748
+ response = self.publicGetSystemStatus(params)
749
+ #
750
+ # {
751
+ # error: [],
752
+ # result: {status: 'online', timestamp: '2024-07-22T16:34:44Z'}
753
+ # }
754
+ #
755
+ result = self.safe_dict(response, 'result')
756
+ statusRaw = self.safe_string(result, 'status')
757
+ return {
758
+ 'status': 'ok' if (statusRaw == 'online') else 'maintenance',
759
+ 'updated': None,
760
+ 'eta': None,
761
+ 'url': None,
762
+ 'info': response,
763
+ }
764
+
765
+ def fetch_currencies(self, params={}) -> Currencies:
645
766
  """
646
767
  fetches all available currencies on an exchange
647
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getAssetInfo
768
+
769
+ https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getAssetInfo
770
+
648
771
  :param dict [params]: extra parameters specific to the exchange API endpoint
649
772
  :returns dict: an associative dictionary of currencies
650
773
  """
@@ -653,15 +776,20 @@ class kraken(Exchange, ImplicitAPI):
653
776
  # {
654
777
  # "error": [],
655
778
  # "result": {
656
- # "ADA": {"aclass": "currency", "altname": "ADA", "decimals": 8, "display_decimals": 6},
657
- # "BCH": {"aclass": "currency", "altname": "BCH", "decimals": 10, "display_decimals": 5},
779
+ # "BCH": {
780
+ # "aclass": "currency",
781
+ # "altname": "BCH",
782
+ # "decimals": 10,
783
+ # "display_decimals": 5
784
+ # "status": "enabled",
785
+ # },
658
786
  # ...
659
787
  # },
660
788
  # }
661
789
  #
662
790
  currencies = self.safe_value(response, 'result', {})
663
791
  ids = list(currencies.keys())
664
- result = {}
792
+ result: dict = {}
665
793
  for i in range(0, len(ids)):
666
794
  id = ids[i]
667
795
  currency = currencies[id]
@@ -669,15 +797,15 @@ class kraken(Exchange, ImplicitAPI):
669
797
  # see: https://support.kraken.com/hc/en-us/articles/201893608-What-are-the-withdrawal-fees-
670
798
  # to add support for multiple withdrawal/deposit methods and
671
799
  # differentiated fees for each particular method
672
- code = self.safe_currency_code(self.safe_string(currency, 'altname'))
800
+ code = self.safe_currency_code(id)
673
801
  precision = self.parse_number(self.parse_precision(self.safe_string(currency, 'decimals')))
674
802
  # assumes all currencies are active except those listed above
675
- active = not self.in_array(code, self.options['inactiveCurrencies'])
803
+ active = self.safe_string(currency, 'status') == 'enabled'
676
804
  result[code] = {
677
805
  'id': id,
678
806
  'code': code,
679
807
  'info': currency,
680
- 'name': code,
808
+ 'name': self.safe_string(currency, 'altname'),
681
809
  'active': active,
682
810
  'deposit': None,
683
811
  'withdraw': None,
@@ -697,17 +825,19 @@ class kraken(Exchange, ImplicitAPI):
697
825
  }
698
826
  return result
699
827
 
700
- def fetch_trading_fee(self, symbol: str, params={}):
828
+ def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
701
829
  """
702
830
  fetch the trading fees for a market
703
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradeVolume
831
+
832
+ https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradeVolume
833
+
704
834
  :param str symbol: unified market symbol
705
835
  :param dict [params]: extra parameters specific to the exchange API endpoint
706
836
  :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
707
837
  """
708
838
  self.load_markets()
709
839
  market = self.market(symbol)
710
- request = {
840
+ request: dict = {
711
841
  'pair': market['id'],
712
842
  'fee-info': True,
713
843
  }
@@ -752,8 +882,8 @@ class kraken(Exchange, ImplicitAPI):
752
882
  return {
753
883
  'info': response,
754
884
  'symbol': market['symbol'],
755
- 'maker': self.safe_number(symbolMakerFee, 'fee'),
756
- 'taker': self.safe_number(symbolTakerFee, 'fee'),
885
+ 'maker': self.parse_number(Precise.string_div(self.safe_string(symbolMakerFee, 'fee'), '100')),
886
+ 'taker': self.parse_number(Precise.string_div(self.safe_string(symbolTakerFee, 'fee'), '100')),
757
887
  'percentage': True,
758
888
  'tierBased': True,
759
889
  }
@@ -767,7 +897,9 @@ class kraken(Exchange, ImplicitAPI):
767
897
  def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
768
898
  """
769
899
  fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
770
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getOrderBook
900
+
901
+ https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getOrderBook
902
+
771
903
  :param str symbol: unified symbol of the market to fetch the order book for
772
904
  :param int [limit]: the maximum amount of order book entries to return
773
905
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -777,7 +909,7 @@ class kraken(Exchange, ImplicitAPI):
777
909
  market = self.market(symbol)
778
910
  if market['darkpool']:
779
911
  raise ExchangeError(self.id + ' fetchOrderBook() does not provide an order book for darkpool symbol ' + symbol)
780
- request = {
912
+ request: dict = {
781
913
  'pair': market['id'],
782
914
  }
783
915
  if limit is not None:
@@ -812,7 +944,7 @@ class kraken(Exchange, ImplicitAPI):
812
944
  orderbook = self.safe_value(result, wsName, orderbook)
813
945
  return self.parse_order_book(orderbook, symbol)
814
946
 
815
- def parse_ticker(self, ticker, market: Market = None) -> Ticker:
947
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
816
948
  #
817
949
  # {
818
950
  # "a":["2432.77000","1","1.000"],
@@ -864,13 +996,15 @@ class kraken(Exchange, ImplicitAPI):
864
996
  def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
865
997
  """
866
998
  fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
867
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTickerInformation
999
+
1000
+ https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTickerInformation
1001
+
868
1002
  :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
869
1003
  :param dict [params]: extra parameters specific to the exchange API endpoint
870
1004
  :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
871
1005
  """
872
1006
  self.load_markets()
873
- request = {}
1007
+ request: dict = {}
874
1008
  if symbols is not None:
875
1009
  symbols = self.market_symbols(symbols)
876
1010
  marketIds = []
@@ -883,7 +1017,7 @@ class kraken(Exchange, ImplicitAPI):
883
1017
  response = self.publicGetTicker(self.extend(request, params))
884
1018
  tickers = response['result']
885
1019
  ids = list(tickers.keys())
886
- result = {}
1020
+ result: dict = {}
887
1021
  for i in range(0, len(ids)):
888
1022
  id = ids[i]
889
1023
  market = self.safe_market(id)
@@ -895,7 +1029,9 @@ class kraken(Exchange, ImplicitAPI):
895
1029
  def fetch_ticker(self, symbol: str, params={}) -> Ticker:
896
1030
  """
897
1031
  fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
898
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTickerInformation
1032
+
1033
+ https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTickerInformation
1034
+
899
1035
  :param str symbol: unified symbol of the market to fetch the ticker for
900
1036
  :param dict [params]: extra parameters specific to the exchange API endpoint
901
1037
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -905,7 +1041,7 @@ class kraken(Exchange, ImplicitAPI):
905
1041
  if darkpool:
906
1042
  raise ExchangeError(self.id + ' fetchTicker() does not provide a ticker for darkpool symbol ' + symbol)
907
1043
  market = self.market(symbol)
908
- request = {
1044
+ request: dict = {
909
1045
  'pair': market['id'],
910
1046
  }
911
1047
  response = self.publicGetTicker(self.extend(request, params))
@@ -937,7 +1073,9 @@ class kraken(Exchange, ImplicitAPI):
937
1073
  def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
938
1074
  """
939
1075
  fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
940
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getOHLCData
1076
+
1077
+ https://docs.kraken.com/api/docs/rest-api/get-ohlc-data
1078
+
941
1079
  :param str symbol: unified symbol of the market to fetch OHLCV data for
942
1080
  :param str timeframe: the length of time each candle represents
943
1081
  :param int [since]: timestamp in ms of the earliest candle to fetch
@@ -953,7 +1091,7 @@ class kraken(Exchange, ImplicitAPI):
953
1091
  return self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 720)
954
1092
  market = self.market(symbol)
955
1093
  parsedTimeframe = self.safe_integer(self.timeframes, timeframe)
956
- request = {
1094
+ request: dict = {
957
1095
  'pair': market['id'],
958
1096
  }
959
1097
  if parsedTimeframe is not None:
@@ -961,9 +1099,9 @@ class kraken(Exchange, ImplicitAPI):
961
1099
  else:
962
1100
  request['interval'] = timeframe
963
1101
  if since is not None:
964
- # contrary to kraken's api documentation, the since parameter must be passed in nanoseconds
965
- # the adding of '000000' is copied from the fetchTrades function
966
- request['since'] = self.number_to_string(since) + '000000' # expected to be in nanoseconds
1102
+ scaledSince = self.parse_to_int(since / 1000)
1103
+ timeFrameInSeconds = parsedTimeframe * 60
1104
+ request['since'] = self.number_to_string(scaledSince - timeFrameInSeconds) # expected to be in seconds
967
1105
  response = self.publicGetOHLC(self.extend(request, params))
968
1106
  #
969
1107
  # {
@@ -979,11 +1117,11 @@ class kraken(Exchange, ImplicitAPI):
979
1117
  # }
980
1118
  # }
981
1119
  result = self.safe_value(response, 'result', {})
982
- ohlcvs = self.safe_value(result, market['id'], [])
1120
+ ohlcvs = self.safe_list(result, market['id'], [])
983
1121
  return self.parse_ohlcvs(ohlcvs, market, timeframe, since, limit)
984
1122
 
985
1123
  def parse_ledger_entry_type(self, type):
986
- types = {
1124
+ types: dict = {
987
1125
  'trade': 'trade',
988
1126
  'withdrawal': 'transaction',
989
1127
  'deposit': 'transaction',
@@ -992,7 +1130,7 @@ class kraken(Exchange, ImplicitAPI):
992
1130
  }
993
1131
  return self.safe_string(types, type, type)
994
1132
 
995
- def parse_ledger_entry(self, item, currency: Currency = None):
1133
+ def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
996
1134
  #
997
1135
  # {
998
1136
  # 'LTFK7F-N2CUX-PNY4SX': {
@@ -1014,15 +1152,17 @@ class kraken(Exchange, ImplicitAPI):
1014
1152
  referenceId = self.safe_string(item, 'refid')
1015
1153
  referenceAccount = None
1016
1154
  type = self.parse_ledger_entry_type(self.safe_string(item, 'type'))
1017
- code = self.safe_currency_code(self.safe_string(item, 'asset'), currency)
1155
+ currencyId = self.safe_string(item, 'asset')
1156
+ code = self.safe_currency_code(currencyId, currency)
1157
+ currency = self.safe_currency(currencyId, currency)
1018
1158
  amount = self.safe_string(item, 'amount')
1019
1159
  if Precise.string_lt(amount, '0'):
1020
1160
  direction = 'out'
1021
1161
  amount = Precise.string_abs(amount)
1022
1162
  else:
1023
1163
  direction = 'in'
1024
- timestamp = self.safe_timestamp(item, 'time')
1025
- return {
1164
+ timestamp = self.safe_integer_product(item, 'time', 1000)
1165
+ return self.safe_ledger_entry({
1026
1166
  'info': item,
1027
1167
  'id': id,
1028
1168
  'direction': direction,
@@ -1041,29 +1181,36 @@ class kraken(Exchange, ImplicitAPI):
1041
1181
  'cost': self.safe_number(item, 'fee'),
1042
1182
  'currency': code,
1043
1183
  },
1044
- }
1184
+ }, currency)
1045
1185
 
1046
- def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
1186
+ def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
1047
1187
  """
1048
- fetch the history of changes, actions done by the user or operations that altered balance of the user
1049
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getLedgers
1050
- :param str code: unified currency code, default is None
1188
+ fetch the history of changes, actions done by the user or operations that altered the balance of the user
1189
+
1190
+ https://docs.kraken.com/rest/#tag/Account-Data/operation/getLedgers
1191
+
1192
+ :param str [code]: unified currency code, default is None
1051
1193
  :param int [since]: timestamp in ms of the earliest ledger entry, default is None
1052
- :param int [limit]: max number of ledger entrys to return, default is None
1194
+ :param int [limit]: max number of ledger entries to return, default is None
1053
1195
  :param dict [params]: extra parameters specific to the exchange API endpoint
1054
1196
  :param int [params.until]: timestamp in ms of the latest ledger entry
1055
- :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
1197
+ :param int [params.end]: timestamp in seconds of the latest ledger entry
1198
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
1056
1199
  """
1057
1200
  # https://www.kraken.com/features/api#get-ledgers-info
1058
1201
  self.load_markets()
1059
- request = {}
1202
+ request: dict = {}
1060
1203
  currency = None
1061
1204
  if code is not None:
1062
1205
  currency = self.currency(code)
1063
1206
  request['asset'] = currency['id']
1064
1207
  if since is not None:
1065
1208
  request['start'] = self.parse_to_int(since / 1000)
1066
- request, params = self.handle_until_option('end', request, params)
1209
+ until = self.safe_string_n(params, ['until', 'till'])
1210
+ if until is not None:
1211
+ params = self.omit(params, ['until', 'till'])
1212
+ untilDivided = Precise.string_div(until, '1000')
1213
+ request['end'] = self.parse_to_int(Precise.string_add(untilDivided, '1'))
1067
1214
  response = self.privatePostLedgers(self.extend(request, params))
1068
1215
  # { error: [],
1069
1216
  # "result": {ledger: {'LPUAIB-TS774-UKHP7X': { refid: "A2B4HBV-L4MDIE-JU4N3N",
@@ -1112,11 +1259,11 @@ class kraken(Exchange, ImplicitAPI):
1112
1259
  items.append(value)
1113
1260
  return self.parse_ledger(items)
1114
1261
 
1115
- def fetch_ledger_entry(self, id: str, code: Str = None, params={}):
1262
+ def fetch_ledger_entry(self, id: str, code: Str = None, params={}) -> LedgerEntry:
1116
1263
  items = self.fetch_ledger_entries_by_ids([id], code, params)
1117
1264
  return items[0]
1118
1265
 
1119
- def parse_trade(self, trade, market: Market = None) -> Trade:
1266
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
1120
1267
  #
1121
1268
  # fetchTrades(public)
1122
1269
  #
@@ -1147,6 +1294,26 @@ class kraken(Exchange, ImplicitAPI):
1147
1294
  # "misc": ''
1148
1295
  # }
1149
1296
  #
1297
+ # fetchMyTrades
1298
+ #
1299
+ # {
1300
+ # "ordertxid": "OSJVN7-A2AE-63WZV",
1301
+ # "postxid": "TBP7O6-PNXI-CONU",
1302
+ # "pair": "XXBTZUSD",
1303
+ # "time": 1710429248.3052235,
1304
+ # "type": "sell",
1305
+ # "ordertype": "liquidation market",
1306
+ # "price": "72026.50000",
1307
+ # "cost": "7.20265",
1308
+ # "fee": "0.01873",
1309
+ # "vol": "0.00010000",
1310
+ # "margin": "1.44053",
1311
+ # "leverage": "5",
1312
+ # "misc": "closing",
1313
+ # "trade_id": 68230622,
1314
+ # "maker": False
1315
+ # }
1316
+ #
1150
1317
  timestamp = None
1151
1318
  side = None
1152
1319
  type = None
@@ -1193,6 +1360,10 @@ class kraken(Exchange, ImplicitAPI):
1193
1360
  if market is not None:
1194
1361
  symbol = market['symbol']
1195
1362
  cost = self.safe_string(trade, 'cost')
1363
+ maker = self.safe_bool(trade, 'maker')
1364
+ takerOrMaker = None
1365
+ if maker is not None:
1366
+ takerOrMaker = 'maker' if maker else 'taker'
1196
1367
  return self.safe_trade({
1197
1368
  'id': id,
1198
1369
  'order': orderId,
@@ -1202,7 +1373,7 @@ class kraken(Exchange, ImplicitAPI):
1202
1373
  'symbol': symbol,
1203
1374
  'type': type,
1204
1375
  'side': side,
1205
- 'takerOrMaker': None,
1376
+ 'takerOrMaker': takerOrMaker,
1206
1377
  'price': price,
1207
1378
  'amount': amount,
1208
1379
  'cost': cost,
@@ -1212,7 +1383,9 @@ class kraken(Exchange, ImplicitAPI):
1212
1383
  def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1213
1384
  """
1214
1385
  get the list of most recent trades for a particular symbol
1215
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getRecentTrades
1386
+
1387
+ https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getRecentTrades
1388
+
1216
1389
  :param str symbol: unified symbol of the market to fetch trades for
1217
1390
  :param int [since]: timestamp in ms of the earliest trade to fetch
1218
1391
  :param int [limit]: the maximum amount of trades to fetch
@@ -1222,16 +1395,13 @@ class kraken(Exchange, ImplicitAPI):
1222
1395
  self.load_markets()
1223
1396
  market = self.market(symbol)
1224
1397
  id = market['id']
1225
- request = {
1398
+ request: dict = {
1226
1399
  'pair': id,
1227
1400
  }
1228
1401
  # https://support.kraken.com/hc/en-us/articles/218198197-How-to-pull-all-trade-data-using-the-Kraken-REST-API
1229
1402
  # https://github.com/ccxt/ccxt/issues/5677
1230
1403
  if since is not None:
1231
- # php does not format it properly
1232
- # therefore we use string concatenation here
1233
- request['since'] = since * 1e6
1234
- request['since'] = str(since) + '000000' # expected to be in nanoseconds
1404
+ request['since'] = self.number_to_string(self.parse_to_int(since / 1000)) # expected to be in seconds
1235
1405
  if limit is not None:
1236
1406
  request['count'] = limit
1237
1407
  response = self.publicGetTrades(self.extend(request, params))
@@ -1260,7 +1430,7 @@ class kraken(Exchange, ImplicitAPI):
1260
1430
 
1261
1431
  def parse_balance(self, response) -> Balances:
1262
1432
  balances = self.safe_value(response, 'result', {})
1263
- result = {
1433
+ result: dict = {
1264
1434
  'info': response,
1265
1435
  'timestamp': None,
1266
1436
  'datetime': None,
@@ -1279,7 +1449,9 @@ class kraken(Exchange, ImplicitAPI):
1279
1449
  def fetch_balance(self, params={}) -> Balances:
1280
1450
  """
1281
1451
  query for balance and get the amount of funds available for trading or funds locked in orders
1282
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getExtendedBalance
1452
+
1453
+ https://docs.kraken.com/rest/#tag/Account-Data/operation/getExtendedBalance
1454
+
1283
1455
  :param dict [params]: extra parameters specific to the exchange API endpoint
1284
1456
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1285
1457
  """
@@ -1302,46 +1474,83 @@ class kraken(Exchange, ImplicitAPI):
1302
1474
  #
1303
1475
  return self.parse_balance(response)
1304
1476
 
1477
+ def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost: float, params={}):
1478
+ """
1479
+ create a market order by providing the symbol, side and cost
1480
+
1481
+ https://docs.kraken.com/rest/#tag/Spot-Trading/operation/addOrder
1482
+
1483
+ :param str symbol: unified symbol of the market to create an order in(only USD markets are supported)
1484
+ :param str side: 'buy' or 'sell'
1485
+ :param float cost: how much you want to trade in units of the quote currency
1486
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1487
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1488
+ """
1489
+ self.load_markets()
1490
+ # only buy orders are supported by the endpoint
1491
+ req = {
1492
+ 'cost': cost,
1493
+ }
1494
+ return self.create_order(symbol, 'market', side, 1, None, self.extend(req, params))
1495
+
1496
+ def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
1497
+ """
1498
+ create a market buy order by providing the symbol, side and cost
1499
+
1500
+ https://docs.kraken.com/rest/#tag/Spot-Trading/operation/addOrder
1501
+
1502
+ :param str symbol: unified symbol of the market to create an order in
1503
+ :param float cost: how much you want to trade in units of the quote currency
1504
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1505
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1506
+ """
1507
+ self.load_markets()
1508
+ return self.create_market_order_with_cost(symbol, 'buy', cost, params)
1509
+
1305
1510
  def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1306
1511
  """
1307
- :see: https://docs.kraken.com/rest/#tag/Trading/operation/addOrder
1308
1512
  create a trade order
1513
+
1514
+ https://docs.kraken.com/api/docs/rest-api/add-order
1515
+
1309
1516
  :param str symbol: unified symbol of the market to create an order in
1310
1517
  :param str type: 'market' or 'limit'
1311
1518
  :param str side: 'buy' or 'sell'
1312
1519
  :param float amount: how much of currency you want to trade in units of base currency
1313
- :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1520
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1314
1521
  :param dict [params]: extra parameters specific to the exchange API endpoint
1315
1522
  :param bool [params.postOnly]: if True, the order will only be posted to the order book and not executed immediately
1316
1523
  :param bool [params.reduceOnly]: *margin only* indicates if self order is to reduce the size of a position
1317
1524
  :param float [params.stopLossPrice]: *margin only* the price that a stop loss order is triggered at
1318
1525
  :param float [params.takeProfitPrice]: *margin only* the price that a take profit order is triggered at
1319
1526
  :param str [params.trailingAmount]: *margin only* the quote amount to trail away from the current market price
1527
+ :param str [params.trailingPercent]: *margin only* the percent to trail away from the current market price
1320
1528
  :param str [params.trailingLimitAmount]: *margin only* the quote amount away from the trailingAmount
1529
+ :param str [params.trailingLimitPercent]: *margin only* the percent away from the trailingAmount
1321
1530
  :param str [params.offset]: *margin only* '+' or '-' whether you want the trailingLimitAmount value to be positive or negative, default is negative '-'
1322
1531
  :param str [params.trigger]: *margin only* the activation price type, 'last' or 'index', default is 'last'
1323
1532
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1324
1533
  """
1325
1534
  self.load_markets()
1326
1535
  market = self.market(symbol)
1327
- request = {
1536
+ request: dict = {
1328
1537
  'pair': market['id'],
1329
1538
  'type': side,
1330
1539
  'ordertype': type,
1331
1540
  'volume': self.amount_to_precision(symbol, amount),
1332
1541
  }
1333
- orderRequest = self.order_request('createOrder()', symbol, type, request, price, params)
1542
+ orderRequest = self.order_request('createOrder', symbol, type, request, amount, price, params)
1334
1543
  response = self.privatePostAddOrder(self.extend(orderRequest[0], orderRequest[1]))
1335
1544
  #
1336
1545
  # {
1337
1546
  # "error": [],
1338
1547
  # "result": {
1339
- # "descr": {order: 'buy 0.02100000 ETHUSDT @ limit 330.00'},
1548
+ # "descr": {order: 'buy 0.02100000 ETHUSDT @ limit 330.00'}, # see more examples in "parseOrder"
1340
1549
  # "txid": ['OEKVV2-IH52O-TPL6GZ']
1341
1550
  # }
1342
1551
  # }
1343
1552
  #
1344
- result = self.safe_value(response, 'result')
1553
+ result = self.safe_dict(response, 'result')
1345
1554
  return self.parse_order(result)
1346
1555
 
1347
1556
  def find_market_by_altname_or_id(self, id):
@@ -1384,8 +1593,8 @@ class kraken(Exchange, ImplicitAPI):
1384
1593
  self.options['delistedMarketsById'][id] = market
1385
1594
  return market
1386
1595
 
1387
- def parse_order_status(self, status):
1388
- statuses = {
1596
+ def parse_order_status(self, status: Str):
1597
+ statuses: dict = {
1389
1598
  'pending': 'open', # order pending book entry
1390
1599
  'open': 'open',
1391
1600
  'closed': 'closed',
@@ -1395,55 +1604,38 @@ class kraken(Exchange, ImplicitAPI):
1395
1604
  return self.safe_string(statuses, status, status)
1396
1605
 
1397
1606
  def parse_order_type(self, status):
1398
- statuses = {
1607
+ statuses: dict = {
1608
+ # we dont add "space" delimited orders here(eg. stop loss) because they need separate parsing
1399
1609
  'take-profit': 'market',
1400
- 'stop-loss-limit': 'limit',
1401
1610
  'stop-loss': 'market',
1611
+ 'stop-loss-limit': 'limit',
1402
1612
  'take-profit-limit': 'limit',
1403
1613
  'trailing-stop-limit': 'limit',
1404
1614
  }
1405
1615
  return self.safe_string(statuses, status, status)
1406
1616
 
1407
- def parse_order(self, order, market: Market = None) -> Order:
1617
+ def parse_order(self, order: dict, market: Market = None) -> Order:
1408
1618
  #
1409
- # createOrder for regular orders
1619
+ # createOrder
1410
1620
  #
1411
1621
  # {
1412
- # "descr": {order: 'buy 0.02100000 ETHUSDT @ limit 330.00'},
1622
+ # "descr": {
1623
+ # "order": "buy 0.02100000 ETHUSDT @ limit 330.00" # limit orders
1624
+ # "buy 0.12345678 ETHUSDT @ market" # market order
1625
+ # "sell 0.28002676 ETHUSDT @ stop loss 0.0123 -> limit 0.0.1222" # stop order
1626
+ # "sell 0.00100000 ETHUSDT @ stop loss 2677.00 -> limit 2577.00 with 5:1 leverage"
1627
+ # "buy 0.10000000 LTCUSDT @ take profit 75.00000 -> limit 74.00000"
1628
+ # "sell 10.00000000 XRPEUR @ trailing stop +50.0000%" # trailing stop
1629
+ # },
1413
1630
  # "txid": ['OEKVV2-IH52O-TPL6GZ']
1414
1631
  # }
1415
- # {
1416
- # "txid": ["TX_ID_HERE"],
1417
- # "descr": {"order":"buy 0.12345678 ETHEUR @ market"},
1418
- # }
1419
- #
1420
- #
1421
- # createOrder for stop orders
1422
- #
1423
- # {
1424
- # "txid":["OSILNC-VQI5Q-775ZDQ"],
1425
- # "descr":{"order":"sell 167.28002676 ADAXBT @ stop loss 0.00003280 -> limit 0.00003212"}
1426
- # }
1427
- #
1428
- #
1429
- # {
1430
- # "txid":["OVHMJV-BZW2V-6NZFWF"],
1431
- # "descr":{"order":"sell 0.00100000 ETHUSD @ stop loss 2677.00 -> limit 2577.00 with 5:1 leverage"}
1432
- # }
1433
1632
  #
1434
1633
  # editOrder
1435
1634
  #
1436
1635
  # {
1437
- # "status": "ok",
1438
- # "txid": "OAW2BO-7RWEK-PZY5UO",
1439
- # "originaltxid": "OXL6SS-UPNMC-26WBE7",
1440
- # "volume": "0.00075000",
1441
- # "price": "13500.0",
1442
- # "orders_cancelled": 1,
1443
- # "descr": {
1444
- # "order": "buy 0.00075000 XBTUSDT @ limit 13500.0"
1445
- # }
1636
+ # "amend_id": "TJSMEH-AA67V-YUSQ6O"
1446
1637
  # }
1638
+ #
1447
1639
  # ws - createOrder
1448
1640
  # {
1449
1641
  # "descr": 'sell 0.00010000 XBTUSDT @ market',
@@ -1497,31 +1689,68 @@ class kraken(Exchange, ImplicitAPI):
1497
1689
  # }
1498
1690
  # }
1499
1691
  #
1692
+ # fetchOpenOrders
1693
+ #
1694
+ # {
1695
+ # "refid": null,
1696
+ # "userref": null,
1697
+ # "cl_ord_id": "1234",
1698
+ # "status": "open",
1699
+ # "opentm": 1733815269.370054,
1700
+ # "starttm": 0,
1701
+ # "expiretm": 0,
1702
+ # "descr": {
1703
+ # "pair": "XBTUSD",
1704
+ # "type": "buy",
1705
+ # "ordertype": "limit",
1706
+ # "price": "70000.0",
1707
+ # "price2": "0",
1708
+ # "leverage": "none",
1709
+ # "order": "buy 0.00010000 XBTUSD @ limit 70000.0",
1710
+ # "close": ""
1711
+ # },
1712
+ # "vol": "0.00010000",
1713
+ # "vol_exec": "0.00000000",
1714
+ # "cost": "0.00000",
1715
+ # "fee": "0.00000",
1716
+ # "price": "0.00000",
1717
+ # "stopprice": "0.00000",
1718
+ # "limitprice": "0.00000",
1719
+ # "misc": "",
1720
+ # "oflags": "fciq"
1721
+ # }
1722
+ #
1500
1723
  description = self.safe_dict(order, 'descr', {})
1724
+ orderDescriptionObj = self.safe_dict(order, 'descr') # can be null
1501
1725
  orderDescription = None
1502
- if description is not None:
1503
- orderDescription = self.safe_string(description, 'order')
1726
+ if orderDescriptionObj is not None:
1727
+ orderDescription = self.safe_string(orderDescriptionObj, 'order')
1504
1728
  else:
1505
1729
  orderDescription = self.safe_string(order, 'descr')
1506
1730
  side = None
1507
- type = None
1731
+ rawType = None
1508
1732
  marketId = None
1509
1733
  price = None
1510
1734
  amount = None
1511
- stopPrice = None
1735
+ triggerPrice = None
1512
1736
  if orderDescription is not None:
1513
1737
  parts = orderDescription.split(' ')
1514
1738
  side = self.safe_string(parts, 0)
1515
1739
  amount = self.safe_string(parts, 1)
1516
1740
  marketId = self.safe_string(parts, 2)
1517
- type = self.safe_string(parts, 4)
1518
- if type == 'stop':
1519
- stopPrice = self.safe_string(parts, 6)
1741
+ part4 = self.safe_string(parts, 4)
1742
+ part5 = self.safe_string(parts, 5)
1743
+ if part4 == 'limit' or part4 == 'market':
1744
+ rawType = part4 # eg, limit, market
1745
+ else:
1746
+ rawType = part4 + ' ' + part5 # eg. stop loss, take profit, trailing stop
1747
+ if rawType == 'stop loss' or rawType == 'take profit':
1748
+ triggerPrice = self.safe_string(parts, 6)
1520
1749
  price = self.safe_string(parts, 9)
1521
- elif type == 'limit':
1750
+ elif rawType == 'limit':
1522
1751
  price = self.safe_string(parts, 5)
1523
1752
  side = self.safe_string(description, 'type', side)
1524
- type = self.safe_string(description, 'ordertype', type)
1753
+ rawType = self.safe_string(description, 'ordertype', rawType) # orderType has dash, e.g. trailing-stop
1525
1754
  marketId = self.safe_string(description, 'pair', marketId)
1526
1755
  foundMarket = self.find_market_by_altname_or_id(marketId)
1527
1756
  symbol = None
@@ -1560,11 +1789,12 @@ class kraken(Exchange, ImplicitAPI):
1560
1789
  elif flags.find('fcib') >= 0:
1561
1790
  fee['currency'] = market['base']
1562
1791
  status = self.parse_order_status(self.safe_string(order, 'status'))
1563
- id = self.safe_string_2(order, 'id', 'txid')
1564
- if (id is None) or (id[0:1] == '['):
1565
- txid = self.safe_value(order, 'txid')
1792
+ id = self.safe_string_n(order, ['id', 'txid', 'amend_id'])
1793
+ if (id is None) or (id.startswith('[')):
1794
+ txid = self.safe_list(order, 'txid')
1566
1795
  id = self.safe_string(txid, 0)
1567
- clientOrderId = self.safe_string(order, 'userref')
1796
+ userref = self.safe_string(order, 'userref')
1797
+ clientOrderId = self.safe_string(order, 'cl_ord_id', userref)
1568
1798
  rawTrades = self.safe_value(order, 'trades', [])
1569
1799
  trades = []
1570
1800
  for i in range(0, len(rawTrades)):
@@ -1573,15 +1803,32 @@ class kraken(Exchange, ImplicitAPI):
1573
1803
  trades.append(self.safe_trade({'id': rawTrade, 'orderId': id, 'symbol': symbol, 'info': {}}))
1574
1804
  else:
1575
1805
  trades.append(rawTrade)
1576
- stopPrice = self.omit_zero(self.safe_string(order, 'stopprice', stopPrice))
1806
+ # in #24192 PR, self field is not something consistent/actual
1807
+ # triggerPrice = self.omit_zero(self.safe_string(order, 'stopprice', triggerPrice))
1577
1808
  stopLossPrice = None
1578
1809
  takeProfitPrice = None
1579
- if type.startswith('take-profit'):
1580
- takeProfitPrice = self.safe_string(description, 'price')
1581
- price = self.omit_zero(self.safe_string(description, 'price2'))
1582
- elif type.startswith('stop-loss'):
1583
- stopLossPrice = self.safe_string(description, 'price')
1584
- price = self.omit_zero(self.safe_string(description, 'price2'))
1810
+ # the dashed strings are not provided from fields(eg. fetch order)
1811
+ # while spaced strings from "order" sentence(when other fields not available)
1812
+ if rawType is not None:
1813
+ if rawType.startswith('take-profit'):
1814
+ takeProfitPrice = self.safe_string(description, 'price')
1815
+ price = self.omit_zero(self.safe_string(description, 'price2'))
1816
+ elif rawType.startswith('stop-loss'):
1817
+ stopLossPrice = self.safe_string(description, 'price')
1818
+ price = self.omit_zero(self.safe_string(description, 'price2'))
1819
+ elif rawType == 'take profit':
1820
+ takeProfitPrice = triggerPrice
1821
+ elif rawType == 'stop loss':
1822
+ stopLossPrice = triggerPrice
1823
+ finalType = self.parse_order_type(rawType)
1824
+ # unlike from endpoints which provide eg: "take-profit-limit"
1825
+ # for "space-delimited" orders we dont have market/limit suffixes, their format is
1826
+ # eg: `stop loss > limit 123`, so we need to parse them manually
1827
+ if self.in_array(finalType, ['stop loss', 'take profit']):
1828
+ finalType = 'market' if (price is None) else 'limit'
1829
+ amendId = self.safe_string(order, 'amend_id')
1830
+ if amendId is not None:
1831
+ isPostOnly = None
1585
1832
  return self.safe_order({
1586
1833
  'id': id,
1587
1834
  'clientOrderId': clientOrderId,
@@ -1591,13 +1838,12 @@ class kraken(Exchange, ImplicitAPI):
1591
1838
  'lastTradeTimestamp': None,
1592
1839
  'status': status,
1593
1840
  'symbol': symbol,
1594
- 'type': self.parse_order_type(type),
1841
+ 'type': finalType,
1595
1842
  'timeInForce': None,
1596
1843
  'postOnly': isPostOnly,
1597
1844
  'side': side,
1598
1845
  'price': price,
1599
- 'stopPrice': stopPrice,
1600
- 'triggerPrice': stopPrice,
1846
+ 'triggerPrice': triggerPrice,
1601
1847
  'takeProfitPrice': takeProfitPrice,
1602
1848
  'stopLossPrice': stopLossPrice,
1603
1849
  'cost': None,
@@ -1605,27 +1851,43 @@ class kraken(Exchange, ImplicitAPI):
1605
1851
  'filled': filled,
1606
1852
  'average': average,
1607
1853
  'remaining': None,
1854
+ 'reduceOnly': self.safe_bool_2(order, 'reduceOnly', 'reduce_only'),
1608
1855
  'fee': fee,
1609
1856
  'trades': trades,
1610
1857
  }, market)
1611
1858
 
1612
- def order_request(self, method, symbol, type, request, price=None, params={}):
1613
- clientOrderId = self.safe_string_2(params, 'userref', 'clientOrderId')
1614
- params = self.omit(params, ['userref', 'clientOrderId'])
1859
+ def order_request(self, method: str, symbol: str, type: str, request: dict, amount: Num, price: Num = None, params={}):
1860
+ clientOrderId = self.safe_string(params, 'clientOrderId')
1861
+ params = self.omit(params, ['clientOrderId'])
1615
1862
  if clientOrderId is not None:
1616
- request['userref'] = clientOrderId
1863
+ request['cl_ord_id'] = clientOrderId
1617
1864
  stopLossTriggerPrice = self.safe_string(params, 'stopLossPrice')
1618
1865
  takeProfitTriggerPrice = self.safe_string(params, 'takeProfitPrice')
1619
1866
  isStopLossTriggerOrder = stopLossTriggerPrice is not None
1620
1867
  isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
1621
1868
  isStopLossOrTakeProfitTrigger = isStopLossTriggerOrder or isTakeProfitTriggerOrder
1622
1869
  trailingAmount = self.safe_string(params, 'trailingAmount')
1870
+ trailingPercent = self.safe_string(params, 'trailingPercent')
1623
1871
  trailingLimitAmount = self.safe_string(params, 'trailingLimitAmount')
1872
+ trailingLimitPercent = self.safe_string(params, 'trailingLimitPercent')
1624
1873
  isTrailingAmountOrder = trailingAmount is not None
1874
+ isTrailingPercentOrder = trailingPercent is not None
1625
1875
  isLimitOrder = type.endswith('limit') # supporting limit, stop-loss-limit, take-profit-limit, etc
1626
- if isLimitOrder and not isTrailingAmountOrder:
1876
+ isMarketOrder = type == 'market'
1877
+ cost = self.safe_string(params, 'cost')
1878
+ flags = self.safe_string(params, 'oflags')
1879
+ params = self.omit(params, ['cost', 'oflags'])
1880
+ isViqcOrder = (flags is not None) and (flags.find('viqc') > -1) # volume in quote currency
1881
+ if isMarketOrder and (cost is not None or isViqcOrder):
1882
+ if cost is None and (amount is not None):
1883
+ request['volume'] = self.cost_to_precision(symbol, self.number_to_string(amount))
1884
+ else:
1885
+ request['volume'] = self.cost_to_precision(symbol, cost)
1886
+ extendedOflags = flags + ',viqc' if (flags is not None) else 'viqc'
1887
+ request['oflags'] = extendedOflags
1888
+ elif isLimitOrder and not isTrailingAmountOrder and not isTrailingPercentOrder:
1627
1889
  request['price'] = self.price_to_precision(symbol, price)
1628
- reduceOnly = self.safe_value_2(params, 'reduceOnly', 'reduce_only')
1890
+ reduceOnly = self.safe_bool_2(params, 'reduceOnly', 'reduce_only')
1629
1891
  if isStopLossOrTakeProfitTrigger:
1630
1892
  if isStopLossTriggerOrder:
1631
1893
  request['price'] = self.price_to_precision(symbol, stopLossTriggerPrice)
@@ -1641,22 +1903,36 @@ class kraken(Exchange, ImplicitAPI):
1641
1903
  request['ordertype'] = 'take-profit'
1642
1904
  if isLimitOrder:
1643
1905
  request['price2'] = self.price_to_precision(symbol, price)
1644
- elif isTrailingAmountOrder:
1906
+ elif isTrailingAmountOrder or isTrailingPercentOrder:
1907
+ trailingPercentString = None
1908
+ if trailingPercent is not None:
1909
+ trailingPercentString = ('+' + trailingPercent) if (trailingPercent.endswith('%')) else ('+' + trailingPercent + '%')
1910
+ trailingAmountString = '+' + trailingAmount if (trailingAmount is not None) else None # must use + for self
1911
+ offset = self.safe_string(params, 'offset', '-') # can use + or - for self
1912
+ trailingLimitAmountString = offset + self.number_to_string(trailingLimitAmount) if (trailingLimitAmount is not None) else None
1645
1913
  trailingActivationPriceType = self.safe_string(params, 'trigger', 'last')
1646
- trailingAmountString = '+' + trailingAmount
1647
1914
  request['trigger'] = trailingActivationPriceType
1648
- if isLimitOrder or (trailingLimitAmount is not None):
1649
- offset = self.safe_string(params, 'offset', '-')
1650
- trailingLimitAmountString = offset + self.number_to_string(trailingLimitAmount)
1651
- request['price'] = trailingAmountString
1652
- request['price2'] = trailingLimitAmountString
1915
+ if isLimitOrder or (trailingLimitAmount is not None) or (trailingLimitPercent is not None):
1653
1916
  request['ordertype'] = 'trailing-stop-limit'
1917
+ if trailingLimitPercent is not None:
1918
+ trailingLimitPercentString = (offset + trailingLimitPercent) if (trailingLimitPercent.endswith('%')) else (offset + trailingLimitPercent + '%')
1919
+ request['price'] = trailingPercentString
1920
+ request['price2'] = trailingLimitPercentString
1921
+ elif trailingLimitAmount is not None:
1922
+ request['price'] = trailingAmountString
1923
+ request['price2'] = trailingLimitAmountString
1654
1924
  else:
1655
- request['price'] = trailingAmountString
1656
1925
  request['ordertype'] = 'trailing-stop'
1926
+ if trailingPercent is not None:
1927
+ request['price'] = trailingPercentString
1928
+ else:
1929
+ request['price'] = trailingAmountString
1657
1930
  if reduceOnly:
1658
- request['reduce_only'] = 'true' # not using hasattr(self, boolean) case, because the urlencodedNested transforms it into 'True' string
1659
- close = self.safe_value(params, 'close')
1931
+ if method == 'createOrderWs':
1932
+ request['reduce_only'] = True # ws request can't have stringified bool
1933
+ else:
1934
+ request['reduce_only'] = 'true' # not using hasattr(self, boolean) case, because the urlencodedNested transforms it into 'True' string
1935
+ close = self.safe_dict(params, 'close')
1660
1936
  if close is not None:
1661
1937
  close = self.extend({}, close)
1662
1938
  closePrice = self.safe_value(close, 'price')
@@ -1673,81 +1949,101 @@ class kraken(Exchange, ImplicitAPI):
1673
1949
  postOnly = None
1674
1950
  postOnly, params = self.handle_post_only(isMarket, False, params)
1675
1951
  if postOnly:
1676
- request['oflags'] = 'post'
1677
- params = self.omit(params, ['timeInForce', 'reduceOnly', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingLimitAmount', 'offset'])
1952
+ extendedPostFlags = flags + ',post' if (flags is not None) else 'post'
1953
+ request['oflags'] = extendedPostFlags
1954
+ if (flags is not None) and not ('oflags' in request):
1955
+ request['oflags'] = flags
1956
+ params = self.omit(params, ['timeInForce', 'reduceOnly', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingLimitAmount', 'trailingLimitPercent', 'offset'])
1678
1957
  return [request, params]
1679
1958
 
1680
1959
  def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
1681
1960
  """
1682
1961
  edit a trade order
1683
- :see: https://docs.kraken.com/rest/#tag/Trading/operation/editOrder
1962
+
1963
+ https://docs.kraken.com/api/docs/rest-api/amend-order
1964
+
1684
1965
  :param str id: order id
1685
1966
  :param str symbol: unified symbol of the market to create an order in
1686
1967
  :param str type: 'market' or 'limit'
1687
1968
  :param str side: 'buy' or 'sell'
1688
- :param float amount: how much of the currency you want to trade in units of the base currency
1689
- :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1969
+ :param float [amount]: how much of the currency you want to trade in units of the base currency
1970
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1690
1971
  :param dict [params]: extra parameters specific to the exchange API endpoint
1691
- :param float [params.stopLossPrice]: *margin only* the price that a stop loss order is triggered at
1692
- :param float [params.takeProfitPrice]: *margin only* the price that a take profit order is triggered at
1693
- :param str [params.trailingAmount]: *margin only* the quote price away from the current market price
1694
- :param str [params.trailingLimitAmount]: *margin only* the quote amount away from the trailingAmount
1695
- :param str [params.offset]: *margin only* '+' or '-' whether you want the trailingLimitAmount value to be positive or negative, default is negative '-'
1696
- :param str [params.trigger]: *margin only* the activation price type, 'last' or 'index', default is 'last'
1972
+ :param float [params.stopLossPrice]: the price that a stop loss order is triggered at
1973
+ :param float [params.takeProfitPrice]: the price that a take profit order is triggered at
1974
+ :param str [params.trailingAmount]: the quote amount to trail away from the current market price
1975
+ :param str [params.trailingPercent]: the percent to trail away from the current market price
1976
+ :param str [params.trailingLimitAmount]: the quote amount away from the trailingAmount
1977
+ :param str [params.trailingLimitPercent]: the percent away from the trailingAmount
1978
+ :param str [params.offset]: '+' or '-' whether you want the trailingLimitAmount value to be positive or negative
1979
+ :param boolean [params.postOnly]: if True, the order will only be posted to the order book and not executed immediately
1980
+ :param str [params.clientOrderId]: the orders client order id
1697
1981
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1698
1982
  """
1699
1983
  self.load_markets()
1700
1984
  market = self.market(symbol)
1701
1985
  if not market['spot']:
1702
1986
  raise NotSupported(self.id + ' editOrder() does not support ' + market['type'] + ' orders, only spot orders are accepted')
1703
- request = {
1987
+ request: dict = {
1704
1988
  'txid': id,
1705
- 'pair': market['id'],
1706
1989
  }
1990
+ clientOrderId = self.safe_string_2(params, 'clientOrderId', 'cl_ord_id')
1991
+ if clientOrderId is not None:
1992
+ request['cl_ord_id'] = clientOrderId
1993
+ params = self.omit(params, ['clientOrderId', 'cl_ord_id'])
1994
+ request = self.omit(request, 'txid')
1995
+ isMarket = (type == 'market')
1996
+ postOnly = None
1997
+ postOnly, params = self.handle_post_only(isMarket, False, params)
1998
+ if postOnly:
1999
+ request['post_only'] = 'true' # not using hasattr(self, boolean) case, because the urlencodedNested transforms it into 'True' string
1707
2000
  if amount is not None:
1708
- request['volume'] = self.amount_to_precision(symbol, amount)
1709
- orderRequest = self.order_request('editOrder()', symbol, type, request, price, params)
1710
- response = self.privatePostEditOrder(self.extend(orderRequest[0], orderRequest[1]))
2001
+ request['order_qty'] = self.amount_to_precision(symbol, amount)
2002
+ if price is not None:
2003
+ request['limit_price'] = self.price_to_precision(symbol, price)
2004
+ allTriggerPrices = self.safe_string_n(params, ['stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingLimitAmount', 'trailingLimitPercent'])
2005
+ if allTriggerPrices is not None:
2006
+ offset = self.safe_string(params, 'offset')
2007
+ params = self.omit(params, ['stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingLimitAmount', 'trailingLimitPercent', 'offset'])
2008
+ if offset is not None:
2009
+ allTriggerPrices = offset + allTriggerPrices
2010
+ request['trigger_price'] = allTriggerPrices
2011
+ else:
2012
+ request['trigger_price'] = self.price_to_precision(symbol, allTriggerPrices)
2013
+ response = self.privatePostAmendOrder(self.extend(request, params))
1711
2014
  #
1712
2015
  # {
1713
2016
  # "error": [],
1714
2017
  # "result": {
1715
- # "status": "ok",
1716
- # "txid": "OAW2BO-7RWEK-PZY5UO",
1717
- # "originaltxid": "OXL6SS-UPNMC-26WBE7",
1718
- # "volume": "0.00075000",
1719
- # "price": "13500.0",
1720
- # "orders_cancelled": 1,
1721
- # "descr": {
1722
- # "order": "buy 0.00075000 XBTUSDT @ limit 13500.0"
1723
- # }
2018
+ # "amend_id": "TJSMEH-AA67V-YUSQ6O"
1724
2019
  # }
1725
2020
  # }
1726
2021
  #
1727
- data = self.safe_value(response, 'result', {})
1728
- return self.parse_order(data, market)
2022
+ result = self.safe_dict(response, 'result', {})
2023
+ return self.parse_order(result, market)
1729
2024
 
1730
2025
  def fetch_order(self, id: str, symbol: Str = None, params={}):
1731
2026
  """
1732
2027
  fetches information on an order made by the user
1733
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getOrdersInfo
2028
+
2029
+ https://docs.kraken.com/rest/#tag/Account-Data/operation/getOrdersInfo
2030
+
2031
+ :param str id: order id
1734
2032
  :param str symbol: not used by kraken fetchOrder
1735
2033
  :param dict [params]: extra parameters specific to the exchange API endpoint
1736
2034
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1737
2035
  """
1738
2036
  self.load_markets()
1739
2037
  clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId')
1740
- request = {
2038
+ request: dict = {
1741
2039
  'trades': True, # whether or not to include trades in output(optional, default False)
1742
- # 'txid': id, # do not comma separate a list of ids - use fetchOrdersByIds instead
2040
+ 'txid': id, # do not comma separate a list of ids - use fetchOrdersByIds instead
1743
2041
  # 'userref': 'optional', # restrict results to given user reference id(optional)
1744
2042
  }
1745
2043
  query = params
1746
2044
  if clientOrderId is not None:
1747
2045
  request['userref'] = clientOrderId
1748
2046
  query = self.omit(params, ['userref', 'clientOrderId'])
1749
- else:
1750
- request['txid'] = id
1751
2047
  response = self.privatePostQueryOrders(self.extend(request, query))
1752
2048
  #
1753
2049
  # {
@@ -1794,7 +2090,9 @@ class kraken(Exchange, ImplicitAPI):
1794
2090
  def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1795
2091
  """
1796
2092
  fetch all the trades made from a single order
1797
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradesInfo
2093
+
2094
+ https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradesInfo
2095
+
1798
2096
  :param str id: order id
1799
2097
  :param str symbol: unified market symbol
1800
2098
  :param int [since]: the earliest time in ms to fetch trades for
@@ -1828,7 +2126,7 @@ class kraken(Exchange, ImplicitAPI):
1828
2126
  index = self.sum(j * batchSize, k)
1829
2127
  if index < numTradeIds:
1830
2128
  requestIds.append(tradeIds[index])
1831
- request = {
2129
+ request: dict = {
1832
2130
  'txid': ','.join(requestIds),
1833
2131
  }
1834
2132
  response = self.privatePostQueryTrades(request)
@@ -1865,8 +2163,11 @@ class kraken(Exchange, ImplicitAPI):
1865
2163
  def fetch_orders_by_ids(self, ids, symbol: Str = None, params={}):
1866
2164
  """
1867
2165
  fetch orders by the list of order id
1868
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getClosedOrders
1869
- :param str[]|None ids: list of order id
2166
+
2167
+ https://docs.kraken.com/rest/#tag/Account-Data/operation/getClosedOrders
2168
+
2169
+ :param str[] [ids]: list of order id
2170
+ :param str [symbol]: unified ccxt market symbol
1870
2171
  :param dict [params]: extra parameters specific to the kraken api endpoint
1871
2172
  :returns dict[]: a list of `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1872
2173
  """
@@ -1888,15 +2189,19 @@ class kraken(Exchange, ImplicitAPI):
1888
2189
  def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1889
2190
  """
1890
2191
  fetch all trades made by the user
1891
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradeHistory
2192
+
2193
+ https://docs.kraken.com/api/docs/rest-api/get-trade-history
2194
+
1892
2195
  :param str symbol: unified market symbol
1893
2196
  :param int [since]: the earliest time in ms to fetch trades for
1894
2197
  :param int [limit]: the maximum number of trades structures to retrieve
1895
2198
  :param dict [params]: extra parameters specific to the exchange API endpoint
2199
+ :param int [params.until]: timestamp in ms of the latest trade entry
2200
+ :param int [params.end]: timestamp in seconds of the latest trade entry
1896
2201
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1897
2202
  """
1898
2203
  self.load_markets()
1899
- request = {
2204
+ request: dict = {
1900
2205
  # 'type': 'all', # any position, closed position, closing position, no position
1901
2206
  # 'trades': False, # whether or not to include trades related to position in output
1902
2207
  # 'start': 1234567890, # starting unix timestamp or trade tx id of results(exclusive)
@@ -1905,6 +2210,11 @@ class kraken(Exchange, ImplicitAPI):
1905
2210
  }
1906
2211
  if since is not None:
1907
2212
  request['start'] = self.parse_to_int(since / 1000)
2213
+ until = self.safe_string_n(params, ['until', 'till'])
2214
+ if until is not None:
2215
+ params = self.omit(params, ['until', 'till'])
2216
+ untilDivided = Precise.string_div(until, '1000')
2217
+ request['end'] = self.parse_to_int(Precise.string_add(untilDivided, '1'))
1908
2218
  response = self.privatePostTradesHistory(self.extend(request, params))
1909
2219
  #
1910
2220
  # {
@@ -1923,7 +2233,10 @@ class kraken(Exchange, ImplicitAPI):
1923
2233
  # "fee": "0.000026",
1924
2234
  # "vol": "16.00000000",
1925
2235
  # "margin": "0.000000",
2236
+ # "leverage": "5",
1926
2237
  # "misc": ""
2238
+ # "trade_id": 68230622,
2239
+ # "maker": False
1927
2240
  # },
1928
2241
  # ...
1929
2242
  # },
@@ -1943,38 +2256,59 @@ class kraken(Exchange, ImplicitAPI):
1943
2256
  def cancel_order(self, id: str, symbol: Str = None, params={}):
1944
2257
  """
1945
2258
  cancels an open order
1946
- :see: https://docs.kraken.com/rest/#tag/Trading/operation/cancelOrder
2259
+
2260
+ https://docs.kraken.com/api/docs/rest-api/cancel-order
2261
+
1947
2262
  :param str id: order id
1948
- :param str symbol: unified symbol of the market the order was made in
2263
+ :param str [symbol]: unified symbol of the market the order was made in
1949
2264
  :param dict [params]: extra parameters specific to the exchange API endpoint
1950
- :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2265
+ :param str [params.clientOrderId]: the orders client order id
2266
+ :param int [params.userref]: the orders user reference id
2267
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1951
2268
  """
1952
2269
  self.load_markets()
1953
2270
  response = None
1954
- clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId', id)
1955
- request = {
1956
- 'txid': clientOrderId, # order id or userref
2271
+ requestId = self.safe_value(params, 'userref', id) # string or integer
2272
+ params = self.omit(params, 'userref')
2273
+ request: dict = {
2274
+ 'txid': requestId, # order id or userref
1957
2275
  }
1958
- params = self.omit(params, ['userref', 'clientOrderId'])
2276
+ clientOrderId = self.safe_string_2(params, 'clientOrderId', 'cl_ord_id')
2277
+ if clientOrderId is not None:
2278
+ request['cl_ord_id'] = clientOrderId
2279
+ params = self.omit(params, ['clientOrderId', 'cl_ord_id'])
2280
+ request = self.omit(request, 'txid')
1959
2281
  try:
1960
2282
  response = self.privatePostCancelOrder(self.extend(request, params))
2283
+ #
2284
+ # {
2285
+ # error: [],
2286
+ # result: {
2287
+ # count: '1'
2288
+ # }
2289
+ # }
2290
+ #
1961
2291
  except Exception as e:
1962
2292
  if self.last_http_response:
1963
2293
  if self.last_http_response.find('EOrder:Unknown order') >= 0:
1964
2294
  raise OrderNotFound(self.id + ' cancelOrder() error ' + self.last_http_response)
1965
2295
  raise e
1966
- return response
2296
+ return self.safe_order({
2297
+ 'info': response,
2298
+ })
1967
2299
 
1968
2300
  def cancel_orders(self, ids, symbol: Str = None, params={}):
1969
2301
  """
1970
2302
  cancel multiple orders
1971
- :see: https://docs.kraken.com/rest/#tag/Trading/operation/cancelOrderBatch
2303
+
2304
+ https://docs.kraken.com/rest/#tag/Spot-Trading/operation/cancelOrderBatch
2305
+
1972
2306
  :param str[] ids: open orders transaction ID(txid) or user reference(userref)
1973
2307
  :param str symbol: unified market symbol
1974
2308
  :param dict [params]: extra parameters specific to the exchange API endpoint
1975
2309
  :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1976
2310
  """
1977
- request = {
2311
+ request: dict = {
1978
2312
  'orders': ids,
1979
2313
  }
1980
2314
  response = self.privatePostCancelOrderBatch(self.extend(request, params))
@@ -1986,68 +2320,172 @@ class kraken(Exchange, ImplicitAPI):
1986
2320
  # }
1987
2321
  # }
1988
2322
  #
1989
- return response
2323
+ return [
2324
+ self.safe_order({
2325
+ 'info': response,
2326
+ }),
2327
+ ]
1990
2328
 
1991
2329
  def cancel_all_orders(self, symbol: Str = None, params={}):
1992
2330
  """
1993
2331
  cancel all open orders
1994
- :see: https://docs.kraken.com/rest/#tag/Trading/operation/cancelAllOrders
2332
+
2333
+ https://docs.kraken.com/rest/#tag/Spot-Trading/operation/cancelAllOrders
2334
+
1995
2335
  :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
1996
2336
  :param dict [params]: extra parameters specific to the exchange API endpoint
1997
2337
  :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1998
2338
  """
1999
2339
  self.load_markets()
2000
- return self.privatePostCancelAll(params)
2340
+ response = self.privatePostCancelAll(params)
2341
+ #
2342
+ # {
2343
+ # error: [],
2344
+ # result: {
2345
+ # count: '1'
2346
+ # }
2347
+ # }
2348
+ #
2349
+ return [
2350
+ self.safe_order({
2351
+ 'info': response,
2352
+ }),
2353
+ ]
2354
+
2355
+ def cancel_all_orders_after(self, timeout: Int, params={}):
2356
+ """
2357
+ dead man's switch, cancel all orders after the given timeout
2358
+
2359
+ https://docs.kraken.com/rest/#tag/Spot-Trading/operation/cancelAllOrdersAfter
2360
+
2361
+ :param number timeout: time in milliseconds, 0 represents cancel the timer
2362
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2363
+ :returns dict: the api result
2364
+ """
2365
+ if timeout > 86400000:
2366
+ raise BadRequest(self.id + 'cancelAllOrdersAfter timeout should be less than 86400000 milliseconds')
2367
+ self.load_markets()
2368
+ request: dict = {
2369
+ 'timeout': (self.parse_to_int(timeout / 1000)) if (timeout > 0) else 0,
2370
+ }
2371
+ response = self.privatePostCancelAllOrdersAfter(self.extend(request, params))
2372
+ #
2373
+ # {
2374
+ # "error": [],
2375
+ # "result": {
2376
+ # "currentTime": "2023-03-24T17:41:56Z",
2377
+ # "triggerTime": "2023-03-24T17:42:56Z"
2378
+ # }
2379
+ # }
2380
+ #
2381
+ return response
2001
2382
 
2002
2383
  def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2003
2384
  """
2004
2385
  fetch all unfilled currently open orders
2005
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getOpenOrders
2006
- :param str symbol: unified market symbol
2386
+
2387
+ https://docs.kraken.com/api/docs/rest-api/get-open-orders
2388
+
2389
+ :param str [symbol]: unified market symbol
2007
2390
  :param int [since]: the earliest time in ms to fetch open orders for
2008
2391
  :param int [limit]: the maximum number of open orders structures to retrieve
2009
2392
  :param dict [params]: extra parameters specific to the exchange API endpoint
2393
+ :param str [params.clientOrderId]: the orders client order id
2394
+ :param int [params.userref]: the orders user reference id
2010
2395
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2011
2396
  """
2012
2397
  self.load_markets()
2013
- request = {}
2398
+ request: dict = {}
2014
2399
  if since is not None:
2015
2400
  request['start'] = self.parse_to_int(since / 1000)
2016
- query = params
2017
- clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId')
2401
+ userref = self.safe_integer(params, 'userref')
2402
+ if userref is not None:
2403
+ request['userref'] = userref
2404
+ params = self.omit(params, 'userref')
2405
+ clientOrderId = self.safe_string(params, 'clientOrderId')
2018
2406
  if clientOrderId is not None:
2019
- request['userref'] = clientOrderId
2020
- query = self.omit(params, ['userref', 'clientOrderId'])
2021
- response = self.privatePostOpenOrders(self.extend(request, query))
2407
+ request['cl_ord_id'] = clientOrderId
2408
+ params = self.omit(params, 'clientOrderId')
2409
+ response = self.privatePostOpenOrders(self.extend(request, params))
2410
+ #
2411
+ # {
2412
+ # "error": [],
2413
+ # "result": {
2414
+ # "open": {
2415
+ # "O45M52-BFD5S-YXKQOU": {
2416
+ # "refid": null,
2417
+ # "userref": null,
2418
+ # "cl_ord_id": "1234",
2419
+ # "status": "open",
2420
+ # "opentm": 1733815269.370054,
2421
+ # "starttm": 0,
2422
+ # "expiretm": 0,
2423
+ # "descr": {
2424
+ # "pair": "XBTUSD",
2425
+ # "type": "buy",
2426
+ # "ordertype": "limit",
2427
+ # "price": "70000.0",
2428
+ # "price2": "0",
2429
+ # "leverage": "none",
2430
+ # "order": "buy 0.00010000 XBTUSD @ limit 70000.0",
2431
+ # "close": ""
2432
+ # },
2433
+ # "vol": "0.00010000",
2434
+ # "vol_exec": "0.00000000",
2435
+ # "cost": "0.00000",
2436
+ # "fee": "0.00000",
2437
+ # "price": "0.00000",
2438
+ # "stopprice": "0.00000",
2439
+ # "limitprice": "0.00000",
2440
+ # "misc": "",
2441
+ # "oflags": "fciq"
2442
+ # }
2443
+ # }
2444
+ # }
2445
+ # }
2446
+ #
2022
2447
  market = None
2023
2448
  if symbol is not None:
2024
2449
  market = self.market(symbol)
2025
- result = self.safe_value(response, 'result', {})
2026
- orders = self.safe_value(result, 'open', [])
2450
+ result = self.safe_dict(response, 'result', {})
2451
+ open = self.safe_dict(result, 'open', {})
2452
+ orders = []
2453
+ orderIds = list(open.keys())
2454
+ for i in range(0, len(orderIds)):
2455
+ id = orderIds[i]
2456
+ item = open[id]
2457
+ orders.append(self.extend({'id': id}, item))
2027
2458
  return self.parse_orders(orders, market, since, limit)
2028
2459
 
2029
2460
  def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2030
2461
  """
2031
2462
  fetches information on multiple closed orders made by the user
2032
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getClosedOrders
2033
- :param str symbol: unified market symbol of the market orders were made in
2463
+
2464
+ https://docs.kraken.com/api/docs/rest-api/get-closed-orders
2465
+
2466
+ :param str [symbol]: unified market symbol of the market orders were made in
2034
2467
  :param int [since]: the earliest time in ms to fetch orders for
2035
2468
  :param int [limit]: the maximum number of order structures to retrieve
2036
2469
  :param dict [params]: extra parameters specific to the exchange API endpoint
2037
2470
  :param int [params.until]: timestamp in ms of the latest entry
2471
+ :param str [params.clientOrderId]: the orders client order id
2472
+ :param int [params.userref]: the orders user reference id
2038
2473
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2039
2474
  """
2040
2475
  self.load_markets()
2041
- request = {}
2476
+ request: dict = {}
2042
2477
  if since is not None:
2043
2478
  request['start'] = self.parse_to_int(since / 1000)
2044
- query = params
2045
- clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId')
2479
+ userref = self.safe_integer(params, 'userref')
2480
+ if userref is not None:
2481
+ request['userref'] = userref
2482
+ params = self.omit(params, 'userref')
2483
+ clientOrderId = self.safe_string(params, 'clientOrderId')
2046
2484
  if clientOrderId is not None:
2047
- request['userref'] = clientOrderId
2048
- query = self.omit(params, ['userref', 'clientOrderId'])
2485
+ request['cl_ord_id'] = clientOrderId
2486
+ params = self.omit(params, 'clientOrderId')
2049
2487
  request, params = self.handle_until_option('end', request, params)
2050
- response = self.privatePostClosedOrders(self.extend(request, query))
2488
+ response = self.privatePostClosedOrders(self.extend(request, params))
2051
2489
  #
2052
2490
  # {
2053
2491
  # "error":[],
@@ -2090,13 +2528,19 @@ class kraken(Exchange, ImplicitAPI):
2090
2528
  market = None
2091
2529
  if symbol is not None:
2092
2530
  market = self.market(symbol)
2093
- result = self.safe_value(response, 'result', {})
2094
- orders = self.safe_value(result, 'closed', [])
2531
+ result = self.safe_dict(response, 'result', {})
2532
+ closed = self.safe_dict(result, 'closed', {})
2533
+ orders = []
2534
+ orderIds = list(closed.keys())
2535
+ for i in range(0, len(orderIds)):
2536
+ id = orderIds[i]
2537
+ item = closed[id]
2538
+ orders.append(self.extend({'id': id}, item))
2095
2539
  return self.parse_orders(orders, market, since, limit)
2096
2540
 
2097
- def parse_transaction_status(self, status):
2541
+ def parse_transaction_status(self, status: Str):
2098
2542
  # IFEX transaction states
2099
- statuses = {
2543
+ statuses: dict = {
2100
2544
  'Initial': 'pending',
2101
2545
  'Pending': 'pending',
2102
2546
  'Success': 'ok',
@@ -2110,7 +2554,7 @@ class kraken(Exchange, ImplicitAPI):
2110
2554
  withdrawMethods = self.safe_value(self.options, 'withdrawMethods', {})
2111
2555
  return self.safe_string(withdrawMethods, network, network)
2112
2556
 
2113
- def parse_transaction(self, transaction, currency: Currency = None) -> Transaction:
2557
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
2114
2558
  #
2115
2559
  # fetchDeposits
2116
2560
  #
@@ -2228,23 +2672,31 @@ class kraken(Exchange, ImplicitAPI):
2228
2672
  def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2229
2673
  """
2230
2674
  fetch all deposits made to an account
2231
- :see: https://docs.kraken.com/rest/#tag/Funding/operation/getStatusRecentDeposits
2675
+
2676
+ https://docs.kraken.com/rest/#tag/Funding/operation/getStatusRecentDeposits
2677
+
2232
2678
  :param str code: unified currency code
2233
2679
  :param int [since]: the earliest time in ms to fetch deposits for
2234
2680
  :param int [limit]: the maximum number of deposits structures to retrieve
2235
2681
  :param dict [params]: extra parameters specific to the exchange API endpoint
2682
+ :param int [params.until]: timestamp in ms of the latest transaction entry
2683
+ :param int [params.end]: timestamp in seconds of the latest transaction entry
2236
2684
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2237
2685
  """
2238
2686
  # https://www.kraken.com/en-us/help/api#deposit-status
2239
- if code is None:
2240
- raise ArgumentsRequired(self.id + ' fetchDeposits() requires a currency code argument')
2241
2687
  self.load_markets()
2242
- currency = self.currency(code)
2243
- request = {
2244
- 'asset': currency['id'],
2245
- }
2688
+ request: dict = {}
2689
+ if code is not None:
2690
+ currency = self.currency(code)
2691
+ request['asset'] = currency['id']
2246
2692
  if since is not None:
2247
- request['start'] = since
2693
+ sinceString = self.number_to_string(since)
2694
+ request['start'] = Precise.string_div(sinceString, '1000')
2695
+ until = self.safe_string_n(params, ['until', 'till'])
2696
+ if until is not None:
2697
+ params = self.omit(params, ['until', 'till'])
2698
+ untilDivided = Precise.string_div(until, '1000')
2699
+ request['end'] = Precise.string_add(untilDivided, '1')
2248
2700
  response = self.privatePostDepositStatus(self.extend(request, params))
2249
2701
  #
2250
2702
  # { error: [],
@@ -2264,7 +2716,9 @@ class kraken(Exchange, ImplicitAPI):
2264
2716
  def fetch_time(self, params={}):
2265
2717
  """
2266
2718
  fetches the current integer timestamp in milliseconds from the exchange server
2267
- :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getServerTime
2719
+
2720
+ https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getServerTime
2721
+
2268
2722
  :param dict [params]: extra parameters specific to the exchange API endpoint
2269
2723
  :returns int: the current integer timestamp in milliseconds from the exchange server
2270
2724
  """
@@ -2285,13 +2739,16 @@ class kraken(Exchange, ImplicitAPI):
2285
2739
  def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2286
2740
  """
2287
2741
  fetch all withdrawals made from an account
2288
- :see: https://docs.kraken.com/rest/#tag/Funding/operation/getStatusRecentWithdrawals
2742
+
2743
+ https://docs.kraken.com/rest/#tag/Funding/operation/getStatusRecentWithdrawals
2744
+
2289
2745
  :param str code: unified currency code
2290
2746
  :param int [since]: the earliest time in ms to fetch withdrawals for
2291
2747
  :param int [limit]: the maximum number of withdrawals structures to retrieve
2292
2748
  :param dict [params]: extra parameters specific to the exchange API endpoint
2293
- :param dict [params.end]: End timestamp, withdrawals created strictly after will be not be included in the response
2294
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times
2749
+ :param int [params.until]: timestamp in ms of the latest transaction entry
2750
+ :param int [params.end]: timestamp in seconds of the latest transaction entry
2751
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times
2295
2752
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2296
2753
  """
2297
2754
  self.load_markets()
@@ -2300,12 +2757,18 @@ class kraken(Exchange, ImplicitAPI):
2300
2757
  if paginate:
2301
2758
  params['cursor'] = True
2302
2759
  return self.fetch_paginated_call_cursor('fetchWithdrawals', code, since, limit, params, 'next_cursor', 'cursor')
2303
- request = {}
2760
+ request: dict = {}
2304
2761
  if code is not None:
2305
2762
  currency = self.currency(code)
2306
2763
  request['asset'] = currency['id']
2307
2764
  if since is not None:
2308
- request['since'] = str(since)
2765
+ sinceString = self.number_to_string(since)
2766
+ request['start'] = Precise.string_div(sinceString, '1000')
2767
+ until = self.safe_string_n(params, ['until', 'till'])
2768
+ if until is not None:
2769
+ params = self.omit(params, ['until', 'till'])
2770
+ untilDivided = Precise.string_div(until, '1000')
2771
+ request['end'] = Precise.string_add(untilDivided, '1')
2309
2772
  response = self.privatePostWithdrawStatus(self.extend(request, params))
2310
2773
  #
2311
2774
  # with no pagination
@@ -2366,12 +2829,14 @@ class kraken(Exchange, ImplicitAPI):
2366
2829
  def create_deposit_address(self, code: str, params={}):
2367
2830
  """
2368
2831
  create a currency deposit address
2369
- :see: https://docs.kraken.com/rest/#tag/Funding/operation/getDepositAddresses
2832
+
2833
+ https://docs.kraken.com/rest/#tag/Funding/operation/getDepositAddresses
2834
+
2370
2835
  :param str code: unified currency code of the currency for the deposit address
2371
2836
  :param dict [params]: extra parameters specific to the exchange API endpoint
2372
2837
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
2373
2838
  """
2374
- request = {
2839
+ request: dict = {
2375
2840
  'new': 'true',
2376
2841
  }
2377
2842
  return self.fetch_deposit_address(code, self.extend(request, params))
@@ -2379,14 +2844,16 @@ class kraken(Exchange, ImplicitAPI):
2379
2844
  def fetch_deposit_methods(self, code: str, params={}):
2380
2845
  """
2381
2846
  fetch deposit methods for a currency associated with self account
2382
- :see: https://docs.kraken.com/rest/#tag/Funding/operation/getDepositMethods
2847
+
2848
+ https://docs.kraken.com/rest/#tag/Funding/operation/getDepositMethods
2849
+
2383
2850
  :param str code: unified currency code
2384
2851
  :param dict [params]: extra parameters specific to the kraken api endpoint
2385
2852
  :returns dict: of deposit methods
2386
2853
  """
2387
2854
  self.load_markets()
2388
2855
  currency = self.currency(code)
2389
- request = {
2856
+ request: dict = {
2390
2857
  'asset': currency['id'],
2391
2858
  }
2392
2859
  response = self.privatePostDepositMethods(self.extend(request, params))
@@ -2415,10 +2882,12 @@ class kraken(Exchange, ImplicitAPI):
2415
2882
  #
2416
2883
  return self.safe_value(response, 'result')
2417
2884
 
2418
- def fetch_deposit_address(self, code: str, params={}):
2885
+ def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
2419
2886
  """
2420
2887
  fetch the deposit address for a currency associated with self account
2421
- :see: https://docs.kraken.com/rest/#tag/Funding/operation/getDepositAddresses
2888
+
2889
+ https://docs.kraken.com/rest/#tag/Funding/operation/getDepositAddresses
2890
+
2422
2891
  :param str code: unified currency code
2423
2892
  :param dict [params]: extra parameters specific to the exchange API endpoint
2424
2893
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
@@ -2449,7 +2918,7 @@ class kraken(Exchange, ImplicitAPI):
2449
2918
  if depositMethod is None:
2450
2919
  firstDepositMethod = self.safe_value(depositMethods, 0, {})
2451
2920
  depositMethod = self.safe_string(firstDepositMethod, 'method')
2452
- request = {
2921
+ request: dict = {
2453
2922
  'asset': currency['id'],
2454
2923
  'method': depositMethod,
2455
2924
  }
@@ -2468,7 +2937,7 @@ class kraken(Exchange, ImplicitAPI):
2468
2937
  raise InvalidAddress(self.id + ' privatePostDepositAddresses() returned no addresses for ' + code)
2469
2938
  return self.parse_deposit_address(firstResult, currency)
2470
2939
 
2471
- def parse_deposit_address(self, depositAddress, currency: Currency = None):
2940
+ def parse_deposit_address(self, depositAddress, currency: Currency = None) -> DepositAddress:
2472
2941
  #
2473
2942
  # {
2474
2943
  # "address":"0x77b5051f97efa9cc52c9ad5b023a53fc15c200d3",
@@ -2481,17 +2950,19 @@ class kraken(Exchange, ImplicitAPI):
2481
2950
  code = currency['code']
2482
2951
  self.check_address(address)
2483
2952
  return {
2953
+ 'info': depositAddress,
2484
2954
  'currency': code,
2955
+ 'network': None,
2485
2956
  'address': address,
2486
2957
  'tag': tag,
2487
- 'network': None,
2488
- 'info': depositAddress,
2489
2958
  }
2490
2959
 
2491
- def withdraw(self, code: str, amount: float, address, tag=None, params={}):
2960
+ def withdraw(self, code: str, amount: float, address: str, tag=None, params={}) -> Transaction:
2492
2961
  """
2493
2962
  make a withdrawal
2494
- :see: https://docs.kraken.com/rest/#tag/Funding/operation/withdrawFunds
2963
+
2964
+ https://docs.kraken.com/rest/#tag/Funding/operation/withdrawFunds
2965
+
2495
2966
  :param str code: unified currency code
2496
2967
  :param float amount: the amount to withdraw
2497
2968
  :param str address: the address to withdraw to
@@ -2504,7 +2975,7 @@ class kraken(Exchange, ImplicitAPI):
2504
2975
  if 'key' in params:
2505
2976
  self.load_markets()
2506
2977
  currency = self.currency(code)
2507
- request = {
2978
+ request: dict = {
2508
2979
  'asset': currency['id'],
2509
2980
  'amount': amount,
2510
2981
  'address': address,
@@ -2518,23 +2989,25 @@ class kraken(Exchange, ImplicitAPI):
2518
2989
  # }
2519
2990
  # }
2520
2991
  #
2521
- result = self.safe_value(response, 'result', {})
2992
+ result = self.safe_dict(response, 'result', {})
2522
2993
  return self.parse_transaction(result, currency)
2523
2994
  raise ExchangeError(self.id + " withdraw() requires a 'key' parameter(withdrawal key name, up on your account)")
2524
2995
 
2525
2996
  def fetch_positions(self, symbols: Strings = None, params={}):
2526
2997
  """
2527
2998
  fetch all open positions
2528
- :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getOpenPositions
2529
- :param str[]|None symbols: not used by kraken fetchPositions()
2999
+
3000
+ https://docs.kraken.com/rest/#tag/Account-Data/operation/getOpenPositions
3001
+
3002
+ :param str[] [symbols]: not used by kraken fetchPositions()
2530
3003
  :param dict [params]: extra parameters specific to the exchange API endpoint
2531
3004
  :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
2532
3005
  """
2533
3006
  self.load_markets()
2534
- request = {
3007
+ request: dict = {
2535
3008
  # 'txid': 'comma delimited list of transaction ids to restrict output to',
2536
- # 'docalcs': False, # whether or not to include profit/loss calculations
2537
- # 'consolidation': 'market', # what to consolidate the positions data around, market will consolidate positions based on market pair
3009
+ 'docalcs': 'true', # whether or not to include profit/loss calculations
3010
+ 'consolidation': 'market', # what to consolidate the positions data around, market will consolidate positions based on market pair
2538
3011
  }
2539
3012
  response = self.privatePostOpenPositions(self.extend(request, params))
2540
3013
  #
@@ -2582,12 +3055,61 @@ class kraken(Exchange, ImplicitAPI):
2582
3055
  # ]
2583
3056
  # }
2584
3057
  #
2585
- result = self.safe_value(response, 'result')
2586
- # todo unify parsePosition/parsePositions
2587
- return result
3058
+ symbols = self.market_symbols(symbols)
3059
+ result = self.safe_list(response, 'result')
3060
+ results = self.parse_positions(result, symbols)
3061
+ return self.filter_by_array_positions(results, 'symbol', symbols, False)
3062
+
3063
+ def parse_position(self, position: dict, market: Market = None):
3064
+ #
3065
+ # {
3066
+ # "pair": "ETHUSDT",
3067
+ # "positions": "1",
3068
+ # "type": "buy",
3069
+ # "leverage": "2.00000",
3070
+ # "cost": "28.49800",
3071
+ # "fee": "0.07979",
3072
+ # "vol": "0.02000000",
3073
+ # "vol_closed": "0.00000000",
3074
+ # "margin": "14.24900"
3075
+ # }
3076
+ #
3077
+ marketId = self.safe_string(position, 'pair')
3078
+ rawSide = self.safe_string(position, 'type')
3079
+ side = 'long' if (rawSide == 'buy') else 'short'
3080
+ return self.safe_position({
3081
+ 'info': position,
3082
+ 'id': None,
3083
+ 'symbol': self.safe_symbol(marketId, market),
3084
+ 'notional': None,
3085
+ 'marginMode': None,
3086
+ 'liquidationPrice': None,
3087
+ 'entryPrice': None,
3088
+ 'unrealizedPnl': self.safe_number(position, 'net'),
3089
+ 'realizedPnl': None,
3090
+ 'percentage': None,
3091
+ 'contracts': self.safe_number(position, 'vol'),
3092
+ 'contractSize': None,
3093
+ 'markPrice': None,
3094
+ 'lastPrice': None,
3095
+ 'side': side,
3096
+ 'hedged': None,
3097
+ 'timestamp': None,
3098
+ 'datetime': None,
3099
+ 'lastUpdateTimestamp': None,
3100
+ 'maintenanceMargin': None,
3101
+ 'maintenanceMarginPercentage': None,
3102
+ 'collateral': None,
3103
+ 'initialMargin': self.safe_number(position, 'margin'),
3104
+ 'initialMarginPercentage': None,
3105
+ 'leverage': self.safe_number(position, 'leverage'),
3106
+ 'marginRatio': None,
3107
+ 'stopLossPrice': None,
3108
+ 'takeProfitPrice': None,
3109
+ })
2588
3110
 
2589
3111
  def parse_account_type(self, account):
2590
- accountByType = {
3112
+ accountByType: dict = {
2591
3113
  'spot': 'Spot Wallet',
2592
3114
  'swap': 'Futures Wallet',
2593
3115
  'future': 'Futures Wallet',
@@ -2597,7 +3119,9 @@ class kraken(Exchange, ImplicitAPI):
2597
3119
  def transfer_out(self, code: str, amount, params={}):
2598
3120
  """
2599
3121
  transfer from spot wallet to futures wallet
2600
- :see: https://docs.kraken.com/rest/#tag/User-Funding/operation/walletTransfer
3122
+
3123
+ https://docs.kraken.com/rest/#tag/User-Funding/operation/walletTransfer
3124
+
2601
3125
  :param str code: Unified currency code
2602
3126
  :param float amount: Size of the transfer
2603
3127
  :param dict [params]: Exchange specific parameters
@@ -2607,7 +3131,9 @@ class kraken(Exchange, ImplicitAPI):
2607
3131
 
2608
3132
  def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
2609
3133
  """
2610
- :see: https://docs.kraken.com/rest/#tag/User-Funding/operation/walletTransfer
3134
+
3135
+ https://docs.kraken.com/rest/#tag/User-Funding/operation/walletTransfer
3136
+
2611
3137
  transfers currencies between sub-accounts(only spot->swap direction is supported)
2612
3138
  :param str code: Unified currency code
2613
3139
  :param float amount: Size of the transfer
@@ -2620,7 +3146,7 @@ class kraken(Exchange, ImplicitAPI):
2620
3146
  currency = self.currency(code)
2621
3147
  fromAccount = self.parse_account_type(fromAccount)
2622
3148
  toAccount = self.parse_account_type(toAccount)
2623
- request = {
3149
+ request: dict = {
2624
3150
  'amount': self.currency_to_precision(code, amount),
2625
3151
  'from': fromAccount,
2626
3152
  'to': toAccount,
@@ -2645,7 +3171,7 @@ class kraken(Exchange, ImplicitAPI):
2645
3171
  'toAccount': toAccount,
2646
3172
  })
2647
3173
 
2648
- def parse_transfer(self, transfer, currency: Currency = None):
3174
+ def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
2649
3175
  #
2650
3176
  # transfer
2651
3177
  #
@@ -2678,11 +3204,15 @@ class kraken(Exchange, ImplicitAPI):
2678
3204
  # urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
2679
3205
  url += '?' + self.urlencode_nested(params)
2680
3206
  elif api == 'private':
3207
+ price = self.safe_string(params, 'price')
3208
+ isTriggerPercent = False
3209
+ if price is not None:
3210
+ isTriggerPercent = True if (price.endswith('%')) else False
2681
3211
  isCancelOrderBatch = (path == 'CancelOrderBatch')
2682
3212
  self.check_required_credentials()
2683
3213
  nonce = str(self.nonce())
2684
3214
  # urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
2685
- if isCancelOrderBatch:
3215
+ if isCancelOrderBatch or isTriggerPercent:
2686
3216
  body = self.json(self.extend({'nonce': nonce}, params))
2687
3217
  else:
2688
3218
  body = self.urlencode_nested(self.extend({'nonce': nonce}, params))
@@ -2695,9 +3225,8 @@ class kraken(Exchange, ImplicitAPI):
2695
3225
  headers = {
2696
3226
  'API-Key': self.apiKey,
2697
3227
  'API-Sign': signature,
2698
- # 'Content-Type': 'application/x-www-form-urlencoded',
2699
3228
  }
2700
- if isCancelOrderBatch:
3229
+ if isCancelOrderBatch or isTriggerPercent:
2701
3230
  headers['Content-Type'] = 'application/json'
2702
3231
  else:
2703
3232
  headers['Content-Type'] = 'application/x-www-form-urlencoded'
@@ -2707,24 +3236,11 @@ class kraken(Exchange, ImplicitAPI):
2707
3236
  return {'url': url, 'method': method, 'body': body, 'headers': headers}
2708
3237
 
2709
3238
  def nonce(self):
2710
- return self.milliseconds()
3239
+ return self.milliseconds() - self.options['timeDifference']
2711
3240
 
2712
- def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
3241
+ def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
2713
3242
  if code == 520:
2714
3243
  raise ExchangeNotAvailable(self.id + ' ' + str(code) + ' ' + reason)
2715
- # todo: rewrite self for "broad" exceptions matching
2716
- if body.find('Invalid order') >= 0:
2717
- raise InvalidOrder(self.id + ' ' + body)
2718
- if body.find('Invalid nonce') >= 0:
2719
- raise InvalidNonce(self.id + ' ' + body)
2720
- if body.find('Insufficient funds') >= 0:
2721
- raise InsufficientFunds(self.id + ' ' + body)
2722
- if body.find('Cancel pending') >= 0:
2723
- raise CancelPending(self.id + ' ' + body)
2724
- if body.find('Invalid arguments:volume') >= 0:
2725
- raise InvalidOrder(self.id + ' ' + body)
2726
- if body.find('Rate limit exceeded') >= 0:
2727
- raise RateLimitExceeded(self.id + ' ' + body)
2728
3244
  if response is None:
2729
3245
  return None
2730
3246
  if body[0] == '{':
@@ -2735,6 +3251,7 @@ class kraken(Exchange, ImplicitAPI):
2735
3251
  message = self.id + ' ' + body
2736
3252
  for i in range(0, len(response['error'])):
2737
3253
  error = response['error'][i]
2738
- self.throw_exactly_matched_exception(self.exceptions, error, message)
3254
+ self.throw_exactly_matched_exception(self.exceptions['exact'], error, message)
3255
+ self.throw_exactly_matched_exception(self.exceptions['broad'], error, message)
2739
3256
  raise ExchangeError(message)
2740
3257
  return None