ccxt-ir 4.3.46.0.1__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (772) hide show
  1. ccxt/__init__.py +358 -0
  2. ccxt/abantether.py +316 -0
  3. ccxt/abstract/__init__.py +0 -0
  4. ccxt/abstract/abantether.py +5 -0
  5. ccxt/abstract/ace.py +15 -0
  6. ccxt/abstract/afratether.py +6 -0
  7. ccxt/abstract/alpaca.py +70 -0
  8. ccxt/abstract/arzinja.py +5 -0
  9. ccxt/abstract/arzplus.py +7 -0
  10. ccxt/abstract/ascendex.py +77 -0
  11. ccxt/abstract/bequant.py +115 -0
  12. ccxt/abstract/bigone.py +45 -0
  13. ccxt/abstract/binance.py +712 -0
  14. ccxt/abstract/binancecoinm.py +712 -0
  15. ccxt/abstract/binanceus.py +764 -0
  16. ccxt/abstract/binanceusdm.py +712 -0
  17. ccxt/abstract/bingx.py +113 -0
  18. ccxt/abstract/bit2c.py +27 -0
  19. ccxt/abstract/bitbank.py +27 -0
  20. ccxt/abstract/bitbay.py +53 -0
  21. ccxt/abstract/bitbns.py +40 -0
  22. ccxt/abstract/bitcoincom.py +115 -0
  23. ccxt/abstract/bitfinex.py +69 -0
  24. ccxt/abstract/bitfinex2.py +139 -0
  25. ccxt/abstract/bitflyer.py +38 -0
  26. ccxt/abstract/bitget.py +508 -0
  27. ccxt/abstract/bithumb.py +32 -0
  28. ccxt/abstract/bitimen.py +7 -0
  29. ccxt/abstract/bitir.py +7 -0
  30. ccxt/abstract/bitmart.py +99 -0
  31. ccxt/abstract/bitmex.py +97 -0
  32. ccxt/abstract/bitopro.py +29 -0
  33. ccxt/abstract/bitpanda.py +35 -0
  34. ccxt/abstract/bitpin.py +7 -0
  35. ccxt/abstract/bitrue.py +72 -0
  36. ccxt/abstract/bitso.py +43 -0
  37. ccxt/abstract/bitstamp.py +258 -0
  38. ccxt/abstract/bitteam.py +29 -0
  39. ccxt/abstract/bitvavo.py +27 -0
  40. ccxt/abstract/bl3p.py +19 -0
  41. ccxt/abstract/blockchaincom.py +28 -0
  42. ccxt/abstract/blofin.py +37 -0
  43. ccxt/abstract/btcalpha.py +18 -0
  44. ccxt/abstract/btcbox.py +13 -0
  45. ccxt/abstract/btcmarkets.py +39 -0
  46. ccxt/abstract/btcturk.py +20 -0
  47. ccxt/abstract/bybit.py +298 -0
  48. ccxt/abstract/cex.py +33 -0
  49. ccxt/abstract/coinbase.py +94 -0
  50. ccxt/abstract/coinbaseadvanced.py +94 -0
  51. ccxt/abstract/coinbaseexchange.py +67 -0
  52. ccxt/abstract/coinbaseinternational.py +39 -0
  53. ccxt/abstract/coincatch.py +94 -0
  54. ccxt/abstract/coincheck.py +33 -0
  55. ccxt/abstract/coinex.py +237 -0
  56. ccxt/abstract/coinlist.py +54 -0
  57. ccxt/abstract/coinmate.py +62 -0
  58. ccxt/abstract/coinmetro.py +34 -0
  59. ccxt/abstract/coinone.py +67 -0
  60. ccxt/abstract/coinsph.py +54 -0
  61. ccxt/abstract/coinspot.py +28 -0
  62. ccxt/abstract/cryptocom.py +107 -0
  63. ccxt/abstract/currencycom.py +68 -0
  64. ccxt/abstract/delta.py +50 -0
  65. ccxt/abstract/deribit.py +125 -0
  66. ccxt/abstract/digifinex.py +91 -0
  67. ccxt/abstract/eterex.py +5 -0
  68. ccxt/abstract/excoino.py +7 -0
  69. ccxt/abstract/exir.py +8 -0
  70. ccxt/abstract/exmo.py +55 -0
  71. ccxt/abstract/exnovin.py +6 -0
  72. ccxt/abstract/farhadexchange.py +5 -0
  73. ccxt/abstract/fmfwio.py +115 -0
  74. ccxt/abstract/gate.py +265 -0
  75. ccxt/abstract/gateio.py +265 -0
  76. ccxt/abstract/gemini.py +58 -0
  77. ccxt/abstract/hashkey.py +67 -0
  78. ccxt/abstract/hitbtc.py +115 -0
  79. ccxt/abstract/hitbtc3.py +115 -0
  80. ccxt/abstract/hitobit.py +8 -0
  81. ccxt/abstract/hollaex.py +33 -0
  82. ccxt/abstract/htx.py +548 -0
  83. ccxt/abstract/huobi.py +548 -0
  84. ccxt/abstract/huobijp.py +114 -0
  85. ccxt/abstract/hyperliquid.py +6 -0
  86. ccxt/abstract/idex.py +26 -0
  87. ccxt/abstract/independentreserve.py +37 -0
  88. ccxt/abstract/indodax.py +26 -0
  89. ccxt/abstract/jibitex.py +7 -0
  90. ccxt/abstract/kraken.py +57 -0
  91. ccxt/abstract/krakenfutures.py +38 -0
  92. ccxt/abstract/kucoin.py +214 -0
  93. ccxt/abstract/kucoinfutures.py +233 -0
  94. ccxt/abstract/kuna.py +182 -0
  95. ccxt/abstract/latoken.py +56 -0
  96. ccxt/abstract/lbank.py +61 -0
  97. ccxt/abstract/luno.py +37 -0
  98. ccxt/abstract/lykke.py +29 -0
  99. ccxt/abstract/mercado.py +25 -0
  100. ccxt/abstract/mexc.py +178 -0
  101. ccxt/abstract/ndax.py +97 -0
  102. ccxt/abstract/nobitex.py +7 -0
  103. ccxt/abstract/novadax.py +29 -0
  104. ccxt/abstract/oceanex.py +22 -0
  105. ccxt/abstract/okcoin.py +74 -0
  106. ccxt/abstract/okexchange.py +8 -0
  107. ccxt/abstract/okx.py +324 -0
  108. ccxt/abstract/ompfinex.py +7 -0
  109. ccxt/abstract/onetrading.py +35 -0
  110. ccxt/abstract/oxfun.py +34 -0
  111. ccxt/abstract/p2b.py +22 -0
  112. ccxt/abstract/paradex.py +40 -0
  113. ccxt/abstract/paymium.py +28 -0
  114. ccxt/abstract/phemex.py +115 -0
  115. ccxt/abstract/poloniex.py +69 -0
  116. ccxt/abstract/poloniexfutures.py +48 -0
  117. ccxt/abstract/probit.py +23 -0
  118. ccxt/abstract/ramzinex.py +7 -0
  119. ccxt/abstract/sarmayex.py +5 -0
  120. ccxt/abstract/sarrafex.py +7 -0
  121. ccxt/abstract/tabdeal.py +7 -0
  122. ccxt/abstract/tetherland.py +5 -0
  123. ccxt/abstract/timex.py +62 -0
  124. ccxt/abstract/tokocrypto.py +37 -0
  125. ccxt/abstract/tradeogre.py +16 -0
  126. ccxt/abstract/twox.py +5 -0
  127. ccxt/abstract/ubitex.py +7 -0
  128. ccxt/abstract/upbit.py +38 -0
  129. ccxt/abstract/vertex.py +19 -0
  130. ccxt/abstract/wallex.py +8 -0
  131. ccxt/abstract/wavesexchange.py +154 -0
  132. ccxt/abstract/wazirx.py +30 -0
  133. ccxt/abstract/whitebit.py +98 -0
  134. ccxt/abstract/woo.py +83 -0
  135. ccxt/abstract/woofipro.py +119 -0
  136. ccxt/abstract/xt.py +152 -0
  137. ccxt/abstract/yobit.py +16 -0
  138. ccxt/abstract/zaif.py +38 -0
  139. ccxt/abstract/zonda.py +53 -0
  140. ccxt/ace.py +1012 -0
  141. ccxt/afratether.py +293 -0
  142. ccxt/alpaca.py +1083 -0
  143. ccxt/arzinja.py +285 -0
  144. ccxt/arzplus.py +412 -0
  145. ccxt/ascendex.py +3330 -0
  146. ccxt/async_support/__init__.py +337 -0
  147. ccxt/async_support/abantether.py +316 -0
  148. ccxt/async_support/ace.py +1012 -0
  149. ccxt/async_support/afratether.py +293 -0
  150. ccxt/async_support/alpaca.py +1083 -0
  151. ccxt/async_support/arzinja.py +285 -0
  152. ccxt/async_support/arzplus.py +412 -0
  153. ccxt/async_support/ascendex.py +3330 -0
  154. ccxt/async_support/base/__init__.py +1 -0
  155. ccxt/async_support/base/exchange.py +1966 -0
  156. ccxt/async_support/base/throttler.py +50 -0
  157. ccxt/async_support/base/ws/__init__.py +38 -0
  158. ccxt/async_support/base/ws/aiohttp_client.py +125 -0
  159. ccxt/async_support/base/ws/cache.py +212 -0
  160. ccxt/async_support/base/ws/client.py +193 -0
  161. ccxt/async_support/base/ws/fast_client.py +96 -0
  162. ccxt/async_support/base/ws/functions.py +59 -0
  163. ccxt/async_support/base/ws/future.py +58 -0
  164. ccxt/async_support/base/ws/order_book.py +78 -0
  165. ccxt/async_support/base/ws/order_book_side.py +174 -0
  166. ccxt/async_support/bequant.py +33 -0
  167. ccxt/async_support/bigone.py +2113 -0
  168. ccxt/async_support/binance.py +12234 -0
  169. ccxt/async_support/binancecoinm.py +45 -0
  170. ccxt/async_support/binanceus.py +211 -0
  171. ccxt/async_support/binanceusdm.py +58 -0
  172. ccxt/async_support/bingx.py +4325 -0
  173. ccxt/async_support/bit2c.py +866 -0
  174. ccxt/async_support/bitbank.py +1001 -0
  175. ccxt/async_support/bitbay.py +17 -0
  176. ccxt/async_support/bitbns.py +1154 -0
  177. ccxt/async_support/bitcoincom.py +17 -0
  178. ccxt/async_support/bitfinex.py +1617 -0
  179. ccxt/async_support/bitfinex2.py +3552 -0
  180. ccxt/async_support/bitflyer.py +995 -0
  181. ccxt/async_support/bitget.py +8273 -0
  182. ccxt/async_support/bithumb.py +1061 -0
  183. ccxt/async_support/bitimen.py +401 -0
  184. ccxt/async_support/bitir.py +490 -0
  185. ccxt/async_support/bitmart.py +4415 -0
  186. ccxt/async_support/bitmex.py +2756 -0
  187. ccxt/async_support/bitopro.py +1630 -0
  188. ccxt/async_support/bitpanda.py +16 -0
  189. ccxt/async_support/bitpin.py +454 -0
  190. ccxt/async_support/bitrue.py +3027 -0
  191. ccxt/async_support/bitso.py +1670 -0
  192. ccxt/async_support/bitstamp.py +2203 -0
  193. ccxt/async_support/bitteam.py +2239 -0
  194. ccxt/async_support/bitvavo.py +1968 -0
  195. ccxt/async_support/bl3p.py +485 -0
  196. ccxt/async_support/blockchaincom.py +1104 -0
  197. ccxt/async_support/blofin.py +2066 -0
  198. ccxt/async_support/btcalpha.py +891 -0
  199. ccxt/async_support/btcbox.py +544 -0
  200. ccxt/async_support/btcmarkets.py +1221 -0
  201. ccxt/async_support/btcturk.py +911 -0
  202. ccxt/async_support/bybit.py +8159 -0
  203. ccxt/async_support/cex.py +1605 -0
  204. ccxt/async_support/coinbase.py +4475 -0
  205. ccxt/async_support/coinbaseadvanced.py +17 -0
  206. ccxt/async_support/coinbaseexchange.py +1734 -0
  207. ccxt/async_support/coinbaseinternational.py +1899 -0
  208. ccxt/async_support/coincatch.py +5069 -0
  209. ccxt/async_support/coincheck.py +815 -0
  210. ccxt/async_support/coinex.py +5526 -0
  211. ccxt/async_support/coinlist.py +2243 -0
  212. ccxt/async_support/coinmate.py +1067 -0
  213. ccxt/async_support/coinmetro.py +1797 -0
  214. ccxt/async_support/coinone.py +1127 -0
  215. ccxt/async_support/coinsph.py +1850 -0
  216. ccxt/async_support/coinspot.py +534 -0
  217. ccxt/async_support/cryptocom.py +2822 -0
  218. ccxt/async_support/currencycom.py +1950 -0
  219. ccxt/async_support/delta.py +3376 -0
  220. ccxt/async_support/deribit.py +3437 -0
  221. ccxt/async_support/digifinex.py +3960 -0
  222. ccxt/async_support/eterex.py +286 -0
  223. ccxt/async_support/excoino.py +399 -0
  224. ccxt/async_support/exir.py +375 -0
  225. ccxt/async_support/exmo.py +2462 -0
  226. ccxt/async_support/exnovin.py +360 -0
  227. ccxt/async_support/farhadexchange.py +266 -0
  228. ccxt/async_support/fmfwio.py +34 -0
  229. ccxt/async_support/gate.py +6976 -0
  230. ccxt/async_support/gateio.py +16 -0
  231. ccxt/async_support/gemini.py +1825 -0
  232. ccxt/async_support/hashkey.py +4150 -0
  233. ccxt/async_support/hitbtc.py +3423 -0
  234. ccxt/async_support/hitbtc3.py +16 -0
  235. ccxt/async_support/hitobit.py +391 -0
  236. ccxt/async_support/hollaex.py +1813 -0
  237. ccxt/async_support/htx.py +8506 -0
  238. ccxt/async_support/huobi.py +16 -0
  239. ccxt/async_support/huobijp.py +1801 -0
  240. ccxt/async_support/hyperliquid.py +2431 -0
  241. ccxt/async_support/idex.py +1766 -0
  242. ccxt/async_support/independentreserve.py +784 -0
  243. ccxt/async_support/indodax.py +1247 -0
  244. ccxt/async_support/jibitex.py +395 -0
  245. ccxt/async_support/kraken.py +2894 -0
  246. ccxt/async_support/krakenfutures.py +2601 -0
  247. ccxt/async_support/kucoin.py +4602 -0
  248. ccxt/async_support/kucoinfutures.py +2698 -0
  249. ccxt/async_support/kuna.py +1841 -0
  250. ccxt/async_support/latoken.py +1664 -0
  251. ccxt/async_support/lbank.py +2683 -0
  252. ccxt/async_support/luno.py +1067 -0
  253. ccxt/async_support/lykke.py +1270 -0
  254. ccxt/async_support/mercado.py +842 -0
  255. ccxt/async_support/mexc.py +5369 -0
  256. ccxt/async_support/ndax.py +2354 -0
  257. ccxt/async_support/nobitex.py +419 -0
  258. ccxt/async_support/novadax.py +1484 -0
  259. ccxt/async_support/oceanex.py +903 -0
  260. ccxt/async_support/okcoin.py +2936 -0
  261. ccxt/async_support/okexchange.py +349 -0
  262. ccxt/async_support/okx.py +7827 -0
  263. ccxt/async_support/ompfinex.py +472 -0
  264. ccxt/async_support/onetrading.py +1911 -0
  265. ccxt/async_support/oxfun.py +2773 -0
  266. ccxt/async_support/p2b.py +1194 -0
  267. ccxt/async_support/paradex.py +2015 -0
  268. ccxt/async_support/paymium.py +564 -0
  269. ccxt/async_support/phemex.py +4473 -0
  270. ccxt/async_support/poloniex.py +2232 -0
  271. ccxt/async_support/poloniexfutures.py +1717 -0
  272. ccxt/async_support/probit.py +1734 -0
  273. ccxt/async_support/ramzinex.py +476 -0
  274. ccxt/async_support/sarmayex.py +357 -0
  275. ccxt/async_support/sarrafex.py +478 -0
  276. ccxt/async_support/tabdeal.py +364 -0
  277. ccxt/async_support/tetherland.py +349 -0
  278. ccxt/async_support/timex.py +1593 -0
  279. ccxt/async_support/tokocrypto.py +2405 -0
  280. ccxt/async_support/tradeogre.py +608 -0
  281. ccxt/async_support/twox.py +326 -0
  282. ccxt/async_support/ubitex.py +409 -0
  283. ccxt/async_support/upbit.py +1833 -0
  284. ccxt/async_support/vertex.py +2922 -0
  285. ccxt/async_support/wallex.py +445 -0
  286. ccxt/async_support/wavesexchange.py +2473 -0
  287. ccxt/async_support/wazirx.py +1224 -0
  288. ccxt/async_support/whitebit.py +2469 -0
  289. ccxt/async_support/woo.py +3114 -0
  290. ccxt/async_support/woofipro.py +2533 -0
  291. ccxt/async_support/xt.py +4454 -0
  292. ccxt/async_support/yobit.py +1283 -0
  293. ccxt/async_support/zaif.py +725 -0
  294. ccxt/async_support/zonda.py +1828 -0
  295. ccxt/base/__init__.py +27 -0
  296. ccxt/base/decimal_to_precision.py +174 -0
  297. ccxt/base/errors.py +242 -0
  298. ccxt/base/exchange.py +5941 -0
  299. ccxt/base/precise.py +287 -0
  300. ccxt/base/types.py +502 -0
  301. ccxt/bequant.py +33 -0
  302. ccxt/bigone.py +2112 -0
  303. ccxt/binance.py +12233 -0
  304. ccxt/binancecoinm.py +45 -0
  305. ccxt/binanceus.py +211 -0
  306. ccxt/binanceusdm.py +58 -0
  307. ccxt/bingx.py +4324 -0
  308. ccxt/bit2c.py +866 -0
  309. ccxt/bitbank.py +1001 -0
  310. ccxt/bitbay.py +17 -0
  311. ccxt/bitbns.py +1154 -0
  312. ccxt/bitcoincom.py +17 -0
  313. ccxt/bitfinex.py +1617 -0
  314. ccxt/bitfinex2.py +3552 -0
  315. ccxt/bitflyer.py +995 -0
  316. ccxt/bitget.py +8272 -0
  317. ccxt/bithumb.py +1061 -0
  318. ccxt/bitimen.py +401 -0
  319. ccxt/bitir.py +490 -0
  320. ccxt/bitmart.py +4415 -0
  321. ccxt/bitmex.py +2756 -0
  322. ccxt/bitopro.py +1630 -0
  323. ccxt/bitpanda.py +16 -0
  324. ccxt/bitpin.py +454 -0
  325. ccxt/bitrue.py +3026 -0
  326. ccxt/bitso.py +1670 -0
  327. ccxt/bitstamp.py +2203 -0
  328. ccxt/bitteam.py +2239 -0
  329. ccxt/bitvavo.py +1968 -0
  330. ccxt/bl3p.py +485 -0
  331. ccxt/blockchaincom.py +1104 -0
  332. ccxt/blofin.py +2066 -0
  333. ccxt/btcalpha.py +891 -0
  334. ccxt/btcbox.py +544 -0
  335. ccxt/btcmarkets.py +1221 -0
  336. ccxt/btcturk.py +911 -0
  337. ccxt/bybit.py +8158 -0
  338. ccxt/cex.py +1605 -0
  339. ccxt/coinbase.py +4474 -0
  340. ccxt/coinbaseadvanced.py +17 -0
  341. ccxt/coinbaseexchange.py +1734 -0
  342. ccxt/coinbaseinternational.py +1899 -0
  343. ccxt/coincatch.py +5069 -0
  344. ccxt/coincheck.py +815 -0
  345. ccxt/coinex.py +5525 -0
  346. ccxt/coinlist.py +2243 -0
  347. ccxt/coinmate.py +1067 -0
  348. ccxt/coinmetro.py +1797 -0
  349. ccxt/coinone.py +1127 -0
  350. ccxt/coinsph.py +1850 -0
  351. ccxt/coinspot.py +534 -0
  352. ccxt/cryptocom.py +2822 -0
  353. ccxt/currencycom.py +1950 -0
  354. ccxt/delta.py +3376 -0
  355. ccxt/deribit.py +3437 -0
  356. ccxt/digifinex.py +3959 -0
  357. ccxt/eterex.py +286 -0
  358. ccxt/excoino.py +399 -0
  359. ccxt/exir.py +375 -0
  360. ccxt/exmo.py +2462 -0
  361. ccxt/exnovin.py +360 -0
  362. ccxt/farhadexchange.py +266 -0
  363. ccxt/fmfwio.py +34 -0
  364. ccxt/gate.py +6975 -0
  365. ccxt/gateio.py +16 -0
  366. ccxt/gemini.py +1824 -0
  367. ccxt/hashkey.py +4150 -0
  368. ccxt/hitbtc.py +3423 -0
  369. ccxt/hitbtc3.py +16 -0
  370. ccxt/hitobit.py +391 -0
  371. ccxt/hollaex.py +1813 -0
  372. ccxt/htx.py +8505 -0
  373. ccxt/huobi.py +16 -0
  374. ccxt/huobijp.py +1801 -0
  375. ccxt/hyperliquid.py +2430 -0
  376. ccxt/idex.py +1766 -0
  377. ccxt/independentreserve.py +784 -0
  378. ccxt/indodax.py +1247 -0
  379. ccxt/jibitex.py +395 -0
  380. ccxt/kraken.py +2894 -0
  381. ccxt/krakenfutures.py +2601 -0
  382. ccxt/kucoin.py +4601 -0
  383. ccxt/kucoinfutures.py +2698 -0
  384. ccxt/kuna.py +1841 -0
  385. ccxt/latoken.py +1664 -0
  386. ccxt/lbank.py +2682 -0
  387. ccxt/luno.py +1067 -0
  388. ccxt/lykke.py +1270 -0
  389. ccxt/mercado.py +842 -0
  390. ccxt/mexc.py +5369 -0
  391. ccxt/ndax.py +2354 -0
  392. ccxt/nobitex.py +419 -0
  393. ccxt/novadax.py +1484 -0
  394. ccxt/oceanex.py +903 -0
  395. ccxt/okcoin.py +2936 -0
  396. ccxt/okexchange.py +349 -0
  397. ccxt/okx.py +7826 -0
  398. ccxt/ompfinex.py +472 -0
  399. ccxt/onetrading.py +1911 -0
  400. ccxt/oxfun.py +2772 -0
  401. ccxt/p2b.py +1194 -0
  402. ccxt/paradex.py +2015 -0
  403. ccxt/paymium.py +564 -0
  404. ccxt/phemex.py +4473 -0
  405. ccxt/poloniex.py +2232 -0
  406. ccxt/poloniexfutures.py +1717 -0
  407. ccxt/pro/__init__.py +149 -0
  408. ccxt/pro/alpaca.py +685 -0
  409. ccxt/pro/ascendex.py +916 -0
  410. ccxt/pro/bequant.py +38 -0
  411. ccxt/pro/binance.py +3488 -0
  412. ccxt/pro/binancecoinm.py +28 -0
  413. ccxt/pro/binanceus.py +48 -0
  414. ccxt/pro/binanceusdm.py +31 -0
  415. ccxt/pro/bingx.py +1264 -0
  416. ccxt/pro/bitcoincom.py +34 -0
  417. ccxt/pro/bitfinex.py +621 -0
  418. ccxt/pro/bitfinex2.py +1083 -0
  419. ccxt/pro/bitget.py +1692 -0
  420. ccxt/pro/bithumb.py +368 -0
  421. ccxt/pro/bitmart.py +1449 -0
  422. ccxt/pro/bitmex.py +1656 -0
  423. ccxt/pro/bitopro.py +445 -0
  424. ccxt/pro/bitpanda.py +15 -0
  425. ccxt/pro/bitrue.py +447 -0
  426. ccxt/pro/bitstamp.py +522 -0
  427. ccxt/pro/bitvavo.py +1270 -0
  428. ccxt/pro/blockchaincom.py +738 -0
  429. ccxt/pro/blofin.py +692 -0
  430. ccxt/pro/bybit.py +2000 -0
  431. ccxt/pro/cex.py +1440 -0
  432. ccxt/pro/coinbase.py +678 -0
  433. ccxt/pro/coinbaseadvanced.py +16 -0
  434. ccxt/pro/coinbaseexchange.py +895 -0
  435. ccxt/pro/coinbaseinternational.py +620 -0
  436. ccxt/pro/coincatch.py +1464 -0
  437. ccxt/pro/coincheck.py +199 -0
  438. ccxt/pro/coinex.py +1061 -0
  439. ccxt/pro/coinone.py +395 -0
  440. ccxt/pro/cryptocom.py +947 -0
  441. ccxt/pro/currencycom.py +536 -0
  442. ccxt/pro/deribit.py +892 -0
  443. ccxt/pro/exmo.py +629 -0
  444. ccxt/pro/gate.py +1416 -0
  445. ccxt/pro/gateio.py +15 -0
  446. ccxt/pro/gemini.py +865 -0
  447. ccxt/pro/hashkey.py +802 -0
  448. ccxt/pro/hitbtc.py +1216 -0
  449. ccxt/pro/hollaex.py +563 -0
  450. ccxt/pro/htx.py +2215 -0
  451. ccxt/pro/huobi.py +15 -0
  452. ccxt/pro/huobijp.py +570 -0
  453. ccxt/pro/hyperliquid.py +525 -0
  454. ccxt/pro/idex.py +672 -0
  455. ccxt/pro/independentreserve.py +270 -0
  456. ccxt/pro/kraken.py +1356 -0
  457. ccxt/pro/krakenfutures.py +1492 -0
  458. ccxt/pro/kucoin.py +1133 -0
  459. ccxt/pro/kucoinfutures.py +1081 -0
  460. ccxt/pro/lbank.py +843 -0
  461. ccxt/pro/luno.py +303 -0
  462. ccxt/pro/mexc.py +1122 -0
  463. ccxt/pro/ndax.py +506 -0
  464. ccxt/pro/okcoin.py +698 -0
  465. ccxt/pro/okx.py +1851 -0
  466. ccxt/pro/onetrading.py +1275 -0
  467. ccxt/pro/oxfun.py +950 -0
  468. ccxt/pro/p2b.py +419 -0
  469. ccxt/pro/paradex.py +352 -0
  470. ccxt/pro/phemex.py +1441 -0
  471. ccxt/pro/poloniex.py +1166 -0
  472. ccxt/pro/poloniexfutures.py +990 -0
  473. ccxt/pro/probit.py +551 -0
  474. ccxt/pro/upbit.py +520 -0
  475. ccxt/pro/vertex.py +943 -0
  476. ccxt/pro/wazirx.py +749 -0
  477. ccxt/pro/whitebit.py +864 -0
  478. ccxt/pro/woo.py +1078 -0
  479. ccxt/pro/woofipro.py +1183 -0
  480. ccxt/pro/xt.py +1067 -0
  481. ccxt/probit.py +1734 -0
  482. ccxt/ramzinex.py +476 -0
  483. ccxt/sarmayex.py +357 -0
  484. ccxt/sarrafex.py +478 -0
  485. ccxt/static_dependencies/__init__.py +1 -0
  486. ccxt/static_dependencies/ecdsa/__init__.py +14 -0
  487. ccxt/static_dependencies/ecdsa/_version.py +520 -0
  488. ccxt/static_dependencies/ecdsa/curves.py +56 -0
  489. ccxt/static_dependencies/ecdsa/der.py +221 -0
  490. ccxt/static_dependencies/ecdsa/ecdsa.py +310 -0
  491. ccxt/static_dependencies/ecdsa/ellipticcurve.py +197 -0
  492. ccxt/static_dependencies/ecdsa/keys.py +332 -0
  493. ccxt/static_dependencies/ecdsa/numbertheory.py +531 -0
  494. ccxt/static_dependencies/ecdsa/rfc6979.py +100 -0
  495. ccxt/static_dependencies/ecdsa/util.py +266 -0
  496. ccxt/static_dependencies/ethereum/__init__.py +7 -0
  497. ccxt/static_dependencies/ethereum/abi/__init__.py +16 -0
  498. ccxt/static_dependencies/ethereum/abi/abi.py +19 -0
  499. ccxt/static_dependencies/ethereum/abi/base.py +152 -0
  500. ccxt/static_dependencies/ethereum/abi/codec.py +217 -0
  501. ccxt/static_dependencies/ethereum/abi/constants.py +3 -0
  502. ccxt/static_dependencies/ethereum/abi/decoding.py +565 -0
  503. ccxt/static_dependencies/ethereum/abi/encoding.py +720 -0
  504. ccxt/static_dependencies/ethereum/abi/exceptions.py +139 -0
  505. ccxt/static_dependencies/ethereum/abi/grammar.py +443 -0
  506. ccxt/static_dependencies/ethereum/abi/packed.py +13 -0
  507. ccxt/static_dependencies/ethereum/abi/py.typed +0 -0
  508. ccxt/static_dependencies/ethereum/abi/registry.py +643 -0
  509. ccxt/static_dependencies/ethereum/abi/tools/__init__.py +3 -0
  510. ccxt/static_dependencies/ethereum/abi/tools/_strategies.py +230 -0
  511. ccxt/static_dependencies/ethereum/abi/utils/__init__.py +0 -0
  512. ccxt/static_dependencies/ethereum/abi/utils/numeric.py +83 -0
  513. ccxt/static_dependencies/ethereum/abi/utils/padding.py +27 -0
  514. ccxt/static_dependencies/ethereum/abi/utils/string.py +19 -0
  515. ccxt/static_dependencies/ethereum/account/__init__.py +3 -0
  516. ccxt/static_dependencies/ethereum/account/encode_typed_data/__init__.py +4 -0
  517. ccxt/static_dependencies/ethereum/account/encode_typed_data/encoding_and_hashing.py +239 -0
  518. ccxt/static_dependencies/ethereum/account/encode_typed_data/helpers.py +40 -0
  519. ccxt/static_dependencies/ethereum/account/messages.py +263 -0
  520. ccxt/static_dependencies/ethereum/account/py.typed +0 -0
  521. ccxt/static_dependencies/ethereum/hexbytes/__init__.py +5 -0
  522. ccxt/static_dependencies/ethereum/hexbytes/_utils.py +54 -0
  523. ccxt/static_dependencies/ethereum/hexbytes/main.py +65 -0
  524. ccxt/static_dependencies/ethereum/hexbytes/py.typed +0 -0
  525. ccxt/static_dependencies/ethereum/typing/__init__.py +63 -0
  526. ccxt/static_dependencies/ethereum/typing/abi.py +6 -0
  527. ccxt/static_dependencies/ethereum/typing/bls.py +7 -0
  528. ccxt/static_dependencies/ethereum/typing/discovery.py +5 -0
  529. ccxt/static_dependencies/ethereum/typing/encoding.py +7 -0
  530. ccxt/static_dependencies/ethereum/typing/enums.py +17 -0
  531. ccxt/static_dependencies/ethereum/typing/ethpm.py +9 -0
  532. ccxt/static_dependencies/ethereum/typing/evm.py +20 -0
  533. ccxt/static_dependencies/ethereum/typing/networks.py +1122 -0
  534. ccxt/static_dependencies/ethereum/typing/py.typed +0 -0
  535. ccxt/static_dependencies/ethereum/utils/__init__.py +115 -0
  536. ccxt/static_dependencies/ethereum/utils/abi.py +72 -0
  537. ccxt/static_dependencies/ethereum/utils/address.py +171 -0
  538. ccxt/static_dependencies/ethereum/utils/applicators.py +151 -0
  539. ccxt/static_dependencies/ethereum/utils/conversions.py +190 -0
  540. ccxt/static_dependencies/ethereum/utils/currency.py +107 -0
  541. ccxt/static_dependencies/ethereum/utils/curried/__init__.py +269 -0
  542. ccxt/static_dependencies/ethereum/utils/debug.py +20 -0
  543. ccxt/static_dependencies/ethereum/utils/decorators.py +132 -0
  544. ccxt/static_dependencies/ethereum/utils/encoding.py +6 -0
  545. ccxt/static_dependencies/ethereum/utils/exceptions.py +4 -0
  546. ccxt/static_dependencies/ethereum/utils/functional.py +75 -0
  547. ccxt/static_dependencies/ethereum/utils/hexadecimal.py +74 -0
  548. ccxt/static_dependencies/ethereum/utils/humanize.py +188 -0
  549. ccxt/static_dependencies/ethereum/utils/logging.py +159 -0
  550. ccxt/static_dependencies/ethereum/utils/module_loading.py +31 -0
  551. ccxt/static_dependencies/ethereum/utils/numeric.py +43 -0
  552. ccxt/static_dependencies/ethereum/utils/py.typed +0 -0
  553. ccxt/static_dependencies/ethereum/utils/toolz.py +76 -0
  554. ccxt/static_dependencies/ethereum/utils/types.py +54 -0
  555. ccxt/static_dependencies/ethereum/utils/typing/__init__.py +18 -0
  556. ccxt/static_dependencies/ethereum/utils/typing/misc.py +14 -0
  557. ccxt/static_dependencies/ethereum/utils/units.py +31 -0
  558. ccxt/static_dependencies/keccak/__init__.py +3 -0
  559. ccxt/static_dependencies/keccak/keccak.py +197 -0
  560. ccxt/static_dependencies/lark/__init__.py +38 -0
  561. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  562. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  563. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  564. ccxt/static_dependencies/lark/common.py +86 -0
  565. ccxt/static_dependencies/lark/exceptions.py +292 -0
  566. ccxt/static_dependencies/lark/grammar.py +130 -0
  567. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  568. ccxt/static_dependencies/lark/indenter.py +143 -0
  569. ccxt/static_dependencies/lark/lark.py +658 -0
  570. ccxt/static_dependencies/lark/lexer.py +678 -0
  571. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  572. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  573. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  574. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  575. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  576. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  577. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  578. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  579. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  580. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  581. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  582. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  583. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  584. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  585. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  586. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  587. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  588. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  589. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  590. ccxt/static_dependencies/lark/tree.py +267 -0
  591. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  592. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  593. ccxt/static_dependencies/lark/utils.py +343 -0
  594. ccxt/static_dependencies/lark/visitors.py +596 -0
  595. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  596. ccxt/static_dependencies/marshmallow/base.py +65 -0
  597. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  598. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  599. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  600. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  601. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  602. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  603. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  604. ccxt/static_dependencies/marshmallow/types.py +12 -0
  605. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  606. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  607. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  608. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  609. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  610. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  611. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  612. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  613. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  614. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  615. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  616. ccxt/static_dependencies/msgpack/__init__.py +55 -0
  617. ccxt/static_dependencies/msgpack/exceptions.py +48 -0
  618. ccxt/static_dependencies/msgpack/ext.py +168 -0
  619. ccxt/static_dependencies/msgpack/fallback.py +951 -0
  620. ccxt/static_dependencies/parsimonious/__init__.py +10 -0
  621. ccxt/static_dependencies/parsimonious/exceptions.py +105 -0
  622. ccxt/static_dependencies/parsimonious/expressions.py +479 -0
  623. ccxt/static_dependencies/parsimonious/grammar.py +487 -0
  624. ccxt/static_dependencies/parsimonious/nodes.py +325 -0
  625. ccxt/static_dependencies/parsimonious/utils.py +40 -0
  626. ccxt/static_dependencies/starknet/__init__.py +0 -0
  627. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  628. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  629. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  630. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  631. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  632. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  633. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  634. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  635. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  636. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  637. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  638. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  639. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  640. ccxt/static_dependencies/starknet/common.py +15 -0
  641. ccxt/static_dependencies/starknet/constants.py +39 -0
  642. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  643. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  644. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  645. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  646. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  647. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  648. ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  649. ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  650. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  651. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  652. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  653. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  654. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  655. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  656. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  657. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  658. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  659. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  660. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  661. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  662. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  663. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  664. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  665. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  666. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  667. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  668. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  669. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  670. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  671. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  672. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  673. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  674. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  675. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  676. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  677. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  678. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  679. ccxt/static_dependencies/starkware/__init__.py +0 -0
  680. ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  681. ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  682. ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  683. ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  684. ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  685. ccxt/static_dependencies/sympy/__init__.py +0 -0
  686. ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  687. ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  688. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  689. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  690. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  691. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  692. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  693. ccxt/static_dependencies/toolz/__init__.py +26 -0
  694. ccxt/static_dependencies/toolz/_signatures.py +784 -0
  695. ccxt/static_dependencies/toolz/_version.py +520 -0
  696. ccxt/static_dependencies/toolz/compatibility.py +30 -0
  697. ccxt/static_dependencies/toolz/curried/__init__.py +101 -0
  698. ccxt/static_dependencies/toolz/curried/exceptions.py +22 -0
  699. ccxt/static_dependencies/toolz/curried/operator.py +22 -0
  700. ccxt/static_dependencies/toolz/dicttoolz.py +339 -0
  701. ccxt/static_dependencies/toolz/functoolz.py +1049 -0
  702. ccxt/static_dependencies/toolz/itertoolz.py +1057 -0
  703. ccxt/static_dependencies/toolz/recipes.py +46 -0
  704. ccxt/static_dependencies/toolz/utils.py +9 -0
  705. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  706. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  707. ccxt/tabdeal.py +364 -0
  708. ccxt/test/__init__.py +3 -0
  709. ccxt/test/base/__init__.py +29 -0
  710. ccxt/test/base/test_account.py +26 -0
  711. ccxt/test/base/test_balance.py +56 -0
  712. ccxt/test/base/test_borrow_interest.py +35 -0
  713. ccxt/test/base/test_borrow_rate.py +32 -0
  714. ccxt/test/base/test_calculate_fee.py +51 -0
  715. ccxt/test/base/test_crypto.py +127 -0
  716. ccxt/test/base/test_currency.py +76 -0
  717. ccxt/test/base/test_datetime.py +109 -0
  718. ccxt/test/base/test_decimal_to_precision.py +392 -0
  719. ccxt/test/base/test_deep_extend.py +68 -0
  720. ccxt/test/base/test_deposit_withdrawal.py +50 -0
  721. ccxt/test/base/test_exchange_datetime_functions.py +76 -0
  722. ccxt/test/base/test_funding_rate_history.py +29 -0
  723. ccxt/test/base/test_last_price.py +31 -0
  724. ccxt/test/base/test_ledger_entry.py +45 -0
  725. ccxt/test/base/test_ledger_item.py +48 -0
  726. ccxt/test/base/test_leverage_tier.py +33 -0
  727. ccxt/test/base/test_liquidation.py +50 -0
  728. ccxt/test/base/test_margin_mode.py +24 -0
  729. ccxt/test/base/test_margin_modification.py +35 -0
  730. ccxt/test/base/test_market.py +193 -0
  731. ccxt/test/base/test_number.py +411 -0
  732. ccxt/test/base/test_ohlcv.py +33 -0
  733. ccxt/test/base/test_open_interest.py +32 -0
  734. ccxt/test/base/test_order.py +64 -0
  735. ccxt/test/base/test_order_book.py +69 -0
  736. ccxt/test/base/test_position.py +60 -0
  737. ccxt/test/base/test_shared_methods.py +353 -0
  738. ccxt/test/base/test_status.py +24 -0
  739. ccxt/test/base/test_throttle.py +126 -0
  740. ccxt/test/base/test_ticker.py +92 -0
  741. ccxt/test/base/test_trade.py +47 -0
  742. ccxt/test/base/test_trading_fee.py +26 -0
  743. ccxt/test/base/test_transaction.py +39 -0
  744. ccxt/test/test_async.py +1649 -0
  745. ccxt/test/test_sync.py +1648 -0
  746. ccxt/test/tests_async.py +1558 -0
  747. ccxt/test/tests_helpers.py +287 -0
  748. ccxt/test/tests_init.py +39 -0
  749. ccxt/test/tests_sync.py +1555 -0
  750. ccxt/tetherland.py +349 -0
  751. ccxt/timex.py +1593 -0
  752. ccxt/tokocrypto.py +2405 -0
  753. ccxt/tradeogre.py +608 -0
  754. ccxt/twox.py +326 -0
  755. ccxt/ubitex.py +409 -0
  756. ccxt/upbit.py +1833 -0
  757. ccxt/vertex.py +2922 -0
  758. ccxt/wallex.py +445 -0
  759. ccxt/wavesexchange.py +2472 -0
  760. ccxt/wazirx.py +1224 -0
  761. ccxt/whitebit.py +2469 -0
  762. ccxt/woo.py +3114 -0
  763. ccxt/woofipro.py +2533 -0
  764. ccxt/xt.py +4453 -0
  765. ccxt/yobit.py +1283 -0
  766. ccxt/zaif.py +725 -0
  767. ccxt/zonda.py +1828 -0
  768. ccxt_ir-4.3.46.0.1.dist-info/LICENSE.txt +21 -0
  769. ccxt_ir-4.3.46.0.1.dist-info/METADATA +655 -0
  770. ccxt_ir-4.3.46.0.1.dist-info/RECORD +772 -0
  771. ccxt_ir-4.3.46.0.1.dist-info/WHEEL +6 -0
  772. ccxt_ir-4.3.46.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2894 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+
6
+ from ccxt.async_support.base.exchange import Exchange
7
+ from ccxt.abstract.kraken import ImplicitAPI
8
+ import hashlib
9
+ from ccxt.base.types import Balances, Currencies, Currency, IndexType, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry
10
+ from typing import List
11
+ from ccxt.base.errors import ExchangeError
12
+ from ccxt.base.errors import AuthenticationError
13
+ from ccxt.base.errors import PermissionDenied
14
+ from ccxt.base.errors import AccountSuspended
15
+ from ccxt.base.errors import ArgumentsRequired
16
+ from ccxt.base.errors import BadRequest
17
+ from ccxt.base.errors import BadSymbol
18
+ from ccxt.base.errors import InsufficientFunds
19
+ from ccxt.base.errors import InvalidAddress
20
+ from ccxt.base.errors import InvalidOrder
21
+ from ccxt.base.errors import OrderNotFound
22
+ from ccxt.base.errors import CancelPending
23
+ from ccxt.base.errors import NotSupported
24
+ from ccxt.base.errors import DDoSProtection
25
+ from ccxt.base.errors import RateLimitExceeded
26
+ from ccxt.base.errors import ExchangeNotAvailable
27
+ from ccxt.base.errors import OnMaintenance
28
+ from ccxt.base.errors import InvalidNonce
29
+ from ccxt.base.decimal_to_precision import TRUNCATE
30
+ from ccxt.base.decimal_to_precision import TICK_SIZE
31
+ from ccxt.base.precise import Precise
32
+
33
+
34
+ class kraken(Exchange, ImplicitAPI):
35
+
36
+ def describe(self):
37
+ return self.deep_extend(super(kraken, self).describe(), {
38
+ 'id': 'kraken',
39
+ 'name': 'Kraken',
40
+ 'countries': ['US'],
41
+ 'version': '0',
42
+ # rate-limits: https://support.kraken.com/hc/en-us/articles/206548367-What-are-the-API-rate-limits-#1
43
+ # for public: 1 req/s
44
+ # for private: every second 0.33 weight added to your allowed capacity(some private endpoints need 1 weight, some need 2)
45
+ 'rateLimit': 1000,
46
+ 'certified': False,
47
+ 'pro': True,
48
+ 'has': {
49
+ 'CORS': None,
50
+ 'spot': True,
51
+ 'margin': True,
52
+ 'swap': False,
53
+ 'future': False,
54
+ 'option': False,
55
+ 'addMargin': False,
56
+ 'cancelAllOrders': True,
57
+ 'cancelAllOrdersAfter': True,
58
+ 'cancelOrder': True,
59
+ 'cancelOrders': True,
60
+ 'createDepositAddress': True,
61
+ 'createMarketBuyOrderWithCost': True,
62
+ 'createMarketOrderWithCost': False,
63
+ 'createMarketSellOrderWithCost': False,
64
+ 'createOrder': True,
65
+ 'createStopLimitOrder': True,
66
+ 'createStopMarketOrder': True,
67
+ 'createStopOrder': True,
68
+ 'createTrailingAmountOrder': True,
69
+ 'editOrder': True,
70
+ 'fetchBalance': True,
71
+ 'fetchBorrowInterest': False,
72
+ 'fetchBorrowRateHistories': False,
73
+ 'fetchBorrowRateHistory': False,
74
+ 'fetchClosedOrders': True,
75
+ 'fetchCrossBorrowRate': False,
76
+ 'fetchCrossBorrowRates': False,
77
+ 'fetchCurrencies': True,
78
+ 'fetchDepositAddress': True,
79
+ 'fetchDeposits': True,
80
+ 'fetchFundingHistory': False,
81
+ 'fetchFundingRate': False,
82
+ 'fetchFundingRateHistory': False,
83
+ 'fetchFundingRates': False,
84
+ 'fetchIndexOHLCV': False,
85
+ 'fetchIsolatedBorrowRate': False,
86
+ 'fetchIsolatedBorrowRates': False,
87
+ 'fetchLedger': True,
88
+ 'fetchLedgerEntry': True,
89
+ 'fetchLeverageTiers': False,
90
+ 'fetchMarkets': True,
91
+ 'fetchMarkOHLCV': False,
92
+ 'fetchMyTrades': True,
93
+ 'fetchOHLCV': True,
94
+ 'fetchOpenInterestHistory': False,
95
+ 'fetchOpenOrders': True,
96
+ 'fetchOrder': True,
97
+ 'fetchOrderBook': True,
98
+ 'fetchOrderTrades': 'emulated',
99
+ 'fetchPositions': True,
100
+ 'fetchPremiumIndexOHLCV': False,
101
+ 'fetchTicker': True,
102
+ 'fetchTickers': True,
103
+ 'fetchTime': True,
104
+ 'fetchTrades': True,
105
+ 'fetchTradingFee': True,
106
+ 'fetchTradingFees': False,
107
+ 'fetchWithdrawals': True,
108
+ 'setLeverage': False,
109
+ 'setMarginMode': False, # Kraken only supports cross margin
110
+ 'transfer': True,
111
+ 'withdraw': True,
112
+ },
113
+ 'timeframes': {
114
+ '1m': 1,
115
+ '5m': 5,
116
+ '15m': 15,
117
+ '30m': 30,
118
+ '1h': 60,
119
+ '4h': 240,
120
+ '1d': 1440,
121
+ '1w': 10080,
122
+ '2w': 21600,
123
+ },
124
+ 'urls': {
125
+ 'logo': 'https://user-images.githubusercontent.com/51840849/76173629-fc67fb00-61b1-11ea-84fe-f2de582f58a3.jpg',
126
+ 'api': {
127
+ 'public': 'https://api.kraken.com',
128
+ 'private': 'https://api.kraken.com',
129
+ 'zendesk': 'https://kraken.zendesk.com/api/v2/help_center/en-us/articles', # use the public zendesk api to receive article bodies and bypass new anti-spam protections
130
+ },
131
+ 'www': 'https://www.kraken.com',
132
+ 'doc': 'https://docs.kraken.com/rest/',
133
+ 'fees': 'https://www.kraken.com/en-us/features/fee-schedule',
134
+ },
135
+ 'fees': {
136
+ 'trading': {
137
+ 'tierBased': True,
138
+ 'percentage': True,
139
+ 'taker': self.parse_number('0.0026'),
140
+ 'maker': self.parse_number('0.0016'),
141
+ 'tiers': {
142
+ 'taker': [
143
+ [self.parse_number('0'), self.parse_number('0.0026')],
144
+ [self.parse_number('50000'), self.parse_number('0.0024')],
145
+ [self.parse_number('100000'), self.parse_number('0.0022')],
146
+ [self.parse_number('250000'), self.parse_number('0.0020')],
147
+ [self.parse_number('500000'), self.parse_number('0.0018')],
148
+ [self.parse_number('1000000'), self.parse_number('0.0016')],
149
+ [self.parse_number('2500000'), self.parse_number('0.0014')],
150
+ [self.parse_number('5000000'), self.parse_number('0.0012')],
151
+ [self.parse_number('10000000'), self.parse_number('0.0001')],
152
+ ],
153
+ 'maker': [
154
+ [self.parse_number('0'), self.parse_number('0.0016')],
155
+ [self.parse_number('50000'), self.parse_number('0.0014')],
156
+ [self.parse_number('100000'), self.parse_number('0.0012')],
157
+ [self.parse_number('250000'), self.parse_number('0.0010')],
158
+ [self.parse_number('500000'), self.parse_number('0.0008')],
159
+ [self.parse_number('1000000'), self.parse_number('0.0006')],
160
+ [self.parse_number('2500000'), self.parse_number('0.0004')],
161
+ [self.parse_number('5000000'), self.parse_number('0.0002')],
162
+ [self.parse_number('10000000'), self.parse_number('0.0')],
163
+ ],
164
+ },
165
+ },
166
+ },
167
+ 'handleContentTypeApplicationZip': True,
168
+ 'api': {
169
+ 'zendesk': {
170
+ 'get': [
171
+ # we should really refrain from putting fixed fee numbers and stop hardcoding
172
+ # we will be using their web APIs to scrape all numbers from these articles
173
+ '360000292886', # -What-are-the-deposit-fees-
174
+ '201893608', # -What-are-the-withdrawal-fees-
175
+ ],
176
+ },
177
+ 'public': {
178
+ 'get': {
179
+ # rate-limits explained in comment in the top of self file
180
+ 'Assets': 1,
181
+ 'AssetPairs': 1,
182
+ 'Depth': 1.2,
183
+ 'OHLC': 1.2, # 1.2 because 1 triggers too many requests immediately
184
+ 'Spread': 1,
185
+ 'SystemStatus': 1,
186
+ 'Ticker': 1,
187
+ 'Time': 1,
188
+ 'Trades': 1.2,
189
+ },
190
+ },
191
+ 'private': {
192
+ 'post': {
193
+ 'AddOrder': 0,
194
+ 'AddOrderBatch': 0,
195
+ 'AddExport': 3,
196
+ 'Balance': 3,
197
+ 'CancelAll': 3,
198
+ 'CancelAllOrdersAfter': 3,
199
+ 'CancelOrder': 0,
200
+ 'CancelOrderBatch': 0,
201
+ 'ClosedOrders': 3,
202
+ 'DepositAddresses': 3,
203
+ 'DepositMethods': 3,
204
+ 'DepositStatus': 3,
205
+ 'EditOrder': 0,
206
+ 'ExportStatus': 3,
207
+ 'GetWebSocketsToken': 3,
208
+ 'Ledgers': 6,
209
+ 'OpenOrders': 3,
210
+ 'OpenPositions': 3,
211
+ 'QueryLedgers': 3,
212
+ 'QueryOrders': 3,
213
+ 'QueryTrades': 3,
214
+ 'RetrieveExport': 3,
215
+ 'RemoveExport': 3,
216
+ 'BalanceEx': 3,
217
+ 'TradeBalance': 3,
218
+ 'TradesHistory': 6,
219
+ 'TradeVolume': 3,
220
+ 'Withdraw': 3,
221
+ 'WithdrawCancel': 3,
222
+ 'WithdrawInfo': 3,
223
+ 'WithdrawMethods': 3,
224
+ 'WithdrawAddresses': 3,
225
+ 'WithdrawStatus': 3,
226
+ 'WalletTransfer': 3,
227
+ # sub accounts
228
+ 'CreateSubaccount': 3,
229
+ 'AccountTransfer': 3,
230
+ # earn
231
+ 'Earn/Allocate': 3,
232
+ 'Earn/Deallocate': 3,
233
+ 'Earn/AllocateStatus': 3,
234
+ 'Earn/DeallocateStatus': 3,
235
+ 'Earn/Strategies': 3,
236
+ 'Earn/Allocations': 3,
237
+ },
238
+ },
239
+ },
240
+ 'commonCurrencies': {
241
+ 'LUNA': 'LUNC',
242
+ 'LUNA2': 'LUNA',
243
+ 'REPV2': 'REP',
244
+ 'REP': 'REPV1',
245
+ 'UST': 'USTC',
246
+ 'XBT': 'BTC',
247
+ 'XBT.M': 'BTC.M', # https://support.kraken.com/hc/en-us/articles/360039879471-What-is-Asset-S-and-Asset-M-
248
+ 'XDG': 'DOGE',
249
+ },
250
+ 'options': {
251
+ 'marketsByAltname': {},
252
+ 'delistedMarketsById': {},
253
+ # cannot withdraw/deposit these
254
+ 'inactiveCurrencies': ['CAD', 'USD', 'JPY', 'GBP'],
255
+ 'networks': {
256
+ 'ETH': 'ERC20',
257
+ 'TRX': 'TRC20',
258
+ },
259
+ 'depositMethods': {
260
+ '1INCH': '1inch(1INCH)',
261
+ 'AAVE': 'Aave',
262
+ 'ADA': 'ADA',
263
+ 'ALGO': 'Algorand',
264
+ 'ANKR': 'ANKR(ANKR)',
265
+ 'ANT': 'Aragon(ANT)',
266
+ 'ATOM': 'Cosmos',
267
+ 'AXS': 'Axie Infinity Shards(AXS)',
268
+ 'BADGER': 'Bager DAO(BADGER)',
269
+ 'BAL': 'Balancer(BAL)',
270
+ 'BAND': 'Band Protocol(BAND)',
271
+ 'BAT': 'BAT',
272
+ 'BCH': 'Bitcoin Cash',
273
+ 'BNC': 'Bifrost(BNC)',
274
+ 'BNT': 'Bancor(BNT)',
275
+ 'BTC': 'Bitcoin',
276
+ 'CHZ': 'Chiliz(CHZ)',
277
+ 'COMP': 'Compound(COMP)',
278
+ 'CQT': '\tCovalent Query Token(CQT)',
279
+ 'CRV': 'Curve DAO Token(CRV)',
280
+ 'CTSI': 'Cartesi(CTSI)',
281
+ 'DAI': 'Dai',
282
+ 'DASH': 'Dash',
283
+ 'DOGE': 'Dogecoin',
284
+ 'DOT': 'Polkadot',
285
+ 'DYDX': 'dYdX(DYDX)',
286
+ 'ENJ': 'Enjin Coin(ENJ)',
287
+ 'EOS': 'EOS',
288
+ 'ETC': 'Ether Classic(Hex)',
289
+ 'ETH': 'Ether(Hex)',
290
+ 'EWT': 'Energy Web Token',
291
+ 'FEE': 'Kraken Fee Credit',
292
+ 'FIL': 'Filecoin',
293
+ 'FLOW': 'Flow',
294
+ 'GHST': 'Aavegotchi(GHST)',
295
+ 'GNO': 'GNO',
296
+ 'GRT': 'GRT',
297
+ 'ICX': 'Icon',
298
+ 'INJ': 'Injective Protocol(INJ)',
299
+ 'KAR': 'Karura(KAR)',
300
+ 'KAVA': 'Kava',
301
+ 'KEEP': 'Keep Token(KEEP)',
302
+ 'KNC': 'Kyber Network(KNC)',
303
+ 'KSM': 'Kusama',
304
+ 'LINK': 'Link',
305
+ 'LPT': 'Livepeer Token(LPT)',
306
+ 'LRC': 'Loopring(LRC)',
307
+ 'LSK': 'Lisk',
308
+ 'LTC': 'Litecoin',
309
+ 'MANA': 'MANA',
310
+ 'MATIC': 'Polygon(MATIC)',
311
+ 'MINA': 'Mina', # inspected from webui
312
+ 'MIR': 'Mirror Protocol(MIR)',
313
+ 'MKR': 'Maker(MKR)',
314
+ 'MLN': 'MLN',
315
+ 'MOVR': 'Moonriver(MOVR)',
316
+ 'NANO': 'NANO',
317
+ 'OCEAN': 'OCEAN',
318
+ 'OGN': 'Origin Protocol(OGN)',
319
+ 'OMG': 'OMG',
320
+ 'OXT': 'Orchid(OXT)',
321
+ 'OXY': 'Oxygen(OXY)',
322
+ 'PAXG': 'PAX(Gold)',
323
+ 'PERP': 'Perpetual Protocol(PERP)',
324
+ 'PHA': 'Phala(PHA)',
325
+ 'QTUM': 'QTUM',
326
+ 'RARI': 'Rarible(RARI)',
327
+ 'RAY': 'Raydium(RAY)',
328
+ 'REN': 'Ren Protocol(REN)',
329
+ 'REP': 'REPv2',
330
+ 'REPV1': 'REP',
331
+ 'SAND': 'The Sandbox(SAND)',
332
+ 'SC': 'Siacoin',
333
+ 'SDN': 'Shiden(SDN)',
334
+ 'SOL': 'Solana', # their deposit method api doesn't work for SOL - was guessed
335
+ 'SNX': 'Synthetix Network(SNX)',
336
+ 'SRM': 'Serum', # inspected from webui
337
+ 'STORJ': 'Storj(STORJ)',
338
+ 'SUSHI': 'Sushiswap(SUSHI)',
339
+ 'TBTC': 'tBTC',
340
+ 'TRX': 'Tron',
341
+ 'UNI': 'UNI',
342
+ 'USDC': 'USDC',
343
+ 'USDT': 'Tether USD(ERC20)',
344
+ 'USDT-TRC20': 'Tether USD(TRC20)',
345
+ 'WAVES': 'Waves',
346
+ 'WBTC': 'Wrapped Bitcoin(WBTC)',
347
+ 'XLM': 'Stellar XLM',
348
+ 'XMR': 'Monero',
349
+ 'XRP': 'Ripple XRP',
350
+ 'XTZ': 'XTZ',
351
+ 'YFI': 'YFI',
352
+ 'ZEC': 'Zcash(Transparent)',
353
+ 'ZRX': '0x(ZRX)',
354
+ },
355
+ 'withdrawMethods': { # keeping it here because deposit and withdraw return different networks codes
356
+ 'Lightning': 'Lightning',
357
+ 'Bitcoin': 'BTC',
358
+ 'Ripple': 'XRP',
359
+ 'Litecoin': 'LTC',
360
+ 'Dogecoin': 'DOGE',
361
+ 'Stellar': 'XLM',
362
+ 'Ethereum': 'ERC20',
363
+ 'Arbitrum One': 'Arbitrum',
364
+ 'Polygon': 'MATIC',
365
+ 'Arbitrum Nova': 'Arbitrum',
366
+ 'Optimism': 'Optimism',
367
+ 'zkSync Era': 'zkSync',
368
+ 'Ethereum Classic': 'ETC',
369
+ 'Zcash': 'ZEC',
370
+ 'Monero': 'XMR',
371
+ 'Tron': 'TRC20',
372
+ 'Solana': 'SOL',
373
+ 'EOS': 'EOS',
374
+ 'Bitcoin Cash': 'BCH',
375
+ 'Cardano': 'ADA',
376
+ 'Qtum': 'QTUM',
377
+ 'Tezos': 'XTZ',
378
+ 'Cosmos': 'ATOM',
379
+ 'Nano': 'NANO',
380
+ 'Siacoin': 'SC',
381
+ 'Lisk': 'LSK',
382
+ 'Waves': 'WAVES',
383
+ 'ICON': 'ICX',
384
+ 'Algorand': 'ALGO',
385
+ 'Polygon - USDC.e': 'MATIC',
386
+ 'Arbitrum One - USDC.e': 'Arbitrum',
387
+ 'Polkadot': 'DOT',
388
+ 'Kava': 'KAVA',
389
+ 'Filecoin': 'FIL',
390
+ 'Kusama': 'KSM',
391
+ 'Flow': 'FLOW',
392
+ 'Energy Web': 'EW',
393
+ 'Mina': 'MINA',
394
+ 'Centrifuge': 'CFG',
395
+ 'Karura': 'KAR',
396
+ 'Moonriver': 'MOVR',
397
+ 'Shiden': 'SDN',
398
+ 'Khala': 'PHA',
399
+ 'Bifrost Kusama': 'BNC',
400
+ 'Songbird': 'SGB',
401
+ 'Terra classic': 'LUNC',
402
+ 'KILT': 'KILT',
403
+ 'Basilisk': 'BSX',
404
+ 'Flare': 'FLR',
405
+ 'Avalanche C-Chain': 'AVAX',
406
+ 'Kintsugi': 'KINT',
407
+ 'Altair': 'AIR',
408
+ 'Moonbeam': 'GLMR',
409
+ 'Acala': 'ACA',
410
+ 'Astar': 'ASTR',
411
+ 'Akash': 'AKT',
412
+ 'Robonomics': 'XRT',
413
+ 'Fantom': 'FTM',
414
+ 'Elrond': 'EGLD',
415
+ 'THORchain': 'RUNE',
416
+ 'Secret': 'SCRT',
417
+ 'Near': 'NEAR',
418
+ 'Internet Computer Protocol': 'ICP',
419
+ 'Picasso': 'PICA',
420
+ 'Crust Shadow': 'CSM',
421
+ 'Integritee': 'TEER',
422
+ 'Parallel Finance': 'PARA',
423
+ 'HydraDX': 'HDX',
424
+ 'Interlay': 'INTR',
425
+ 'Fetch.ai': 'FET',
426
+ 'NYM': 'NYM',
427
+ 'Terra 2.0': 'LUNA2',
428
+ 'Juno': 'JUNO',
429
+ 'Nodle': 'NODL',
430
+ 'Stacks': 'STX',
431
+ 'Ethereum PoW': 'ETHW',
432
+ 'Aptos': 'APT',
433
+ 'Sui': 'SUI',
434
+ 'Genshiro': 'GENS',
435
+ 'Aventus': 'AVT',
436
+ 'Sei': 'SEI',
437
+ 'OriginTrail': 'OTP',
438
+ 'Celestia': 'TIA',
439
+ },
440
+ },
441
+ 'precisionMode': TICK_SIZE,
442
+ 'exceptions': {
443
+ 'EQuery:Invalid asset pair': BadSymbol, # {"error":["EQuery:Invalid asset pair"]}
444
+ 'EAPI:Invalid key': AuthenticationError,
445
+ 'EFunding:Unknown withdraw key': InvalidAddress, # {"error":["EFunding:Unknown withdraw key"]}
446
+ 'EFunding:Invalid amount': InsufficientFunds,
447
+ 'EService:Unavailable': ExchangeNotAvailable,
448
+ 'EDatabase:Internal error': ExchangeNotAvailable,
449
+ 'EService:Busy': ExchangeNotAvailable,
450
+ 'EQuery:Unknown asset': BadSymbol, # {"error":["EQuery:Unknown asset"]}
451
+ 'EAPI:Rate limit exceeded': DDoSProtection,
452
+ 'EOrder:Rate limit exceeded': DDoSProtection,
453
+ 'EGeneral:Internal error': ExchangeNotAvailable,
454
+ 'EGeneral:Temporary lockout': DDoSProtection,
455
+ 'EGeneral:Permission denied': PermissionDenied,
456
+ 'EOrder:Unknown order': InvalidOrder,
457
+ 'EOrder:Order minimum not met': InvalidOrder,
458
+ 'EGeneral:Invalid arguments': BadRequest,
459
+ 'ESession:Invalid session': AuthenticationError,
460
+ 'EAPI:Invalid nonce': InvalidNonce,
461
+ 'EFunding:No funding method': BadRequest, # {"error":"EFunding:No funding method"}
462
+ 'EFunding:Unknown asset': BadSymbol, # {"error":["EFunding:Unknown asset"]}
463
+ 'EService:Market in post_only mode': OnMaintenance, # {"error":["EService:Market in post_only mode"]}
464
+ 'EGeneral:Too many requests': DDoSProtection, # {"error":["EGeneral:Too many requests"]}
465
+ 'ETrade:User Locked': AccountSuspended, # {"error":["ETrade:User Locked"]}
466
+ },
467
+ })
468
+
469
+ def fee_to_precision(self, symbol, fee):
470
+ return self.decimal_to_precision(fee, TRUNCATE, self.markets[symbol]['precision']['amount'], self.precisionMode)
471
+
472
+ async def fetch_markets(self, params={}) -> List[Market]:
473
+ """
474
+ retrieves data on all markets for kraken
475
+ :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTradableAssetPairs
476
+ :param dict [params]: extra parameters specific to the exchange API endpoint
477
+ :returns dict[]: an array of objects representing market data
478
+ """
479
+ response = await self.publicGetAssetPairs(params)
480
+ #
481
+ # {
482
+ # "error": [],
483
+ # "result": {
484
+ # "ADAETH": {
485
+ # "altname": "ADAETH",
486
+ # "wsname": "ADA\/ETH",
487
+ # "aclass_base": "currency",
488
+ # "base": "ADA",
489
+ # "aclass_quote": "currency",
490
+ # "quote": "XETH",
491
+ # "lot": "unit",
492
+ # "pair_decimals": 7,
493
+ # "lot_decimals": 8,
494
+ # "lot_multiplier": 1,
495
+ # "leverage_buy": [],
496
+ # "leverage_sell": [],
497
+ # "fees": [
498
+ # [0, 0.26],
499
+ # [50000, 0.24],
500
+ # [100000, 0.22],
501
+ # [250000, 0.2],
502
+ # [500000, 0.18],
503
+ # [1000000, 0.16],
504
+ # [2500000, 0.14],
505
+ # [5000000, 0.12],
506
+ # [10000000, 0.1]
507
+ # ],
508
+ # "fees_maker": [
509
+ # [0, 0.16],
510
+ # [50000, 0.14],
511
+ # [100000, 0.12],
512
+ # [250000, 0.1],
513
+ # [500000, 0.08],
514
+ # [1000000, 0.06],
515
+ # [2500000, 0.04],
516
+ # [5000000, 0.02],
517
+ # [10000000, 0]
518
+ # ],
519
+ # "fee_volume_currency": "ZUSD",
520
+ # "margin_call": 80,
521
+ # "margin_stop": 40,
522
+ # "ordermin": "1"
523
+ # },
524
+ # }
525
+ # }
526
+ #
527
+ markets = self.safe_value(response, 'result', {})
528
+ keys = list(markets.keys())
529
+ result = []
530
+ for i in range(0, len(keys)):
531
+ id = keys[i]
532
+ market = markets[id]
533
+ baseId = self.safe_string(market, 'base')
534
+ quoteId = self.safe_string(market, 'quote')
535
+ base = self.safe_currency_code(baseId)
536
+ quote = self.safe_currency_code(quoteId)
537
+ darkpool = id.find('.d') >= 0
538
+ altname = self.safe_string(market, 'altname')
539
+ makerFees = self.safe_value(market, 'fees_maker', [])
540
+ firstMakerFee = self.safe_value(makerFees, 0, [])
541
+ firstMakerFeeRate = self.safe_string(firstMakerFee, 1)
542
+ maker = None
543
+ if firstMakerFeeRate is not None:
544
+ maker = self.parse_number(Precise.string_div(firstMakerFeeRate, '100'))
545
+ takerFees = self.safe_value(market, 'fees', [])
546
+ firstTakerFee = self.safe_value(takerFees, 0, [])
547
+ firstTakerFeeRate = self.safe_string(firstTakerFee, 1)
548
+ taker = None
549
+ if firstTakerFeeRate is not None:
550
+ taker = self.parse_number(Precise.string_div(firstTakerFeeRate, '100'))
551
+ leverageBuy = self.safe_value(market, 'leverage_buy', [])
552
+ leverageBuyLength = len(leverageBuy)
553
+ precisionPrice = self.parse_number(self.parse_precision(self.safe_string(market, 'pair_decimals')))
554
+ status = self.safe_string(market, 'status')
555
+ isActive = status == 'online'
556
+ result.append({
557
+ 'id': id,
558
+ 'wsId': self.safe_string(market, 'wsname'),
559
+ 'symbol': altname if darkpool else (base + '/' + quote),
560
+ 'base': base,
561
+ 'quote': quote,
562
+ 'settle': None,
563
+ 'baseId': baseId,
564
+ 'quoteId': quoteId,
565
+ 'settleId': None,
566
+ 'darkpool': darkpool,
567
+ 'altname': market['altname'],
568
+ 'type': 'spot',
569
+ 'spot': True,
570
+ 'margin': (leverageBuyLength > 0),
571
+ 'swap': False,
572
+ 'future': False,
573
+ 'option': False,
574
+ 'active': isActive,
575
+ 'contract': False,
576
+ 'linear': None,
577
+ 'inverse': None,
578
+ 'taker': taker,
579
+ 'maker': maker,
580
+ 'contractSize': None,
581
+ 'expiry': None,
582
+ 'expiryDatetime': None,
583
+ 'strike': None,
584
+ 'optionType': None,
585
+ 'precision': {
586
+ 'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'lot_decimals'))),
587
+ 'price': precisionPrice,
588
+ },
589
+ 'limits': {
590
+ 'leverage': {
591
+ 'min': self.parse_number('1'),
592
+ 'max': self.safe_number(leverageBuy, leverageBuyLength - 1, 1),
593
+ },
594
+ 'amount': {
595
+ 'min': self.safe_number(market, 'ordermin'),
596
+ 'max': None,
597
+ },
598
+ 'price': {
599
+ 'min': precisionPrice,
600
+ 'max': None,
601
+ },
602
+ 'cost': {
603
+ 'min': self.safe_number(market, 'costmin'),
604
+ 'max': None,
605
+ },
606
+ },
607
+ 'created': None,
608
+ 'info': market,
609
+ })
610
+ result = self.append_inactive_markets(result)
611
+ self.options['marketsByAltname'] = self.index_by(result, 'altname')
612
+ return result
613
+
614
+ def safe_currency(self, currencyId, currency: Currency = None):
615
+ if currencyId is not None:
616
+ if len(currencyId) > 3:
617
+ if (currencyId.find('X') == 0) or (currencyId.find('Z') == 0):
618
+ if not (currencyId.find('.') > 0):
619
+ currencyId = currencyId[1:]
620
+ return super(kraken, self).safe_currency(currencyId, currency)
621
+
622
+ def append_inactive_markets(self, result):
623
+ # result should be an array to append to
624
+ precision: dict = {
625
+ 'amount': self.parse_number('1e-8'),
626
+ 'price': self.parse_number('1e-8'),
627
+ }
628
+ costLimits: dict = {'min': None, 'max': None}
629
+ priceLimits: dict = {'min': precision['price'], 'max': None}
630
+ amountLimits: dict = {'min': precision['amount'], 'max': None}
631
+ limits: dict = {'amount': amountLimits, 'price': priceLimits, 'cost': costLimits}
632
+ defaults: dict = {
633
+ 'darkpool': False,
634
+ 'info': None,
635
+ 'maker': None,
636
+ 'taker': None,
637
+ 'active': False,
638
+ 'precision': precision,
639
+ 'limits': limits,
640
+ }
641
+ markets = [
642
+ # {'id': 'XXLMZEUR', 'symbol': 'XLM/EUR', 'base': 'XLM', 'quote': 'EUR', 'altname': 'XLMEUR'},
643
+ ]
644
+ for i in range(0, len(markets)):
645
+ result.append(self.extend(defaults, markets[i]))
646
+ return result
647
+
648
+ async def fetch_currencies(self, params={}) -> Currencies:
649
+ """
650
+ fetches all available currencies on an exchange
651
+ :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getAssetInfo
652
+ :param dict [params]: extra parameters specific to the exchange API endpoint
653
+ :returns dict: an associative dictionary of currencies
654
+ """
655
+ response = await self.publicGetAssets(params)
656
+ #
657
+ # {
658
+ # "error": [],
659
+ # "result": {
660
+ # "BCH": {
661
+ # "aclass": "currency",
662
+ # "altname": "BCH",
663
+ # "decimals": 10,
664
+ # "display_decimals": 5
665
+ # "status": "enabled",
666
+ # },
667
+ # ...
668
+ # },
669
+ # }
670
+ #
671
+ currencies = self.safe_value(response, 'result', {})
672
+ ids = list(currencies.keys())
673
+ result: dict = {}
674
+ for i in range(0, len(ids)):
675
+ id = ids[i]
676
+ currency = currencies[id]
677
+ # todo: will need to rethink the fees
678
+ # see: https://support.kraken.com/hc/en-us/articles/201893608-What-are-the-withdrawal-fees-
679
+ # to add support for multiple withdrawal/deposit methods and
680
+ # differentiated fees for each particular method
681
+ code = self.safe_currency_code(id)
682
+ precision = self.parse_number(self.parse_precision(self.safe_string(currency, 'decimals')))
683
+ # assumes all currencies are active except those listed above
684
+ active = self.safe_string(currency, 'status') == 'enabled'
685
+ result[code] = {
686
+ 'id': id,
687
+ 'code': code,
688
+ 'info': currency,
689
+ 'name': self.safe_string(currency, 'altname'),
690
+ 'active': active,
691
+ 'deposit': None,
692
+ 'withdraw': None,
693
+ 'fee': None,
694
+ 'precision': precision,
695
+ 'limits': {
696
+ 'amount': {
697
+ 'min': precision,
698
+ 'max': None,
699
+ },
700
+ 'withdraw': {
701
+ 'min': None,
702
+ 'max': None,
703
+ },
704
+ },
705
+ 'networks': {},
706
+ }
707
+ return result
708
+
709
+ async def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
710
+ """
711
+ fetch the trading fees for a market
712
+ :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradeVolume
713
+ :param str symbol: unified market symbol
714
+ :param dict [params]: extra parameters specific to the exchange API endpoint
715
+ :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
716
+ """
717
+ await self.load_markets()
718
+ market = self.market(symbol)
719
+ request: dict = {
720
+ 'pair': market['id'],
721
+ 'fee-info': True,
722
+ }
723
+ response = await self.privatePostTradeVolume(self.extend(request, params))
724
+ #
725
+ # {
726
+ # "error": [],
727
+ # "result": {
728
+ # "currency": 'ZUSD',
729
+ # "volume": '0.0000',
730
+ # "fees": {
731
+ # "XXBTZUSD": {
732
+ # "fee": '0.2600',
733
+ # "minfee": '0.1000',
734
+ # "maxfee": '0.2600',
735
+ # "nextfee": '0.2400',
736
+ # "tiervolume": '0.0000',
737
+ # "nextvolume": '50000.0000'
738
+ # }
739
+ # },
740
+ # "fees_maker": {
741
+ # "XXBTZUSD": {
742
+ # "fee": '0.1600',
743
+ # "minfee": '0.0000',
744
+ # "maxfee": '0.1600',
745
+ # "nextfee": '0.1400',
746
+ # "tiervolume": '0.0000',
747
+ # "nextvolume": '50000.0000'
748
+ # }
749
+ # }
750
+ # }
751
+ # }
752
+ #
753
+ result = self.safe_value(response, 'result', {})
754
+ return self.parse_trading_fee(result, market)
755
+
756
+ def parse_trading_fee(self, response, market):
757
+ makerFees = self.safe_value(response, 'fees_maker', {})
758
+ takerFees = self.safe_value(response, 'fees', {})
759
+ symbolMakerFee = self.safe_value(makerFees, market['id'], {})
760
+ symbolTakerFee = self.safe_value(takerFees, market['id'], {})
761
+ return {
762
+ 'info': response,
763
+ 'symbol': market['symbol'],
764
+ 'maker': self.parse_number(Precise.string_div(self.safe_string(symbolMakerFee, 'fee'), '100')),
765
+ 'taker': self.parse_number(Precise.string_div(self.safe_string(symbolTakerFee, 'fee'), '100')),
766
+ 'percentage': True,
767
+ 'tierBased': True,
768
+ }
769
+
770
+ def parse_bid_ask(self, bidask, priceKey: IndexType = 0, amountKey: IndexType = 1, countOrIdKey: IndexType = 2):
771
+ price = self.safe_number(bidask, priceKey)
772
+ amount = self.safe_number(bidask, amountKey)
773
+ timestamp = self.safe_integer(bidask, 2)
774
+ return [price, amount, timestamp]
775
+
776
+ async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
777
+ """
778
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
779
+ :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getOrderBook
780
+ :param str symbol: unified symbol of the market to fetch the order book for
781
+ :param int [limit]: the maximum amount of order book entries to return
782
+ :param dict [params]: extra parameters specific to the exchange API endpoint
783
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
784
+ """
785
+ await self.load_markets()
786
+ market = self.market(symbol)
787
+ if market['darkpool']:
788
+ raise ExchangeError(self.id + ' fetchOrderBook() does not provide an order book for darkpool symbol ' + symbol)
789
+ request: dict = {
790
+ 'pair': market['id'],
791
+ }
792
+ if limit is not None:
793
+ request['count'] = limit # 100
794
+ response = await self.publicGetDepth(self.extend(request, params))
795
+ #
796
+ # {
797
+ # "error":[],
798
+ # "result":{
799
+ # "XETHXXBT":{
800
+ # "asks":[
801
+ # ["0.023480","4.000",1586321307],
802
+ # ["0.023490","50.095",1586321306],
803
+ # ["0.023500","28.535",1586321302],
804
+ # ],
805
+ # "bids":[
806
+ # ["0.023470","59.580",1586321307],
807
+ # ["0.023460","20.000",1586321301],
808
+ # ["0.023440","67.832",1586321306],
809
+ # ]
810
+ # }
811
+ # }
812
+ # }
813
+ #
814
+ result = self.safe_value(response, 'result', {})
815
+ orderbook = self.safe_value(result, market['id'])
816
+ # sometimes kraken returns wsname instead of market id
817
+ # https://github.com/ccxt/ccxt/issues/8662
818
+ marketInfo = self.safe_value(market, 'info', {})
819
+ wsName = self.safe_value(marketInfo, 'wsname')
820
+ if wsName is not None:
821
+ orderbook = self.safe_value(result, wsName, orderbook)
822
+ return self.parse_order_book(orderbook, symbol)
823
+
824
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
825
+ #
826
+ # {
827
+ # "a":["2432.77000","1","1.000"],
828
+ # "b":["2431.37000","2","2.000"],
829
+ # "c":["2430.58000","0.04408910"],
830
+ # "v":["4147.94474901","8896.96086304"],
831
+ # "p":["2456.22239","2568.63032"],
832
+ # "t":[3907,10056],
833
+ # "l":["2302.18000","2302.18000"],
834
+ # "h":["2621.14000","2860.01000"],
835
+ # "o":"2571.56000"
836
+ # }
837
+ #
838
+ symbol = self.safe_symbol(None, market)
839
+ v = self.safe_value(ticker, 'v', [])
840
+ baseVolume = self.safe_string(v, 1)
841
+ p = self.safe_value(ticker, 'p', [])
842
+ vwap = self.safe_string(p, 1)
843
+ quoteVolume = Precise.string_mul(baseVolume, vwap)
844
+ c = self.safe_value(ticker, 'c', [])
845
+ last = self.safe_string(c, 0)
846
+ high = self.safe_value(ticker, 'h', [])
847
+ low = self.safe_value(ticker, 'l', [])
848
+ bid = self.safe_value(ticker, 'b', [])
849
+ ask = self.safe_value(ticker, 'a', [])
850
+ return self.safe_ticker({
851
+ 'symbol': symbol,
852
+ 'timestamp': None,
853
+ 'datetime': None,
854
+ 'high': self.safe_string(high, 1),
855
+ 'low': self.safe_string(low, 1),
856
+ 'bid': self.safe_string(bid, 0),
857
+ 'bidVolume': None,
858
+ 'ask': self.safe_string(ask, 0),
859
+ 'askVolume': None,
860
+ 'vwap': vwap,
861
+ 'open': self.safe_string(ticker, 'o'),
862
+ 'close': last,
863
+ 'last': last,
864
+ 'previousClose': None,
865
+ 'change': None,
866
+ 'percentage': None,
867
+ 'average': None,
868
+ 'baseVolume': baseVolume,
869
+ 'quoteVolume': quoteVolume,
870
+ 'info': ticker,
871
+ }, market)
872
+
873
+ async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
874
+ """
875
+ fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
876
+ :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTickerInformation
877
+ :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
878
+ :param dict [params]: extra parameters specific to the exchange API endpoint
879
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
880
+ """
881
+ await self.load_markets()
882
+ request: dict = {}
883
+ if symbols is not None:
884
+ symbols = self.market_symbols(symbols)
885
+ marketIds = []
886
+ for i in range(0, len(symbols)):
887
+ symbol = symbols[i]
888
+ market = self.markets[symbol]
889
+ if market['active'] and not market['darkpool']:
890
+ marketIds.append(market['id'])
891
+ request['pair'] = ','.join(marketIds)
892
+ response = await self.publicGetTicker(self.extend(request, params))
893
+ tickers = response['result']
894
+ ids = list(tickers.keys())
895
+ result: dict = {}
896
+ for i in range(0, len(ids)):
897
+ id = ids[i]
898
+ market = self.safe_market(id)
899
+ symbol = market['symbol']
900
+ ticker = tickers[id]
901
+ result[symbol] = self.parse_ticker(ticker, market)
902
+ return self.filter_by_array_tickers(result, 'symbol', symbols)
903
+
904
+ async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
905
+ """
906
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
907
+ :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTickerInformation
908
+ :param str symbol: unified symbol of the market to fetch the ticker for
909
+ :param dict [params]: extra parameters specific to the exchange API endpoint
910
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
911
+ """
912
+ await self.load_markets()
913
+ darkpool = symbol.find('.d') >= 0
914
+ if darkpool:
915
+ raise ExchangeError(self.id + ' fetchTicker() does not provide a ticker for darkpool symbol ' + symbol)
916
+ market = self.market(symbol)
917
+ request: dict = {
918
+ 'pair': market['id'],
919
+ }
920
+ response = await self.publicGetTicker(self.extend(request, params))
921
+ ticker = response['result'][market['id']]
922
+ return self.parse_ticker(ticker, market)
923
+
924
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
925
+ #
926
+ # [
927
+ # 1591475640,
928
+ # "0.02500",
929
+ # "0.02500",
930
+ # "0.02500",
931
+ # "0.02500",
932
+ # "0.02500",
933
+ # "9.12201000",
934
+ # 5
935
+ # ]
936
+ #
937
+ return [
938
+ self.safe_timestamp(ohlcv, 0),
939
+ self.safe_number(ohlcv, 1),
940
+ self.safe_number(ohlcv, 2),
941
+ self.safe_number(ohlcv, 3),
942
+ self.safe_number(ohlcv, 4),
943
+ self.safe_number(ohlcv, 6),
944
+ ]
945
+
946
+ async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
947
+ """
948
+ fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
949
+ :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getOHLCData
950
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
951
+ :param str timeframe: the length of time each candle represents
952
+ :param int [since]: timestamp in ms of the earliest candle to fetch
953
+ :param int [limit]: the maximum amount of candles to fetch
954
+ :param dict [params]: extra parameters specific to the exchange API endpoint
955
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
956
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
957
+ """
958
+ await self.load_markets()
959
+ paginate = False
960
+ paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate')
961
+ if paginate:
962
+ return await self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 720)
963
+ market = self.market(symbol)
964
+ parsedTimeframe = self.safe_integer(self.timeframes, timeframe)
965
+ request: dict = {
966
+ 'pair': market['id'],
967
+ }
968
+ if parsedTimeframe is not None:
969
+ request['interval'] = parsedTimeframe
970
+ else:
971
+ request['interval'] = timeframe
972
+ if since is not None:
973
+ scaledSince = self.parse_to_int(since / 1000)
974
+ timeFrameInSeconds = parsedTimeframe * 60
975
+ request['since'] = self.number_to_string(scaledSince - timeFrameInSeconds) # expected to be in seconds
976
+ response = await self.publicGetOHLC(self.extend(request, params))
977
+ #
978
+ # {
979
+ # "error":[],
980
+ # "result":{
981
+ # "XETHXXBT":[
982
+ # [1591475580,"0.02499","0.02499","0.02499","0.02499","0.00000","0.00000000",0],
983
+ # [1591475640,"0.02500","0.02500","0.02500","0.02500","0.02500","9.12201000",5],
984
+ # [1591475700,"0.02499","0.02499","0.02499","0.02499","0.02499","1.28681415",2],
985
+ # [1591475760,"0.02499","0.02499","0.02499","0.02499","0.02499","0.08800000",1],
986
+ # ],
987
+ # "last":1591517580
988
+ # }
989
+ # }
990
+ result = self.safe_value(response, 'result', {})
991
+ ohlcvs = self.safe_list(result, market['id'], [])
992
+ return self.parse_ohlcvs(ohlcvs, market, timeframe, since, limit)
993
+
994
+ def parse_ledger_entry_type(self, type):
995
+ types: dict = {
996
+ 'trade': 'trade',
997
+ 'withdrawal': 'transaction',
998
+ 'deposit': 'transaction',
999
+ 'transfer': 'transfer',
1000
+ 'margin': 'margin',
1001
+ }
1002
+ return self.safe_string(types, type, type)
1003
+
1004
+ def parse_ledger_entry(self, item: dict, currency: Currency = None):
1005
+ #
1006
+ # {
1007
+ # 'LTFK7F-N2CUX-PNY4SX': {
1008
+ # "refid": "TSJTGT-DT7WN-GPPQMJ",
1009
+ # "time": 1520102320.555,
1010
+ # "type": "trade",
1011
+ # "aclass": "currency",
1012
+ # "asset": "XETH",
1013
+ # "amount": "0.1087194600",
1014
+ # "fee": "0.0000000000",
1015
+ # "balance": "0.2855851000"
1016
+ # },
1017
+ # ...
1018
+ # }
1019
+ #
1020
+ id = self.safe_string(item, 'id')
1021
+ direction = None
1022
+ account = None
1023
+ referenceId = self.safe_string(item, 'refid')
1024
+ referenceAccount = None
1025
+ type = self.parse_ledger_entry_type(self.safe_string(item, 'type'))
1026
+ code = self.safe_currency_code(self.safe_string(item, 'asset'), currency)
1027
+ amount = self.safe_string(item, 'amount')
1028
+ if Precise.string_lt(amount, '0'):
1029
+ direction = 'out'
1030
+ amount = Precise.string_abs(amount)
1031
+ else:
1032
+ direction = 'in'
1033
+ timestamp = self.safe_timestamp(item, 'time')
1034
+ return {
1035
+ 'info': item,
1036
+ 'id': id,
1037
+ 'direction': direction,
1038
+ 'account': account,
1039
+ 'referenceId': referenceId,
1040
+ 'referenceAccount': referenceAccount,
1041
+ 'type': type,
1042
+ 'currency': code,
1043
+ 'amount': self.parse_number(amount),
1044
+ 'before': None,
1045
+ 'after': self.safe_number(item, 'balance'),
1046
+ 'status': 'ok',
1047
+ 'timestamp': timestamp,
1048
+ 'datetime': self.iso8601(timestamp),
1049
+ 'fee': {
1050
+ 'cost': self.safe_number(item, 'fee'),
1051
+ 'currency': code,
1052
+ },
1053
+ }
1054
+
1055
+ async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
1056
+ """
1057
+ fetch the history of changes, actions done by the user or operations that altered balance of the user
1058
+ :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getLedgers
1059
+ :param str code: unified currency code, default is None
1060
+ :param int [since]: timestamp in ms of the earliest ledger entry, default is None
1061
+ :param int [limit]: max number of ledger entrys to return, default is None
1062
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1063
+ :param int [params.until]: timestamp in ms of the latest ledger entry
1064
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
1065
+ """
1066
+ # https://www.kraken.com/features/api#get-ledgers-info
1067
+ await self.load_markets()
1068
+ request: dict = {}
1069
+ currency = None
1070
+ if code is not None:
1071
+ currency = self.currency(code)
1072
+ request['asset'] = currency['id']
1073
+ if since is not None:
1074
+ request['start'] = self.parse_to_int(since / 1000)
1075
+ request, params = self.handle_until_option('end', request, params)
1076
+ response = await self.privatePostLedgers(self.extend(request, params))
1077
+ # { error: [],
1078
+ # "result": {ledger: {'LPUAIB-TS774-UKHP7X': { refid: "A2B4HBV-L4MDIE-JU4N3N",
1079
+ # "time": 1520103488.314,
1080
+ # "type": "withdrawal",
1081
+ # "aclass": "currency",
1082
+ # "asset": "XETH",
1083
+ # "amount": "-0.2805800000",
1084
+ # "fee": "0.0050000000",
1085
+ # "balance": "0.0000051000" },
1086
+ result = self.safe_value(response, 'result', {})
1087
+ ledger = self.safe_value(result, 'ledger', {})
1088
+ keys = list(ledger.keys())
1089
+ items = []
1090
+ for i in range(0, len(keys)):
1091
+ key = keys[i]
1092
+ value = ledger[key]
1093
+ value['id'] = key
1094
+ items.append(value)
1095
+ return self.parse_ledger(items, currency, since, limit)
1096
+
1097
+ async def fetch_ledger_entries_by_ids(self, ids, code: Str = None, params={}):
1098
+ # https://www.kraken.com/features/api#query-ledgers
1099
+ await self.load_markets()
1100
+ ids = ','.join(ids)
1101
+ request = self.extend({
1102
+ 'id': ids,
1103
+ }, params)
1104
+ response = await self.privatePostQueryLedgers(request)
1105
+ # { error: [],
1106
+ # "result": {'LPUAIB-TS774-UKHP7X': { refid: "A2B4HBV-L4MDIE-JU4N3N",
1107
+ # "time": 1520103488.314,
1108
+ # "type": "withdrawal",
1109
+ # "aclass": "currency",
1110
+ # "asset": "XETH",
1111
+ # "amount": "-0.2805800000",
1112
+ # "fee": "0.0050000000",
1113
+ # "balance": "0.0000051000" }}}
1114
+ result = response['result']
1115
+ keys = list(result.keys())
1116
+ items = []
1117
+ for i in range(0, len(keys)):
1118
+ key = keys[i]
1119
+ value = result[key]
1120
+ value['id'] = key
1121
+ items.append(value)
1122
+ return self.parse_ledger(items)
1123
+
1124
+ async def fetch_ledger_entry(self, id: str, code: Str = None, params={}):
1125
+ items = await self.fetch_ledger_entries_by_ids([id], code, params)
1126
+ return items[0]
1127
+
1128
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
1129
+ #
1130
+ # fetchTrades(public)
1131
+ #
1132
+ # [
1133
+ # "0.032310", # price
1134
+ # "4.28169434", # amount
1135
+ # 1541390792.763, # timestamp
1136
+ # "s", # sell or buy
1137
+ # "l", # limit or market
1138
+ # ""
1139
+ # ]
1140
+ #
1141
+ # fetchOrderTrades(private)
1142
+ #
1143
+ # {
1144
+ # "id": 'TIMIRG-WUNNE-RRJ6GT', # injected from outside
1145
+ # "ordertxid": 'OQRPN2-LRHFY-HIFA7D',
1146
+ # "postxid": 'TKH2SE-M7IF5-CFI7LT',
1147
+ # "pair": 'USDCUSDT',
1148
+ # "time": 1586340086.457,
1149
+ # "type": 'sell',
1150
+ # "ordertype": 'market',
1151
+ # "price": '0.99860000',
1152
+ # "cost": '22.16892001',
1153
+ # "fee": '0.04433784',
1154
+ # "vol": '22.20000000',
1155
+ # "margin": '0.00000000',
1156
+ # "misc": ''
1157
+ # }
1158
+ #
1159
+ timestamp = None
1160
+ side = None
1161
+ type = None
1162
+ price = None
1163
+ amount = None
1164
+ id = None
1165
+ orderId = None
1166
+ fee = None
1167
+ symbol = None
1168
+ if isinstance(trade, list):
1169
+ timestamp = self.safe_timestamp(trade, 2)
1170
+ side = 'sell' if (trade[3] == 's') else 'buy'
1171
+ type = 'limit' if (trade[4] == 'l') else 'market'
1172
+ price = self.safe_string(trade, 0)
1173
+ amount = self.safe_string(trade, 1)
1174
+ tradeLength = len(trade)
1175
+ if tradeLength > 6:
1176
+ id = self.safe_string(trade, 6) # artificially added #1794
1177
+ elif isinstance(trade, str):
1178
+ id = trade
1179
+ elif 'ordertxid' in trade:
1180
+ marketId = self.safe_string(trade, 'pair')
1181
+ foundMarket = self.find_market_by_altname_or_id(marketId)
1182
+ if foundMarket is not None:
1183
+ market = foundMarket
1184
+ elif marketId is not None:
1185
+ # delisted market ids go here
1186
+ market = self.get_delisted_market_by_id(marketId)
1187
+ orderId = self.safe_string(trade, 'ordertxid')
1188
+ id = self.safe_string_2(trade, 'id', 'postxid')
1189
+ timestamp = self.safe_timestamp(trade, 'time')
1190
+ side = self.safe_string(trade, 'type')
1191
+ type = self.safe_string(trade, 'ordertype')
1192
+ price = self.safe_string(trade, 'price')
1193
+ amount = self.safe_string(trade, 'vol')
1194
+ if 'fee' in trade:
1195
+ currency = None
1196
+ if market is not None:
1197
+ currency = market['quote']
1198
+ fee = {
1199
+ 'cost': self.safe_string(trade, 'fee'),
1200
+ 'currency': currency,
1201
+ }
1202
+ if market is not None:
1203
+ symbol = market['symbol']
1204
+ cost = self.safe_string(trade, 'cost')
1205
+ return self.safe_trade({
1206
+ 'id': id,
1207
+ 'order': orderId,
1208
+ 'info': trade,
1209
+ 'timestamp': timestamp,
1210
+ 'datetime': self.iso8601(timestamp),
1211
+ 'symbol': symbol,
1212
+ 'type': type,
1213
+ 'side': side,
1214
+ 'takerOrMaker': None,
1215
+ 'price': price,
1216
+ 'amount': amount,
1217
+ 'cost': cost,
1218
+ 'fee': fee,
1219
+ }, market)
1220
+
1221
+ async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1222
+ """
1223
+ get the list of most recent trades for a particular symbol
1224
+ :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getRecentTrades
1225
+ :param str symbol: unified symbol of the market to fetch trades for
1226
+ :param int [since]: timestamp in ms of the earliest trade to fetch
1227
+ :param int [limit]: the maximum amount of trades to fetch
1228
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1229
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
1230
+ """
1231
+ await self.load_markets()
1232
+ market = self.market(symbol)
1233
+ id = market['id']
1234
+ request: dict = {
1235
+ 'pair': id,
1236
+ }
1237
+ # https://support.kraken.com/hc/en-us/articles/218198197-How-to-pull-all-trade-data-using-the-Kraken-REST-API
1238
+ # https://github.com/ccxt/ccxt/issues/5677
1239
+ if since is not None:
1240
+ request['since'] = self.number_to_string(self.parse_to_int(since / 1000)) # expected to be in seconds
1241
+ if limit is not None:
1242
+ request['count'] = limit
1243
+ response = await self.publicGetTrades(self.extend(request, params))
1244
+ #
1245
+ # {
1246
+ # "error": [],
1247
+ # "result": {
1248
+ # "XETHXXBT": [
1249
+ # ["0.032310","4.28169434",1541390792.763,"s","l",""]
1250
+ # ],
1251
+ # "last": "1541439421200678657"
1252
+ # }
1253
+ # }
1254
+ #
1255
+ result = response['result']
1256
+ trades = result[id]
1257
+ # trades is a sorted array: last(most recent trade) goes last
1258
+ length = len(trades)
1259
+ if length <= 0:
1260
+ return []
1261
+ lastTrade = trades[length - 1]
1262
+ lastTradeId = self.safe_string(result, 'last')
1263
+ lastTrade.append(lastTradeId)
1264
+ trades[length - 1] = lastTrade
1265
+ return self.parse_trades(trades, market, since, limit)
1266
+
1267
+ def parse_balance(self, response) -> Balances:
1268
+ balances = self.safe_value(response, 'result', {})
1269
+ result: dict = {
1270
+ 'info': response,
1271
+ 'timestamp': None,
1272
+ 'datetime': None,
1273
+ }
1274
+ currencyIds = list(balances.keys())
1275
+ for i in range(0, len(currencyIds)):
1276
+ currencyId = currencyIds[i]
1277
+ code = self.safe_currency_code(currencyId)
1278
+ balance = self.safe_value(balances, currencyId, {})
1279
+ account = self.account()
1280
+ account['used'] = self.safe_string(balance, 'hold_trade')
1281
+ account['total'] = self.safe_string(balance, 'balance')
1282
+ result[code] = account
1283
+ return self.safe_balance(result)
1284
+
1285
+ async def fetch_balance(self, params={}) -> Balances:
1286
+ """
1287
+ query for balance and get the amount of funds available for trading or funds locked in orders
1288
+ :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getExtendedBalance
1289
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1290
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1291
+ """
1292
+ await self.load_markets()
1293
+ response = await self.privatePostBalanceEx(params)
1294
+ #
1295
+ # {
1296
+ # "error": [],
1297
+ # "result": {
1298
+ # "ZUSD": {
1299
+ # "balance": 25435.21,
1300
+ # "hold_trade": 8249.76
1301
+ # },
1302
+ # "XXBT": {
1303
+ # "balance": 1.2435,
1304
+ # "hold_trade": 0.8423
1305
+ # }
1306
+ # }
1307
+ # }
1308
+ #
1309
+ return self.parse_balance(response)
1310
+
1311
+ async def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost: float, params={}):
1312
+ """
1313
+ create a market order by providing the symbol, side and cost
1314
+ :see: https://docs.kraken.com/rest/#tag/Trading/operation/addOrder
1315
+ :param str symbol: unified symbol of the market to create an order in(only USD markets are supported)
1316
+ :param str side: 'buy' or 'sell'
1317
+ :param float cost: how much you want to trade in units of the quote currency
1318
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1319
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1320
+ """
1321
+ await self.load_markets()
1322
+ # only buy orders are supported by the endpoint
1323
+ params['cost'] = cost
1324
+ return await self.create_order(symbol, 'market', side, cost, None, params)
1325
+
1326
+ async def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
1327
+ """
1328
+ create a market buy order by providing the symbol, side and cost
1329
+ :see: https://docs.kraken.com/rest/#tag/Trading/operation/addOrder
1330
+ :param str symbol: unified symbol of the market to create an order in
1331
+ :param float cost: how much you want to trade in units of the quote currency
1332
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1333
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1334
+ """
1335
+ await self.load_markets()
1336
+ return await self.create_market_order_with_cost(symbol, 'buy', cost, params)
1337
+
1338
+ async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1339
+ """
1340
+ :see: https://docs.kraken.com/rest/#tag/Trading/operation/addOrder
1341
+ create a trade order
1342
+ :param str symbol: unified symbol of the market to create an order in
1343
+ :param str type: 'market' or 'limit'
1344
+ :param str side: 'buy' or 'sell'
1345
+ :param float amount: how much of currency you want to trade in units of base currency
1346
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1347
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1348
+ :param bool [params.postOnly]: if True, the order will only be posted to the order book and not executed immediately
1349
+ :param bool [params.reduceOnly]: *margin only* indicates if self order is to reduce the size of a position
1350
+ :param float [params.stopLossPrice]: *margin only* the price that a stop loss order is triggered at
1351
+ :param float [params.takeProfitPrice]: *margin only* the price that a take profit order is triggered at
1352
+ :param str [params.trailingAmount]: *margin only* the quote amount to trail away from the current market price
1353
+ :param str [params.trailingLimitAmount]: *margin only* the quote amount away from the trailingAmount
1354
+ :param str [params.offset]: *margin only* '+' or '-' whether you want the trailingLimitAmount value to be positive or negative, default is negative '-'
1355
+ :param str [params.trigger]: *margin only* the activation price type, 'last' or 'index', default is 'last'
1356
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1357
+ """
1358
+ await self.load_markets()
1359
+ market = self.market(symbol)
1360
+ request: dict = {
1361
+ 'pair': market['id'],
1362
+ 'type': side,
1363
+ 'ordertype': type,
1364
+ 'volume': self.amount_to_precision(symbol, amount),
1365
+ }
1366
+ orderRequest = self.order_request('createOrder', symbol, type, request, amount, price, params)
1367
+ response = await self.privatePostAddOrder(self.extend(orderRequest[0], orderRequest[1]))
1368
+ #
1369
+ # {
1370
+ # "error": [],
1371
+ # "result": {
1372
+ # "descr": {order: 'buy 0.02100000 ETHUSDT @ limit 330.00'},
1373
+ # "txid": ['OEKVV2-IH52O-TPL6GZ']
1374
+ # }
1375
+ # }
1376
+ #
1377
+ result = self.safe_dict(response, 'result')
1378
+ return self.parse_order(result)
1379
+
1380
+ def find_market_by_altname_or_id(self, id):
1381
+ marketsByAltname = self.safe_value(self.options, 'marketsByAltname', {})
1382
+ if id in marketsByAltname:
1383
+ return marketsByAltname[id]
1384
+ else:
1385
+ return self.safe_market(id)
1386
+
1387
+ def get_delisted_market_by_id(self, id):
1388
+ if id is None:
1389
+ return id
1390
+ market = self.safe_value(self.options['delistedMarketsById'], id)
1391
+ if market is not None:
1392
+ return market
1393
+ baseIdStart = 0
1394
+ baseIdEnd = 3
1395
+ quoteIdStart = 3
1396
+ quoteIdEnd = 6
1397
+ if len(id) == 8:
1398
+ baseIdEnd = 4
1399
+ quoteIdStart = 4
1400
+ quoteIdEnd = 8
1401
+ elif len(id) == 7:
1402
+ baseIdEnd = 4
1403
+ quoteIdStart = 4
1404
+ quoteIdEnd = 7
1405
+ baseId = id[baseIdStart:baseIdEnd]
1406
+ quoteId = id[quoteIdStart:quoteIdEnd]
1407
+ base = self.safe_currency_code(baseId)
1408
+ quote = self.safe_currency_code(quoteId)
1409
+ symbol = base + '/' + quote
1410
+ market = {
1411
+ 'symbol': symbol,
1412
+ 'base': base,
1413
+ 'quote': quote,
1414
+ 'baseId': baseId,
1415
+ 'quoteId': quoteId,
1416
+ }
1417
+ self.options['delistedMarketsById'][id] = market
1418
+ return market
1419
+
1420
+ def parse_order_status(self, status: Str):
1421
+ statuses: dict = {
1422
+ 'pending': 'open', # order pending book entry
1423
+ 'open': 'open',
1424
+ 'closed': 'closed',
1425
+ 'canceled': 'canceled',
1426
+ 'expired': 'expired',
1427
+ }
1428
+ return self.safe_string(statuses, status, status)
1429
+
1430
+ def parse_order_type(self, status):
1431
+ statuses: dict = {
1432
+ 'take-profit': 'market',
1433
+ 'stop-loss-limit': 'limit',
1434
+ 'stop-loss': 'market',
1435
+ 'take-profit-limit': 'limit',
1436
+ 'trailing-stop-limit': 'limit',
1437
+ }
1438
+ return self.safe_string(statuses, status, status)
1439
+
1440
+ def parse_order(self, order: dict, market: Market = None) -> Order:
1441
+ #
1442
+ # createOrder for regular orders
1443
+ #
1444
+ # {
1445
+ # "descr": {order: 'buy 0.02100000 ETHUSDT @ limit 330.00'},
1446
+ # "txid": ['OEKVV2-IH52O-TPL6GZ']
1447
+ # }
1448
+ # {
1449
+ # "txid": ["TX_ID_HERE"],
1450
+ # "descr": {"order":"buy 0.12345678 ETHEUR @ market"},
1451
+ # }
1452
+ #
1453
+ #
1454
+ # createOrder for stop orders
1455
+ #
1456
+ # {
1457
+ # "txid":["OSILNC-VQI5Q-775ZDQ"],
1458
+ # "descr":{"order":"sell 167.28002676 ADAXBT @ stop loss 0.00003280 -> limit 0.00003212"}
1459
+ # }
1460
+ #
1461
+ #
1462
+ # {
1463
+ # "txid":["OVHMJV-BZW2V-6NZFWF"],
1464
+ # "descr":{"order":"sell 0.00100000 ETHUSD @ stop loss 2677.00 -> limit 2577.00 with 5:1 leverage"}
1465
+ # }
1466
+ #
1467
+ # editOrder
1468
+ #
1469
+ # {
1470
+ # "status": "ok",
1471
+ # "txid": "OAW2BO-7RWEK-PZY5UO",
1472
+ # "originaltxid": "OXL6SS-UPNMC-26WBE7",
1473
+ # "volume": "0.00075000",
1474
+ # "price": "13500.0",
1475
+ # "orders_cancelled": 1,
1476
+ # "descr": {
1477
+ # "order": "buy 0.00075000 XBTUSDT @ limit 13500.0"
1478
+ # }
1479
+ # }
1480
+ # ws - createOrder
1481
+ # {
1482
+ # "descr": 'sell 0.00010000 XBTUSDT @ market',
1483
+ # "event": 'addOrderStatus',
1484
+ # "reqid": 1,
1485
+ # "status": 'ok',
1486
+ # "txid": 'OAVXZH-XIE54-JCYYDG'
1487
+ # }
1488
+ # ws - editOrder
1489
+ # {
1490
+ # "descr": "order edited price = 9000.00000000",
1491
+ # "event": "editOrderStatus",
1492
+ # "originaltxid": "O65KZW-J4AW3-VFS74A",
1493
+ # "reqid": 3,
1494
+ # "status": "ok",
1495
+ # "txid": "OTI672-HJFAO-XOIPPK"
1496
+ # }
1497
+ #
1498
+ # {
1499
+ # "error": [],
1500
+ # "result": {
1501
+ # "open": {
1502
+ # "OXVPSU-Q726F-L3SDEP": {
1503
+ # "refid": null,
1504
+ # "userref": 0,
1505
+ # "status": "open",
1506
+ # "opentm": 1706893367.4656649,
1507
+ # "starttm": 0,
1508
+ # "expiretm": 0,
1509
+ # "descr": {
1510
+ # "pair": "XRPEUR",
1511
+ # "type": "sell",
1512
+ # "ordertype": "trailing-stop",
1513
+ # "price": "+50.0000%",
1514
+ # "price2": "0",
1515
+ # "leverage": "none",
1516
+ # "order": "sell 10.00000000 XRPEUR @ trailing stop +50.0000%",
1517
+ # "close": ""
1518
+ # },
1519
+ # "vol": "10.00000000",
1520
+ # "vol_exec": "0.00000000",
1521
+ # "cost": "0.00000000",
1522
+ # "fee": "0.00000000",
1523
+ # "price": "0.00000000",
1524
+ # "stopprice": "0.23424000",
1525
+ # "limitprice": "0.46847000",
1526
+ # "misc": "",
1527
+ # "oflags": "fciq",
1528
+ # "trigger": "index"
1529
+ # }
1530
+ # }
1531
+ # }
1532
+ #
1533
+ description = self.safe_dict(order, 'descr', {})
1534
+ orderDescriptionObj = self.safe_dict(order, 'descr') # can be null
1535
+ orderDescription = None
1536
+ if orderDescriptionObj is not None:
1537
+ orderDescription = self.safe_string(orderDescriptionObj, 'order')
1538
+ else:
1539
+ orderDescription = self.safe_string(order, 'descr')
1540
+ side = None
1541
+ type = None
1542
+ marketId = None
1543
+ price = None
1544
+ amount = None
1545
+ stopPrice = None
1546
+ if orderDescription is not None:
1547
+ parts = orderDescription.split(' ')
1548
+ side = self.safe_string(parts, 0)
1549
+ amount = self.safe_string(parts, 1)
1550
+ marketId = self.safe_string(parts, 2)
1551
+ type = self.safe_string(parts, 4)
1552
+ if type == 'stop':
1553
+ stopPrice = self.safe_string(parts, 6)
1554
+ price = self.safe_string(parts, 9)
1555
+ elif type == 'limit':
1556
+ price = self.safe_string(parts, 5)
1557
+ side = self.safe_string(description, 'type', side)
1558
+ type = self.safe_string(description, 'ordertype', type)
1559
+ marketId = self.safe_string(description, 'pair', marketId)
1560
+ foundMarket = self.find_market_by_altname_or_id(marketId)
1561
+ symbol = None
1562
+ if foundMarket is not None:
1563
+ market = foundMarket
1564
+ elif marketId is not None:
1565
+ # delisted market ids go here
1566
+ market = self.get_delisted_market_by_id(marketId)
1567
+ timestamp = self.safe_timestamp(order, 'opentm')
1568
+ amount = self.safe_string(order, 'vol', amount)
1569
+ filled = self.safe_string(order, 'vol_exec')
1570
+ fee = None
1571
+ # kraken truncates the cost in the api response so we will ignore it and calculate it from average & filled
1572
+ # cost = self.safe_string(order, 'cost')
1573
+ price = self.safe_string(description, 'price', price)
1574
+ # when type = trailling stop returns price = '+50.0000%'
1575
+ if (price is not None) and price.endswith('%'):
1576
+ price = None # self is not the price we want
1577
+ if (price is None) or Precise.string_equals(price, '0'):
1578
+ price = self.safe_string(description, 'price2')
1579
+ if (price is None) or Precise.string_equals(price, '0'):
1580
+ price = self.safe_string(order, 'price', price)
1581
+ flags = self.safe_string(order, 'oflags', '')
1582
+ isPostOnly = flags.find('post') > -1
1583
+ average = self.safe_number(order, 'price')
1584
+ if market is not None:
1585
+ symbol = market['symbol']
1586
+ if 'fee' in order:
1587
+ feeCost = self.safe_string(order, 'fee')
1588
+ fee = {
1589
+ 'cost': feeCost,
1590
+ 'rate': None,
1591
+ }
1592
+ if flags.find('fciq') >= 0:
1593
+ fee['currency'] = market['quote']
1594
+ elif flags.find('fcib') >= 0:
1595
+ fee['currency'] = market['base']
1596
+ status = self.parse_order_status(self.safe_string(order, 'status'))
1597
+ id = self.safe_string_2(order, 'id', 'txid')
1598
+ if (id is None) or (id.startswith('[')):
1599
+ txid = self.safe_list(order, 'txid')
1600
+ id = self.safe_string(txid, 0)
1601
+ clientOrderId = self.safe_string(order, 'userref')
1602
+ rawTrades = self.safe_value(order, 'trades', [])
1603
+ trades = []
1604
+ for i in range(0, len(rawTrades)):
1605
+ rawTrade = rawTrades[i]
1606
+ if isinstance(rawTrade, str):
1607
+ trades.append(self.safe_trade({'id': rawTrade, 'orderId': id, 'symbol': symbol, 'info': {}}))
1608
+ else:
1609
+ trades.append(rawTrade)
1610
+ stopPrice = self.omit_zero(self.safe_string(order, 'stopprice', stopPrice))
1611
+ stopLossPrice = None
1612
+ takeProfitPrice = None
1613
+ if type.startswith('take-profit'):
1614
+ takeProfitPrice = self.safe_string(description, 'price')
1615
+ price = self.omit_zero(self.safe_string(description, 'price2'))
1616
+ elif type.startswith('stop-loss'):
1617
+ stopLossPrice = self.safe_string(description, 'price')
1618
+ price = self.omit_zero(self.safe_string(description, 'price2'))
1619
+ return self.safe_order({
1620
+ 'id': id,
1621
+ 'clientOrderId': clientOrderId,
1622
+ 'info': order,
1623
+ 'timestamp': timestamp,
1624
+ 'datetime': self.iso8601(timestamp),
1625
+ 'lastTradeTimestamp': None,
1626
+ 'status': status,
1627
+ 'symbol': symbol,
1628
+ 'type': self.parse_order_type(type),
1629
+ 'timeInForce': None,
1630
+ 'postOnly': isPostOnly,
1631
+ 'side': side,
1632
+ 'price': price,
1633
+ 'stopPrice': stopPrice,
1634
+ 'triggerPrice': stopPrice,
1635
+ 'takeProfitPrice': takeProfitPrice,
1636
+ 'stopLossPrice': stopLossPrice,
1637
+ 'cost': None,
1638
+ 'amount': amount,
1639
+ 'filled': filled,
1640
+ 'average': average,
1641
+ 'remaining': None,
1642
+ 'fee': fee,
1643
+ 'trades': trades,
1644
+ }, market)
1645
+
1646
+ def order_request(self, method: str, symbol: str, type: str, request: dict, amount: Num, price: Num = None, params={}):
1647
+ clientOrderId = self.safe_string_2(params, 'userref', 'clientOrderId')
1648
+ params = self.omit(params, ['userref', 'clientOrderId'])
1649
+ if clientOrderId is not None:
1650
+ request['userref'] = clientOrderId
1651
+ stopLossTriggerPrice = self.safe_string(params, 'stopLossPrice')
1652
+ takeProfitTriggerPrice = self.safe_string(params, 'takeProfitPrice')
1653
+ isStopLossTriggerOrder = stopLossTriggerPrice is not None
1654
+ isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
1655
+ isStopLossOrTakeProfitTrigger = isStopLossTriggerOrder or isTakeProfitTriggerOrder
1656
+ trailingAmount = self.safe_string(params, 'trailingAmount')
1657
+ trailingLimitAmount = self.safe_string(params, 'trailingLimitAmount')
1658
+ isTrailingAmountOrder = trailingAmount is not None
1659
+ isLimitOrder = type.endswith('limit') # supporting limit, stop-loss-limit, take-profit-limit, etc
1660
+ isMarketOrder = type == 'market'
1661
+ cost = self.safe_string(params, 'cost')
1662
+ flags = self.safe_string(params, 'oflags')
1663
+ params = self.omit(params, ['cost', 'oflags'])
1664
+ isViqcOrder = (flags is not None) and (flags.find('viqc') > -1) # volume in quote currency
1665
+ if isMarketOrder and (cost is not None or isViqcOrder):
1666
+ if cost is None and (amount is not None):
1667
+ request['volume'] = self.cost_to_precision(symbol, self.number_to_string(amount))
1668
+ else:
1669
+ request['volume'] = self.cost_to_precision(symbol, cost)
1670
+ extendedOflags = flags + ',viqc' if (flags is not None) else 'viqc'
1671
+ request['oflags'] = extendedOflags
1672
+ elif isLimitOrder and not isTrailingAmountOrder:
1673
+ request['price'] = self.price_to_precision(symbol, price)
1674
+ reduceOnly = self.safe_bool_2(params, 'reduceOnly', 'reduce_only')
1675
+ if isStopLossOrTakeProfitTrigger:
1676
+ if isStopLossTriggerOrder:
1677
+ request['price'] = self.price_to_precision(symbol, stopLossTriggerPrice)
1678
+ if isLimitOrder:
1679
+ request['ordertype'] = 'stop-loss-limit'
1680
+ else:
1681
+ request['ordertype'] = 'stop-loss'
1682
+ elif isTakeProfitTriggerOrder:
1683
+ request['price'] = self.price_to_precision(symbol, takeProfitTriggerPrice)
1684
+ if isLimitOrder:
1685
+ request['ordertype'] = 'take-profit-limit'
1686
+ else:
1687
+ request['ordertype'] = 'take-profit'
1688
+ if isLimitOrder:
1689
+ request['price2'] = self.price_to_precision(symbol, price)
1690
+ elif isTrailingAmountOrder:
1691
+ trailingActivationPriceType = self.safe_string(params, 'trigger', 'last')
1692
+ trailingAmountString = '+' + trailingAmount
1693
+ request['trigger'] = trailingActivationPriceType
1694
+ if isLimitOrder or (trailingLimitAmount is not None):
1695
+ offset = self.safe_string(params, 'offset', '-')
1696
+ trailingLimitAmountString = offset + self.number_to_string(trailingLimitAmount)
1697
+ request['price'] = trailingAmountString
1698
+ request['price2'] = trailingLimitAmountString
1699
+ request['ordertype'] = 'trailing-stop-limit'
1700
+ else:
1701
+ request['price'] = trailingAmountString
1702
+ request['ordertype'] = 'trailing-stop'
1703
+ if reduceOnly:
1704
+ if method == 'createOrderWs':
1705
+ request['reduce_only'] = True # ws request can't have stringified bool
1706
+ else:
1707
+ request['reduce_only'] = 'true' # not using hasattr(self, boolean) case, because the urlencodedNested transforms it into 'True' string
1708
+ close = self.safe_dict(params, 'close')
1709
+ if close is not None:
1710
+ close = self.extend({}, close)
1711
+ closePrice = self.safe_value(close, 'price')
1712
+ if closePrice is not None:
1713
+ close['price'] = self.price_to_precision(symbol, closePrice)
1714
+ closePrice2 = self.safe_value(close, 'price2') # stopPrice
1715
+ if closePrice2 is not None:
1716
+ close['price2'] = self.price_to_precision(symbol, closePrice2)
1717
+ request['close'] = close
1718
+ timeInForce = self.safe_string_2(params, 'timeInForce', 'timeinforce')
1719
+ if timeInForce is not None:
1720
+ request['timeinforce'] = timeInForce
1721
+ isMarket = (type == 'market')
1722
+ postOnly = None
1723
+ postOnly, params = self.handle_post_only(isMarket, False, params)
1724
+ if postOnly:
1725
+ extendedPostFlags = flags + ',post' if (flags is not None) else 'post'
1726
+ request['oflags'] = extendedPostFlags
1727
+ params = self.omit(params, ['timeInForce', 'reduceOnly', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingLimitAmount', 'offset'])
1728
+ return [request, params]
1729
+
1730
+ async def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
1731
+ """
1732
+ edit a trade order
1733
+ :see: https://docs.kraken.com/rest/#tag/Trading/operation/editOrder
1734
+ :param str id: order id
1735
+ :param str symbol: unified symbol of the market to create an order in
1736
+ :param str type: 'market' or 'limit'
1737
+ :param str side: 'buy' or 'sell'
1738
+ :param float amount: how much of the currency you want to trade in units of the base currency
1739
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1740
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1741
+ :param float [params.stopLossPrice]: *margin only* the price that a stop loss order is triggered at
1742
+ :param float [params.takeProfitPrice]: *margin only* the price that a take profit order is triggered at
1743
+ :param str [params.trailingAmount]: *margin only* the quote price away from the current market price
1744
+ :param str [params.trailingLimitAmount]: *margin only* the quote amount away from the trailingAmount
1745
+ :param str [params.offset]: *margin only* '+' or '-' whether you want the trailingLimitAmount value to be positive or negative, default is negative '-'
1746
+ :param str [params.trigger]: *margin only* the activation price type, 'last' or 'index', default is 'last'
1747
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1748
+ """
1749
+ await self.load_markets()
1750
+ market = self.market(symbol)
1751
+ if not market['spot']:
1752
+ raise NotSupported(self.id + ' editOrder() does not support ' + market['type'] + ' orders, only spot orders are accepted')
1753
+ request: dict = {
1754
+ 'txid': id,
1755
+ 'pair': market['id'],
1756
+ }
1757
+ if amount is not None:
1758
+ request['volume'] = self.amount_to_precision(symbol, amount)
1759
+ orderRequest = self.order_request('editOrder', symbol, type, request, amount, price, params)
1760
+ response = await self.privatePostEditOrder(self.extend(orderRequest[0], orderRequest[1]))
1761
+ #
1762
+ # {
1763
+ # "error": [],
1764
+ # "result": {
1765
+ # "status": "ok",
1766
+ # "txid": "OAW2BO-7RWEK-PZY5UO",
1767
+ # "originaltxid": "OXL6SS-UPNMC-26WBE7",
1768
+ # "volume": "0.00075000",
1769
+ # "price": "13500.0",
1770
+ # "orders_cancelled": 1,
1771
+ # "descr": {
1772
+ # "order": "buy 0.00075000 XBTUSDT @ limit 13500.0"
1773
+ # }
1774
+ # }
1775
+ # }
1776
+ #
1777
+ data = self.safe_dict(response, 'result', {})
1778
+ return self.parse_order(data, market)
1779
+
1780
+ async def fetch_order(self, id: str, symbol: Str = None, params={}):
1781
+ """
1782
+ fetches information on an order made by the user
1783
+ :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getOrdersInfo
1784
+ :param str symbol: not used by kraken fetchOrder
1785
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1786
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1787
+ """
1788
+ await self.load_markets()
1789
+ clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId')
1790
+ request: dict = {
1791
+ 'trades': True, # whether or not to include trades in output(optional, default False)
1792
+ # 'txid': id, # do not comma separate a list of ids - use fetchOrdersByIds instead
1793
+ # 'userref': 'optional', # restrict results to given user reference id(optional)
1794
+ }
1795
+ query = params
1796
+ if clientOrderId is not None:
1797
+ request['userref'] = clientOrderId
1798
+ query = self.omit(params, ['userref', 'clientOrderId'])
1799
+ else:
1800
+ request['txid'] = id
1801
+ response = await self.privatePostQueryOrders(self.extend(request, query))
1802
+ #
1803
+ # {
1804
+ # "error":[],
1805
+ # "result":{
1806
+ # "OTLAS3-RRHUF-NDWH5A":{
1807
+ # "refid":null,
1808
+ # "userref":null,
1809
+ # "status":"closed",
1810
+ # "reason":null,
1811
+ # "opentm":1586822919.3342,
1812
+ # "closetm":1586822919.365,
1813
+ # "starttm":0,
1814
+ # "expiretm":0,
1815
+ # "descr":{
1816
+ # "pair":"XBTUSDT",
1817
+ # "type":"sell",
1818
+ # "ordertype":"market",
1819
+ # "price":"0",
1820
+ # "price2":"0",
1821
+ # "leverage":"none",
1822
+ # "order":"sell 0.21804000 XBTUSDT @ market",
1823
+ # "close":""
1824
+ # },
1825
+ # "vol":"0.21804000",
1826
+ # "vol_exec":"0.21804000",
1827
+ # "cost":"1493.9",
1828
+ # "fee":"3.8",
1829
+ # "price":"6851.5",
1830
+ # "stopprice":"0.00000",
1831
+ # "limitprice":"0.00000",
1832
+ # "misc":"",
1833
+ # "oflags":"fciq",
1834
+ # "trades":["TT5UC3-GOIRW-6AZZ6R"]
1835
+ # }
1836
+ # }
1837
+ # }
1838
+ #
1839
+ result = self.safe_value(response, 'result', [])
1840
+ if not (id in result):
1841
+ raise OrderNotFound(self.id + ' fetchOrder() could not find order id ' + id)
1842
+ return self.parse_order(self.extend({'id': id}, result[id]))
1843
+
1844
+ async def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1845
+ """
1846
+ fetch all the trades made from a single order
1847
+ :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradesInfo
1848
+ :param str id: order id
1849
+ :param str symbol: unified market symbol
1850
+ :param int [since]: the earliest time in ms to fetch trades for
1851
+ :param int [limit]: the maximum number of trades to retrieve
1852
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1853
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1854
+ """
1855
+ orderTrades = self.safe_value(params, 'trades')
1856
+ tradeIds = []
1857
+ if orderTrades is None:
1858
+ raise ArgumentsRequired(self.id + " fetchOrderTrades() requires a unified order structure in the params argument or a 'trades' param(an array of trade id strings)")
1859
+ else:
1860
+ for i in range(0, len(orderTrades)):
1861
+ orderTrade = orderTrades[i]
1862
+ if isinstance(orderTrade, str):
1863
+ tradeIds.append(orderTrade)
1864
+ else:
1865
+ tradeIds.append(orderTrade['id'])
1866
+ await self.load_markets()
1867
+ if symbol is not None:
1868
+ symbol = self.symbol(symbol)
1869
+ options = self.safe_value(self.options, 'fetchOrderTrades', {})
1870
+ batchSize = self.safe_integer(options, 'batchSize', 20)
1871
+ numTradeIds = len(tradeIds)
1872
+ numBatches = self.parse_to_int(numTradeIds / batchSize)
1873
+ numBatches = self.sum(numBatches, 1)
1874
+ result = []
1875
+ for j in range(0, numBatches):
1876
+ requestIds = []
1877
+ for k in range(0, batchSize):
1878
+ index = self.sum(j * batchSize, k)
1879
+ if index < numTradeIds:
1880
+ requestIds.append(tradeIds[index])
1881
+ request: dict = {
1882
+ 'txid': ','.join(requestIds),
1883
+ }
1884
+ response = await self.privatePostQueryTrades(request)
1885
+ #
1886
+ # {
1887
+ # "error": [],
1888
+ # "result": {
1889
+ # 'TIMIRG-WUNNE-RRJ6GT': {
1890
+ # "ordertxid": 'OQRPN2-LRHFY-HIFA7D',
1891
+ # "postxid": 'TKH2SE-M7IF5-CFI7LT',
1892
+ # "pair": 'USDCUSDT',
1893
+ # "time": 1586340086.457,
1894
+ # "type": 'sell',
1895
+ # "ordertype": 'market',
1896
+ # "price": '0.99860000',
1897
+ # "cost": '22.16892001',
1898
+ # "fee": '0.04433784',
1899
+ # "vol": '22.20000000',
1900
+ # "margin": '0.00000000',
1901
+ # "misc": ''
1902
+ # }
1903
+ # }
1904
+ # }
1905
+ #
1906
+ rawTrades = self.safe_value(response, 'result')
1907
+ ids = list(rawTrades.keys())
1908
+ for i in range(0, len(ids)):
1909
+ rawTrades[ids[i]]['id'] = ids[i]
1910
+ trades = self.parse_trades(rawTrades, None, since, limit)
1911
+ tradesFilteredBySymbol = self.filter_by_symbol(trades, symbol)
1912
+ result = self.array_concat(result, tradesFilteredBySymbol)
1913
+ return result
1914
+
1915
+ async def fetch_orders_by_ids(self, ids, symbol: Str = None, params={}):
1916
+ """
1917
+ fetch orders by the list of order id
1918
+ :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getClosedOrders
1919
+ :param str[]|None ids: list of order id
1920
+ :param dict [params]: extra parameters specific to the kraken api endpoint
1921
+ :returns dict[]: a list of `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1922
+ """
1923
+ await self.load_markets()
1924
+ response = await self.privatePostQueryOrders(self.extend({
1925
+ 'trades': True, # whether or not to include trades in output(optional, default False)
1926
+ 'txid': ','.join(ids), # comma delimited list of transaction ids to query info about(20 maximum)
1927
+ }, params))
1928
+ result = self.safe_value(response, 'result', {})
1929
+ orders = []
1930
+ orderIds = list(result.keys())
1931
+ for i in range(0, len(orderIds)):
1932
+ id = orderIds[i]
1933
+ item = result[id]
1934
+ order = self.parse_order(self.extend({'id': id}, item))
1935
+ orders.append(order)
1936
+ return orders
1937
+
1938
+ async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1939
+ """
1940
+ fetch all trades made by the user
1941
+ :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradeHistory
1942
+ :param str symbol: unified market symbol
1943
+ :param int [since]: the earliest time in ms to fetch trades for
1944
+ :param int [limit]: the maximum number of trades structures to retrieve
1945
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1946
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1947
+ """
1948
+ await self.load_markets()
1949
+ request: dict = {
1950
+ # 'type': 'all', # any position, closed position, closing position, no position
1951
+ # 'trades': False, # whether or not to include trades related to position in output
1952
+ # 'start': 1234567890, # starting unix timestamp or trade tx id of results(exclusive)
1953
+ # 'end': 1234567890, # ending unix timestamp or trade tx id of results(inclusive)
1954
+ # 'ofs' = result offset
1955
+ }
1956
+ if since is not None:
1957
+ request['start'] = self.parse_to_int(since / 1000)
1958
+ response = await self.privatePostTradesHistory(self.extend(request, params))
1959
+ #
1960
+ # {
1961
+ # "error": [],
1962
+ # "result": {
1963
+ # "trades": {
1964
+ # "GJ3NYQ-XJRTF-THZABF": {
1965
+ # "ordertxid": "TKH2SE-ZIF5E-CFI7LT",
1966
+ # "postxid": "OEN3VX-M7IF5-JNBJAM",
1967
+ # "pair": "XICNXETH",
1968
+ # "time": 1527213229.4491,
1969
+ # "type": "sell",
1970
+ # "ordertype": "limit",
1971
+ # "price": "0.001612",
1972
+ # "cost": "0.025792",
1973
+ # "fee": "0.000026",
1974
+ # "vol": "16.00000000",
1975
+ # "margin": "0.000000",
1976
+ # "misc": ""
1977
+ # },
1978
+ # ...
1979
+ # },
1980
+ # "count": 9760,
1981
+ # },
1982
+ # }
1983
+ #
1984
+ trades = response['result']['trades']
1985
+ ids = list(trades.keys())
1986
+ for i in range(0, len(ids)):
1987
+ trades[ids[i]]['id'] = ids[i]
1988
+ market = None
1989
+ if symbol is not None:
1990
+ market = self.market(symbol)
1991
+ return self.parse_trades(trades, market, since, limit)
1992
+
1993
+ async def cancel_order(self, id: str, symbol: Str = None, params={}):
1994
+ """
1995
+ cancels an open order
1996
+ :see: https://docs.kraken.com/rest/#tag/Trading/operation/cancelOrder
1997
+ :param str id: order id
1998
+ :param str symbol: unified symbol of the market the order was made in
1999
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2000
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2001
+ """
2002
+ await self.load_markets()
2003
+ response = None
2004
+ clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId', id)
2005
+ request: dict = {
2006
+ 'txid': clientOrderId, # order id or userref
2007
+ }
2008
+ params = self.omit(params, ['userref', 'clientOrderId'])
2009
+ try:
2010
+ response = await self.privatePostCancelOrder(self.extend(request, params))
2011
+ #
2012
+ # {
2013
+ # error: [],
2014
+ # result: {
2015
+ # count: '1'
2016
+ # }
2017
+ # }
2018
+ #
2019
+ except Exception as e:
2020
+ if self.last_http_response:
2021
+ if self.last_http_response.find('EOrder:Unknown order') >= 0:
2022
+ raise OrderNotFound(self.id + ' cancelOrder() error ' + self.last_http_response)
2023
+ raise e
2024
+ return self.safe_order({
2025
+ 'info': response,
2026
+ })
2027
+
2028
+ async def cancel_orders(self, ids, symbol: Str = None, params={}):
2029
+ """
2030
+ cancel multiple orders
2031
+ :see: https://docs.kraken.com/rest/#tag/Trading/operation/cancelOrderBatch
2032
+ :param str[] ids: open orders transaction ID(txid) or user reference(userref)
2033
+ :param str symbol: unified market symbol
2034
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2035
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2036
+ """
2037
+ request: dict = {
2038
+ 'orders': ids,
2039
+ }
2040
+ response = await self.privatePostCancelOrderBatch(self.extend(request, params))
2041
+ #
2042
+ # {
2043
+ # "error": [],
2044
+ # "result": {
2045
+ # "count": 2
2046
+ # }
2047
+ # }
2048
+ #
2049
+ return [
2050
+ self.safe_order({
2051
+ 'info': response,
2052
+ }),
2053
+ ]
2054
+
2055
+ async def cancel_all_orders(self, symbol: Str = None, params={}):
2056
+ """
2057
+ cancel all open orders
2058
+ :see: https://docs.kraken.com/rest/#tag/Trading/operation/cancelAllOrders
2059
+ :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
2060
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2061
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2062
+ """
2063
+ await self.load_markets()
2064
+ response = await self.privatePostCancelAll(params)
2065
+ #
2066
+ # {
2067
+ # error: [],
2068
+ # result: {
2069
+ # count: '1'
2070
+ # }
2071
+ # }
2072
+ #
2073
+ return [
2074
+ self.safe_order({
2075
+ 'info': response,
2076
+ }),
2077
+ ]
2078
+
2079
+ async def cancel_all_orders_after(self, timeout: Int, params={}):
2080
+ """
2081
+ dead man's switch, cancel all orders after the given timeout
2082
+ :see: https://docs.kraken.com/rest/#tag/Spot-Trading/operation/cancelAllOrdersAfter
2083
+ :param number timeout: time in milliseconds, 0 represents cancel the timer
2084
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2085
+ :returns dict: the api result
2086
+ """
2087
+ if timeout > 86400000:
2088
+ raise BadRequest(self.id + 'cancelAllOrdersAfter timeout should be less than 86400000 milliseconds')
2089
+ await self.load_markets()
2090
+ request: dict = {
2091
+ 'timeout': (self.parse_to_int(timeout / 1000)) if (timeout > 0) else 0,
2092
+ }
2093
+ response = await self.privatePostCancelAllOrdersAfter(self.extend(request, params))
2094
+ #
2095
+ # {
2096
+ # "error": [],
2097
+ # "result": {
2098
+ # "currentTime": "2023-03-24T17:41:56Z",
2099
+ # "triggerTime": "2023-03-24T17:42:56Z"
2100
+ # }
2101
+ # }
2102
+ #
2103
+ return response
2104
+
2105
+ async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2106
+ """
2107
+ fetch all unfilled currently open orders
2108
+ :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getOpenOrders
2109
+ :param str symbol: unified market symbol
2110
+ :param int [since]: the earliest time in ms to fetch open orders for
2111
+ :param int [limit]: the maximum number of open orders structures to retrieve
2112
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2113
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2114
+ """
2115
+ await self.load_markets()
2116
+ request: dict = {}
2117
+ if since is not None:
2118
+ request['start'] = self.parse_to_int(since / 1000)
2119
+ query = params
2120
+ clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId')
2121
+ if clientOrderId is not None:
2122
+ request['userref'] = clientOrderId
2123
+ query = self.omit(params, ['userref', 'clientOrderId'])
2124
+ response = await self.privatePostOpenOrders(self.extend(request, query))
2125
+ market = None
2126
+ if symbol is not None:
2127
+ market = self.market(symbol)
2128
+ result = self.safe_dict(response, 'result', {})
2129
+ orders = self.safe_dict(result, 'open', {})
2130
+ return self.parse_orders(orders, market, since, limit)
2131
+
2132
+ async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2133
+ """
2134
+ fetches information on multiple closed orders made by the user
2135
+ :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getClosedOrders
2136
+ :param str symbol: unified market symbol of the market orders were made in
2137
+ :param int [since]: the earliest time in ms to fetch orders for
2138
+ :param int [limit]: the maximum number of order structures to retrieve
2139
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2140
+ :param int [params.until]: timestamp in ms of the latest entry
2141
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2142
+ """
2143
+ await self.load_markets()
2144
+ request: dict = {}
2145
+ if since is not None:
2146
+ request['start'] = self.parse_to_int(since / 1000)
2147
+ query = params
2148
+ clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId')
2149
+ if clientOrderId is not None:
2150
+ request['userref'] = clientOrderId
2151
+ query = self.omit(params, ['userref', 'clientOrderId'])
2152
+ request, params = self.handle_until_option('end', request, params)
2153
+ response = await self.privatePostClosedOrders(self.extend(request, query))
2154
+ #
2155
+ # {
2156
+ # "error":[],
2157
+ # "result":{
2158
+ # "closed":{
2159
+ # "OETZYO-UL524-QJMXCT":{
2160
+ # "refid":null,
2161
+ # "userref":null,
2162
+ # "status":"canceled",
2163
+ # "reason":"User requested",
2164
+ # "opentm":1601489313.3898,
2165
+ # "closetm":1601489346.5507,
2166
+ # "starttm":0,
2167
+ # "expiretm":0,
2168
+ # "descr":{
2169
+ # "pair":"ETHUSDT",
2170
+ # "type":"buy",
2171
+ # "ordertype":"limit",
2172
+ # "price":"330.00",
2173
+ # "price2":"0",
2174
+ # "leverage":"none",
2175
+ # "order":"buy 0.02100000 ETHUSDT @ limit 330.00",
2176
+ # "close":""
2177
+ # },
2178
+ # "vol":"0.02100000",
2179
+ # "vol_exec":"0.00000000",
2180
+ # "cost":"0.00000",
2181
+ # "fee":"0.00000",
2182
+ # "price":"0.00000",
2183
+ # "stopprice":"0.00000",
2184
+ # "limitprice":"0.00000",
2185
+ # "misc":"",
2186
+ # "oflags":"fciq"
2187
+ # },
2188
+ # },
2189
+ # "count":16
2190
+ # }
2191
+ # }
2192
+ #
2193
+ market = None
2194
+ if symbol is not None:
2195
+ market = self.market(symbol)
2196
+ result = self.safe_dict(response, 'result', {})
2197
+ orders = self.safe_dict(result, 'closed', {})
2198
+ return self.parse_orders(orders, market, since, limit)
2199
+
2200
+ def parse_transaction_status(self, status: Str):
2201
+ # IFEX transaction states
2202
+ statuses: dict = {
2203
+ 'Initial': 'pending',
2204
+ 'Pending': 'pending',
2205
+ 'Success': 'ok',
2206
+ 'Settled': 'pending',
2207
+ 'Failure': 'failed',
2208
+ 'Partial': 'ok',
2209
+ }
2210
+ return self.safe_string(statuses, status, status)
2211
+
2212
+ def parse_network(self, network):
2213
+ withdrawMethods = self.safe_value(self.options, 'withdrawMethods', {})
2214
+ return self.safe_string(withdrawMethods, network, network)
2215
+
2216
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
2217
+ #
2218
+ # fetchDeposits
2219
+ #
2220
+ # {
2221
+ # "method": "Ether(Hex)",
2222
+ # "aclass": "currency",
2223
+ # "asset": "XETH",
2224
+ # "refid": "Q2CANKL-LBFVEE-U4Y2WQ",
2225
+ # "txid": "0x57fd704dab1a73c20e24c8696099b695d596924b401b261513cfdab23…",
2226
+ # "info": "0x615f9ba7a9575b0ab4d571b2b36b1b324bd83290",
2227
+ # "amount": "7.9999257900",
2228
+ # "fee": "0.0000000000",
2229
+ # "time": 1529223212,
2230
+ # "status": "Success"
2231
+ # }
2232
+ #
2233
+ # there can be an additional 'status-prop' field present
2234
+ # deposit pending review by exchange => 'on-hold'
2235
+ # the deposit is initiated by the exchange => 'return'
2236
+ #
2237
+ # {
2238
+ # "type": 'deposit',
2239
+ # "method": 'Fidor Bank AG(Wire Transfer)',
2240
+ # "aclass": 'currency',
2241
+ # "asset": 'ZEUR',
2242
+ # "refid": 'xxx-xxx-xxx',
2243
+ # "txid": '12341234',
2244
+ # "info": 'BANKCODEXXX',
2245
+ # "amount": '38769.08',
2246
+ # "fee": '0.0000',
2247
+ # "time": 1644306552,
2248
+ # "status": 'Success',
2249
+ # status-prop: 'on-hold'
2250
+ # }
2251
+ #
2252
+ #
2253
+ # fetchWithdrawals
2254
+ #
2255
+ # {
2256
+ # "method": "Ether",
2257
+ # "aclass": "currency",
2258
+ # "asset": "XETH",
2259
+ # "refid": "A2BF34S-O7LBNQ-UE4Y4O",
2260
+ # "txid": "0x288b83c6b0904d8400ef44e1c9e2187b5c8f7ea3d838222d53f701a15b5c274d",
2261
+ # "info": "0x7cb275a5e07ba943fee972e165d80daa67cb2dd0",
2262
+ # "amount": "9.9950000000",
2263
+ # "fee": "0.0050000000",
2264
+ # "time": 1530481750,
2265
+ # "status": "Success"
2266
+ # "key":"Huobi wallet",
2267
+ # "network":"Tron"
2268
+ # status-prop: 'on-hold' # self field might not be present in some cases
2269
+ # }
2270
+ #
2271
+ # withdraw
2272
+ #
2273
+ # {
2274
+ # "refid": "AGBSO6T-UFMTTQ-I7KGS6"
2275
+ # }
2276
+ #
2277
+ id = self.safe_string(transaction, 'refid')
2278
+ txid = self.safe_string(transaction, 'txid')
2279
+ timestamp = self.safe_timestamp(transaction, 'time')
2280
+ currencyId = self.safe_string(transaction, 'asset')
2281
+ code = self.safe_currency_code(currencyId, currency)
2282
+ address = self.safe_string(transaction, 'info')
2283
+ amount = self.safe_number(transaction, 'amount')
2284
+ status = self.parse_transaction_status(self.safe_string(transaction, 'status'))
2285
+ statusProp = self.safe_string(transaction, 'status-prop')
2286
+ isOnHoldDeposit = statusProp == 'on-hold'
2287
+ isCancellationRequest = statusProp == 'cancel-pending'
2288
+ isOnHoldWithdrawal = statusProp == 'onhold'
2289
+ if isOnHoldDeposit or isCancellationRequest or isOnHoldWithdrawal:
2290
+ status = 'pending'
2291
+ type = self.safe_string(transaction, 'type') # injected from the outside
2292
+ feeCost = self.safe_number(transaction, 'fee')
2293
+ if feeCost is None:
2294
+ if type == 'deposit':
2295
+ feeCost = 0
2296
+ return {
2297
+ 'info': transaction,
2298
+ 'id': id,
2299
+ 'currency': code,
2300
+ 'amount': amount,
2301
+ 'network': self.parse_network(self.safe_string(transaction, 'network')),
2302
+ 'address': address,
2303
+ 'addressTo': None,
2304
+ 'addressFrom': None,
2305
+ 'tag': None,
2306
+ 'tagTo': None,
2307
+ 'tagFrom': None,
2308
+ 'status': status,
2309
+ 'type': type,
2310
+ 'updated': None,
2311
+ 'txid': txid,
2312
+ 'timestamp': timestamp,
2313
+ 'datetime': self.iso8601(timestamp),
2314
+ 'comment': None,
2315
+ 'internal': None,
2316
+ 'fee': {
2317
+ 'currency': code,
2318
+ 'cost': feeCost,
2319
+ },
2320
+ }
2321
+
2322
+ def parse_transactions_by_type(self, type, transactions, code: Str = None, since: Int = None, limit: Int = None):
2323
+ result = []
2324
+ for i in range(0, len(transactions)):
2325
+ transaction = self.parse_transaction(self.extend({
2326
+ 'type': type,
2327
+ }, transactions[i]))
2328
+ result.append(transaction)
2329
+ return self.filter_by_currency_since_limit(result, code, since, limit)
2330
+
2331
+ async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2332
+ """
2333
+ fetch all deposits made to an account
2334
+ :see: https://docs.kraken.com/rest/#tag/Funding/operation/getStatusRecentDeposits
2335
+ :param str code: unified currency code
2336
+ :param int [since]: the earliest time in ms to fetch deposits for
2337
+ :param int [limit]: the maximum number of deposits structures to retrieve
2338
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2339
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2340
+ """
2341
+ # https://www.kraken.com/en-us/help/api#deposit-status
2342
+ if code is None:
2343
+ raise ArgumentsRequired(self.id + ' fetchDeposits() requires a currency code argument')
2344
+ await self.load_markets()
2345
+ currency = self.currency(code)
2346
+ request: dict = {
2347
+ 'asset': currency['id'],
2348
+ }
2349
+ if since is not None:
2350
+ request['start'] = since
2351
+ response = await self.privatePostDepositStatus(self.extend(request, params))
2352
+ #
2353
+ # { error: [],
2354
+ # "result": [{"method": "Ether(Hex)",
2355
+ # "aclass": "currency",
2356
+ # "asset": "XETH",
2357
+ # "refid": "Q2CANKL-LBFVEE-U4Y2WQ",
2358
+ # "txid": "0x57fd704dab1a73c20e24c8696099b695d596924b401b261513cfdab23…",
2359
+ # "info": "0x615f9ba7a9575b0ab4d571b2b36b1b324bd83290",
2360
+ # "amount": "7.9999257900",
2361
+ # "fee": "0.0000000000",
2362
+ # "time": 1529223212,
2363
+ # "status": "Success" }]}
2364
+ #
2365
+ return self.parse_transactions_by_type('deposit', response['result'], code, since, limit)
2366
+
2367
+ async def fetch_time(self, params={}):
2368
+ """
2369
+ fetches the current integer timestamp in milliseconds from the exchange server
2370
+ :see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getServerTime
2371
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2372
+ :returns int: the current integer timestamp in milliseconds from the exchange server
2373
+ """
2374
+ # https://www.kraken.com/en-us/features/api#get-server-time
2375
+ response = await self.publicGetTime(params)
2376
+ #
2377
+ # {
2378
+ # "error": [],
2379
+ # "result": {
2380
+ # "unixtime": 1591502873,
2381
+ # "rfc1123": "Sun, 7 Jun 20 04:07:53 +0000"
2382
+ # }
2383
+ # }
2384
+ #
2385
+ result = self.safe_value(response, 'result', {})
2386
+ return self.safe_timestamp(result, 'unixtime')
2387
+
2388
+ async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2389
+ """
2390
+ fetch all withdrawals made from an account
2391
+ :see: https://docs.kraken.com/rest/#tag/Funding/operation/getStatusRecentWithdrawals
2392
+ :param str code: unified currency code
2393
+ :param int [since]: the earliest time in ms to fetch withdrawals for
2394
+ :param int [limit]: the maximum number of withdrawals structures to retrieve
2395
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2396
+ :param dict [params.end]: End timestamp, withdrawals created strictly after will be not be included in the response
2397
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times
2398
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2399
+ """
2400
+ await self.load_markets()
2401
+ paginate = False
2402
+ paginate, params = self.handle_option_and_params(params, 'fetchWithdrawals', 'paginate')
2403
+ if paginate:
2404
+ params['cursor'] = True
2405
+ return await self.fetch_paginated_call_cursor('fetchWithdrawals', code, since, limit, params, 'next_cursor', 'cursor')
2406
+ request: dict = {}
2407
+ if code is not None:
2408
+ currency = self.currency(code)
2409
+ request['asset'] = currency['id']
2410
+ if since is not None:
2411
+ request['since'] = str(since)
2412
+ response = await self.privatePostWithdrawStatus(self.extend(request, params))
2413
+ #
2414
+ # with no pagination
2415
+ # { error: [],
2416
+ # "result": [{"method": "Ether",
2417
+ # "aclass": "currency",
2418
+ # "asset": "XETH",
2419
+ # "refid": "A2BF34S-O7LBNQ-UE4Y4O",
2420
+ # "txid": "0x298c83c7b0904d8400ef43e1c9e2287b518f7ea3d838822d53f704a1565c274d",
2421
+ # "info": "0x7cb275a5e07ba943fee972e165d80daa67cb2dd0",
2422
+ # "amount": "9.9950000000",
2423
+ # "fee": "0.0050000000",
2424
+ # "time": 1530481750,
2425
+ # "status": "Success" }]}
2426
+ # with pagination
2427
+ # {
2428
+ # "error":[],
2429
+ # "result":{
2430
+ # "withdrawals":[
2431
+ # {
2432
+ # "method":"Tether USD(TRC20)",
2433
+ # "aclass":"currency",
2434
+ # "asset":"USDT",
2435
+ # "refid":"BSNFZU2-MEFN4G-J3NEZV",
2436
+ # "txid":"1c7a642fb7387bbc2c6a2c509fd1ae146937f4cf793b4079a4f0715e3a02615a",
2437
+ # "info":"TQmdxSuC16EhFg8FZWtYgrfFRosoRF7bCp",
2438
+ # "amount":"1996.50000000",
2439
+ # "fee":"2.50000000",
2440
+ # "time":1669126657,
2441
+ # "status":"Success",
2442
+ # "key":"poloniex",
2443
+ # "network":"Tron"
2444
+ # },
2445
+ # ...
2446
+ # ],
2447
+ # "next_cursor":"HgAAAAAAAABGVFRSd3k1LVF4Y0JQY05Gd0xRY0NxenFndHpybkwBAQH2AwEBAAAAAQAAAAAAAAABAAAAAAAZAAAAAAAAAA=="
2448
+ # }
2449
+ # }
2450
+ #
2451
+ rawWithdrawals = None
2452
+ result = self.safe_value(response, 'result')
2453
+ if not isinstance(result, list):
2454
+ rawWithdrawals = self.add_pagination_cursor_to_result(result)
2455
+ else:
2456
+ rawWithdrawals = result
2457
+ return self.parse_transactions_by_type('withdrawal', rawWithdrawals, code, since, limit)
2458
+
2459
+ def add_pagination_cursor_to_result(self, result):
2460
+ cursor = self.safe_string(result, 'next_cursor')
2461
+ data = self.safe_value(result, 'withdrawals')
2462
+ dataLength = len(data)
2463
+ if cursor is not None and dataLength > 0:
2464
+ last = data[dataLength - 1]
2465
+ last['next_cursor'] = cursor
2466
+ data[dataLength - 1] = last
2467
+ return data
2468
+
2469
+ async def create_deposit_address(self, code: str, params={}):
2470
+ """
2471
+ create a currency deposit address
2472
+ :see: https://docs.kraken.com/rest/#tag/Funding/operation/getDepositAddresses
2473
+ :param str code: unified currency code of the currency for the deposit address
2474
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2475
+ :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
2476
+ """
2477
+ request: dict = {
2478
+ 'new': 'true',
2479
+ }
2480
+ return await self.fetch_deposit_address(code, self.extend(request, params))
2481
+
2482
+ async def fetch_deposit_methods(self, code: str, params={}):
2483
+ """
2484
+ fetch deposit methods for a currency associated with self account
2485
+ :see: https://docs.kraken.com/rest/#tag/Funding/operation/getDepositMethods
2486
+ :param str code: unified currency code
2487
+ :param dict [params]: extra parameters specific to the kraken api endpoint
2488
+ :returns dict: of deposit methods
2489
+ """
2490
+ await self.load_markets()
2491
+ currency = self.currency(code)
2492
+ request: dict = {
2493
+ 'asset': currency['id'],
2494
+ }
2495
+ response = await self.privatePostDepositMethods(self.extend(request, params))
2496
+ #
2497
+ # {
2498
+ # "error":[],
2499
+ # "result":[
2500
+ # {"method":"Ether(Hex)","limit":false,"gen-address":true}
2501
+ # ]
2502
+ # }
2503
+ #
2504
+ # {
2505
+ # "error":[],
2506
+ # "result":[
2507
+ # {"method":"Tether USD(ERC20)","limit":false,"address-setup-fee":"0.00000000","gen-address":true},
2508
+ # {"method":"Tether USD(TRC20)","limit":false,"address-setup-fee":"0.00000000","gen-address":true}
2509
+ # ]
2510
+ # }
2511
+ #
2512
+ # {
2513
+ # "error":[],
2514
+ # "result":[
2515
+ # {"method":"Bitcoin","limit":false,"fee":"0.0000000000","gen-address":true}
2516
+ # ]
2517
+ # }
2518
+ #
2519
+ return self.safe_value(response, 'result')
2520
+
2521
+ async def fetch_deposit_address(self, code: str, params={}):
2522
+ """
2523
+ fetch the deposit address for a currency associated with self account
2524
+ :see: https://docs.kraken.com/rest/#tag/Funding/operation/getDepositAddresses
2525
+ :param str code: unified currency code
2526
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2527
+ :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
2528
+ """
2529
+ await self.load_markets()
2530
+ currency = self.currency(code)
2531
+ network = self.safe_string_upper(params, 'network')
2532
+ networks = self.safe_value(self.options, 'networks', {})
2533
+ network = self.safe_string(networks, network, network) # support ETH > ERC20 aliases
2534
+ params = self.omit(params, 'network')
2535
+ if (code == 'USDT') and (network == 'TRC20'):
2536
+ code = code + '-' + network
2537
+ defaultDepositMethods = self.safe_value(self.options, 'depositMethods', {})
2538
+ defaultDepositMethod = self.safe_string(defaultDepositMethods, code)
2539
+ depositMethod = self.safe_string(params, 'method', defaultDepositMethod)
2540
+ # if the user has specified an exchange-specific method in params
2541
+ # we pass it, otherwise we take the 'network' unified param
2542
+ if depositMethod is None:
2543
+ depositMethods = await self.fetch_deposit_methods(code)
2544
+ if network is not None:
2545
+ # find best matching deposit method, or fallback to the first one
2546
+ for i in range(0, len(depositMethods)):
2547
+ entry = self.safe_string(depositMethods[i], 'method')
2548
+ if entry.find(network) >= 0:
2549
+ depositMethod = entry
2550
+ break
2551
+ # if depositMethod was not specified, fallback to the first available deposit method
2552
+ if depositMethod is None:
2553
+ firstDepositMethod = self.safe_value(depositMethods, 0, {})
2554
+ depositMethod = self.safe_string(firstDepositMethod, 'method')
2555
+ request: dict = {
2556
+ 'asset': currency['id'],
2557
+ 'method': depositMethod,
2558
+ }
2559
+ response = await self.privatePostDepositAddresses(self.extend(request, params))
2560
+ #
2561
+ # {
2562
+ # "error":[],
2563
+ # "result":[
2564
+ # {"address":"0x77b5051f97efa9cc52c9ad5b023a53fc15c200d3","expiretm":"0"}
2565
+ # ]
2566
+ # }
2567
+ #
2568
+ result = self.safe_value(response, 'result', [])
2569
+ firstResult = self.safe_value(result, 0, {})
2570
+ if firstResult is None:
2571
+ raise InvalidAddress(self.id + ' privatePostDepositAddresses() returned no addresses for ' + code)
2572
+ return self.parse_deposit_address(firstResult, currency)
2573
+
2574
+ def parse_deposit_address(self, depositAddress, currency: Currency = None):
2575
+ #
2576
+ # {
2577
+ # "address":"0x77b5051f97efa9cc52c9ad5b023a53fc15c200d3",
2578
+ # "expiretm":"0"
2579
+ # }
2580
+ #
2581
+ address = self.safe_string(depositAddress, 'address')
2582
+ tag = self.safe_string(depositAddress, 'tag')
2583
+ currency = self.safe_currency(None, currency)
2584
+ code = currency['code']
2585
+ self.check_address(address)
2586
+ return {
2587
+ 'currency': code,
2588
+ 'address': address,
2589
+ 'tag': tag,
2590
+ 'network': None,
2591
+ 'info': depositAddress,
2592
+ }
2593
+
2594
+ async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
2595
+ """
2596
+ make a withdrawal
2597
+ :see: https://docs.kraken.com/rest/#tag/Funding/operation/withdrawFunds
2598
+ :param str code: unified currency code
2599
+ :param float amount: the amount to withdraw
2600
+ :param str address: the address to withdraw to
2601
+ :param str tag:
2602
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2603
+ :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
2604
+ """
2605
+ tag, params = self.handle_withdraw_tag_and_params(tag, params)
2606
+ self.check_address(address)
2607
+ if 'key' in params:
2608
+ await self.load_markets()
2609
+ currency = self.currency(code)
2610
+ request: dict = {
2611
+ 'asset': currency['id'],
2612
+ 'amount': amount,
2613
+ 'address': address,
2614
+ }
2615
+ response = await self.privatePostWithdraw(self.extend(request, params))
2616
+ #
2617
+ # {
2618
+ # "error": [],
2619
+ # "result": {
2620
+ # "refid": "AGBSO6T-UFMTTQ-I7KGS6"
2621
+ # }
2622
+ # }
2623
+ #
2624
+ result = self.safe_dict(response, 'result', {})
2625
+ return self.parse_transaction(result, currency)
2626
+ raise ExchangeError(self.id + " withdraw() requires a 'key' parameter(withdrawal key name, up on your account)")
2627
+
2628
+ async def fetch_positions(self, symbols: Strings = None, params={}):
2629
+ """
2630
+ fetch all open positions
2631
+ :see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getOpenPositions
2632
+ :param str[] [symbols]: not used by kraken fetchPositions()
2633
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2634
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
2635
+ """
2636
+ await self.load_markets()
2637
+ request: dict = {
2638
+ # 'txid': 'comma delimited list of transaction ids to restrict output to',
2639
+ 'docalcs': 'true', # whether or not to include profit/loss calculations
2640
+ 'consolidation': 'market', # what to consolidate the positions data around, market will consolidate positions based on market pair
2641
+ }
2642
+ response = await self.privatePostOpenPositions(self.extend(request, params))
2643
+ #
2644
+ # no consolidation
2645
+ #
2646
+ # {
2647
+ # "error": [],
2648
+ # "result": {
2649
+ # 'TGUFMY-FLESJ-VYIX3J': {
2650
+ # "ordertxid": "O3LRNU-ZKDG5-XNCDFR",
2651
+ # "posstatus": "open",
2652
+ # "pair": "ETHUSDT",
2653
+ # "time": 1611557231.4584,
2654
+ # "type": "buy",
2655
+ # "ordertype": "market",
2656
+ # "cost": "28.49800",
2657
+ # "fee": "0.07979",
2658
+ # "vol": "0.02000000",
2659
+ # "vol_closed": "0.00000000",
2660
+ # "margin": "14.24900",
2661
+ # "terms": "0.0200% per 4 hours",
2662
+ # "rollovertm": "1611571631",
2663
+ # "misc": "",
2664
+ # "oflags": ""
2665
+ # }
2666
+ # }
2667
+ # }
2668
+ #
2669
+ # consolidation by market
2670
+ #
2671
+ # {
2672
+ # "error": [],
2673
+ # "result": [
2674
+ # {
2675
+ # "pair": "ETHUSDT",
2676
+ # "positions": "1",
2677
+ # "type": "buy",
2678
+ # "leverage": "2.00000",
2679
+ # "cost": "28.49800",
2680
+ # "fee": "0.07979",
2681
+ # "vol": "0.02000000",
2682
+ # "vol_closed": "0.00000000",
2683
+ # "margin": "14.24900"
2684
+ # }
2685
+ # ]
2686
+ # }
2687
+ #
2688
+ symbols = self.market_symbols(symbols)
2689
+ result = self.safe_list(response, 'result')
2690
+ results = self.parse_positions(result, symbols)
2691
+ return self.filter_by_array_positions(results, 'symbol', symbols, False)
2692
+
2693
+ def parse_position(self, position: dict, market: Market = None):
2694
+ #
2695
+ # {
2696
+ # "pair": "ETHUSDT",
2697
+ # "positions": "1",
2698
+ # "type": "buy",
2699
+ # "leverage": "2.00000",
2700
+ # "cost": "28.49800",
2701
+ # "fee": "0.07979",
2702
+ # "vol": "0.02000000",
2703
+ # "vol_closed": "0.00000000",
2704
+ # "margin": "14.24900"
2705
+ # }
2706
+ #
2707
+ marketId = self.safe_string(position, 'pair')
2708
+ rawSide = self.safe_string(position, 'type')
2709
+ side = 'long' if (rawSide == 'buy') else 'short'
2710
+ return self.safe_position({
2711
+ 'info': position,
2712
+ 'id': None,
2713
+ 'symbol': self.safe_symbol(marketId, market),
2714
+ 'notional': None,
2715
+ 'marginMode': None,
2716
+ 'liquidationPrice': None,
2717
+ 'entryPrice': None,
2718
+ 'unrealizedPnl': self.safe_number(position, 'net'),
2719
+ 'realizedPnl': None,
2720
+ 'percentage': None,
2721
+ 'contracts': self.safe_number(position, 'vol'),
2722
+ 'contractSize': None,
2723
+ 'markPrice': None,
2724
+ 'lastPrice': None,
2725
+ 'side': side,
2726
+ 'hedged': None,
2727
+ 'timestamp': None,
2728
+ 'datetime': None,
2729
+ 'lastUpdateTimestamp': None,
2730
+ 'maintenanceMargin': None,
2731
+ 'maintenanceMarginPercentage': None,
2732
+ 'collateral': None,
2733
+ 'initialMargin': self.safe_number(position, 'margin'),
2734
+ 'initialMarginPercentage': None,
2735
+ 'leverage': self.safe_number(position, 'leverage'),
2736
+ 'marginRatio': None,
2737
+ 'stopLossPrice': None,
2738
+ 'takeProfitPrice': None,
2739
+ })
2740
+
2741
+ def parse_account_type(self, account):
2742
+ accountByType: dict = {
2743
+ 'spot': 'Spot Wallet',
2744
+ 'swap': 'Futures Wallet',
2745
+ 'future': 'Futures Wallet',
2746
+ }
2747
+ return self.safe_string(accountByType, account, account)
2748
+
2749
+ async def transfer_out(self, code: str, amount, params={}):
2750
+ """
2751
+ transfer from spot wallet to futures wallet
2752
+ :see: https://docs.kraken.com/rest/#tag/User-Funding/operation/walletTransfer
2753
+ :param str code: Unified currency code
2754
+ :param float amount: Size of the transfer
2755
+ :param dict [params]: Exchange specific parameters
2756
+ :returns: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
2757
+ """
2758
+ return await self.transfer(code, amount, 'spot', 'swap', params)
2759
+
2760
+ async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
2761
+ """
2762
+ :see: https://docs.kraken.com/rest/#tag/User-Funding/operation/walletTransfer
2763
+ transfers currencies between sub-accounts(only spot->swap direction is supported)
2764
+ :param str code: Unified currency code
2765
+ :param float amount: Size of the transfer
2766
+ :param str fromAccount: 'spot' or 'Spot Wallet'
2767
+ :param str toAccount: 'swap' or 'Futures Wallet'
2768
+ :param dict [params]: Exchange specific parameters
2769
+ :returns: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
2770
+ """
2771
+ await self.load_markets()
2772
+ currency = self.currency(code)
2773
+ fromAccount = self.parse_account_type(fromAccount)
2774
+ toAccount = self.parse_account_type(toAccount)
2775
+ request: dict = {
2776
+ 'amount': self.currency_to_precision(code, amount),
2777
+ 'from': fromAccount,
2778
+ 'to': toAccount,
2779
+ 'asset': currency['id'],
2780
+ }
2781
+ if fromAccount != 'Spot Wallet':
2782
+ raise BadRequest(self.id + ' transfer cannot transfer from ' + fromAccount + ' to ' + toAccount + '. Use krakenfutures instead to transfer from the futures account.')
2783
+ response = await self.privatePostWalletTransfer(self.extend(request, params))
2784
+ #
2785
+ # {
2786
+ # "error":[
2787
+ # ],
2788
+ # "result":{
2789
+ # "refid":"BOIUSIF-M7DLMN-UXZ3P5"
2790
+ # }
2791
+ # }
2792
+ #
2793
+ transfer = self.parse_transfer(response, currency)
2794
+ return self.extend(transfer, {
2795
+ 'amount': amount,
2796
+ 'fromAccount': fromAccount,
2797
+ 'toAccount': toAccount,
2798
+ })
2799
+
2800
+ def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
2801
+ #
2802
+ # transfer
2803
+ #
2804
+ # {
2805
+ # "error":[
2806
+ # ],
2807
+ # "result":{
2808
+ # "refid":"BOIUSIF-M7DLMN-UXZ3P5"
2809
+ # }
2810
+ # }
2811
+ #
2812
+ result = self.safe_value(transfer, 'result', {})
2813
+ refid = self.safe_string(result, 'refid')
2814
+ return {
2815
+ 'info': transfer,
2816
+ 'id': refid,
2817
+ 'timestamp': None,
2818
+ 'datetime': None,
2819
+ 'currency': self.safe_string(currency, 'code'),
2820
+ 'amount': None,
2821
+ 'fromAccount': None,
2822
+ 'toAccount': None,
2823
+ 'status': 'sucess',
2824
+ }
2825
+
2826
+ def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
2827
+ url = '/' + self.version + '/' + api + '/' + path
2828
+ if api == 'public':
2829
+ if params:
2830
+ # urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
2831
+ url += '?' + self.urlencode_nested(params)
2832
+ elif api == 'private':
2833
+ isCancelOrderBatch = (path == 'CancelOrderBatch')
2834
+ self.check_required_credentials()
2835
+ nonce = str(self.nonce())
2836
+ # urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
2837
+ if isCancelOrderBatch:
2838
+ body = self.json(self.extend({'nonce': nonce}, params))
2839
+ else:
2840
+ body = self.urlencode_nested(self.extend({'nonce': nonce}, params))
2841
+ auth = self.encode(nonce + body)
2842
+ hash = self.hash(auth, 'sha256', 'binary')
2843
+ binary = self.encode(url)
2844
+ binhash = self.binary_concat(binary, hash)
2845
+ secret = self.base64_to_binary(self.secret)
2846
+ signature = self.hmac(binhash, secret, hashlib.sha512, 'base64')
2847
+ headers = {
2848
+ 'API-Key': self.apiKey,
2849
+ 'API-Sign': signature,
2850
+ # 'Content-Type': 'application/x-www-form-urlencoded',
2851
+ }
2852
+ if isCancelOrderBatch:
2853
+ headers['Content-Type'] = 'application/json'
2854
+ else:
2855
+ headers['Content-Type'] = 'application/x-www-form-urlencoded'
2856
+ else:
2857
+ url = '/' + path
2858
+ url = self.urls['api'][api] + url
2859
+ return {'url': url, 'method': method, 'body': body, 'headers': headers}
2860
+
2861
+ def nonce(self):
2862
+ return self.milliseconds()
2863
+
2864
+ def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
2865
+ if code == 520:
2866
+ raise ExchangeNotAvailable(self.id + ' ' + str(code) + ' ' + reason)
2867
+ # todo: rewrite self for "broad" exceptions matching
2868
+ if body.find('Invalid order') >= 0:
2869
+ raise InvalidOrder(self.id + ' ' + body)
2870
+ if body.find('Invalid nonce') >= 0:
2871
+ raise InvalidNonce(self.id + ' ' + body)
2872
+ if body.find('Insufficient funds') >= 0:
2873
+ raise InsufficientFunds(self.id + ' ' + body)
2874
+ if body.find('Cancel pending') >= 0:
2875
+ raise CancelPending(self.id + ' ' + body)
2876
+ if body.find('Invalid arguments:volume') >= 0:
2877
+ raise InvalidOrder(self.id + ' ' + body)
2878
+ if body.find('Invalid arguments:viqc') >= 0:
2879
+ raise InvalidOrder(self.id + ' ' + body)
2880
+ if body.find('Rate limit exceeded') >= 0:
2881
+ raise RateLimitExceeded(self.id + ' ' + body)
2882
+ if response is None:
2883
+ return None
2884
+ if body[0] == '{':
2885
+ if not isinstance(response, str):
2886
+ if 'error' in response:
2887
+ numErrors = len(response['error'])
2888
+ if numErrors:
2889
+ message = self.id + ' ' + body
2890
+ for i in range(0, len(response['error'])):
2891
+ error = response['error'][i]
2892
+ self.throw_exactly_matched_exception(self.exceptions, error, message)
2893
+ raise ExchangeError(message)
2894
+ return None