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,2473 @@
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.wavesexchange import ImplicitAPI
8
+ import asyncio
9
+ import json
10
+ from ccxt.base.types import Balances, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
11
+ from typing import List
12
+ from typing import Any
13
+ from ccxt.base.errors import ExchangeError
14
+ from ccxt.base.errors import AuthenticationError
15
+ from ccxt.base.errors import AccountSuspended
16
+ from ccxt.base.errors import ArgumentsRequired
17
+ from ccxt.base.errors import BadRequest
18
+ from ccxt.base.errors import BadSymbol
19
+ from ccxt.base.errors import InsufficientFunds
20
+ from ccxt.base.errors import InvalidOrder
21
+ from ccxt.base.errors import OrderNotFound
22
+ from ccxt.base.errors import DuplicateOrderId
23
+ from ccxt.base.errors import ExchangeNotAvailable
24
+ from ccxt.base.decimal_to_precision import TICK_SIZE
25
+ from ccxt.base.precise import Precise
26
+
27
+
28
+ class wavesexchange(Exchange, ImplicitAPI):
29
+
30
+ def describe(self):
31
+ return self.deep_extend(super(wavesexchange, self).describe(), {
32
+ 'id': 'wavesexchange',
33
+ 'name': 'Waves.Exchange',
34
+ 'countries': ['CH'], # Switzerland
35
+ 'certified': False,
36
+ 'pro': False,
37
+ 'dex': True,
38
+ 'has': {
39
+ 'CORS': None,
40
+ 'spot': True,
41
+ 'margin': False,
42
+ 'swap': False,
43
+ 'future': False,
44
+ 'option': False,
45
+ 'addMargin': False,
46
+ 'cancelOrder': True,
47
+ 'closeAllPositions': False,
48
+ 'closePosition': False,
49
+ 'createMarketOrder': True,
50
+ 'createOrder': True,
51
+ 'createReduceOnlyOrder': False,
52
+ 'createStopLimitOrder': False,
53
+ 'createStopMarketOrder': False,
54
+ 'createStopOrder': False,
55
+ 'fetchBalance': True,
56
+ 'fetchBorrowRateHistories': False,
57
+ 'fetchBorrowRateHistory': False,
58
+ 'fetchClosedOrders': True,
59
+ 'fetchCrossBorrowRate': False,
60
+ 'fetchCrossBorrowRates': False,
61
+ 'fetchDepositAddress': True,
62
+ 'fetchDepositWithdrawFee': 'emulated',
63
+ 'fetchDepositWithdrawFees': True,
64
+ 'fetchFundingHistory': False,
65
+ 'fetchFundingRate': False,
66
+ 'fetchFundingRateHistory': False,
67
+ 'fetchFundingRates': False,
68
+ 'fetchIndexOHLCV': False,
69
+ 'fetchIsolatedBorrowRate': False,
70
+ 'fetchIsolatedBorrowRates': False,
71
+ 'fetchLeverage': False,
72
+ 'fetchLeverageTiers': False,
73
+ 'fetchMarginMode': False,
74
+ 'fetchMarkets': True,
75
+ 'fetchMarkOHLCV': False,
76
+ 'fetchMyTrades': True,
77
+ 'fetchOHLCV': True,
78
+ 'fetchOpenInterestHistory': False,
79
+ 'fetchOpenOrders': True,
80
+ 'fetchOrder': True,
81
+ 'fetchOrderBook': True,
82
+ 'fetchOrders': True,
83
+ 'fetchPosition': False,
84
+ 'fetchPositionHistory': False,
85
+ 'fetchPositionMode': False,
86
+ 'fetchPositions': False,
87
+ 'fetchPositionsForSymbol': False,
88
+ 'fetchPositionsHistory': False,
89
+ 'fetchPositionsRisk': False,
90
+ 'fetchPremiumIndexOHLCV': False,
91
+ 'fetchTicker': True,
92
+ 'fetchTickers': True,
93
+ 'fetchTrades': True,
94
+ 'fetchTransfer': False,
95
+ 'fetchTransfers': False,
96
+ 'reduceMargin': False,
97
+ 'sandbox': True,
98
+ 'setLeverage': False,
99
+ 'setMarginMode': False,
100
+ 'setPositionMode': False,
101
+ 'signIn': True,
102
+ 'transfer': False,
103
+ 'withdraw': True,
104
+ 'ws': False,
105
+ },
106
+ 'timeframes': {
107
+ '1m': '1m',
108
+ '5m': '5m',
109
+ '15m': '15m',
110
+ '30m': '30m',
111
+ '1h': '1h',
112
+ '2h': '2h',
113
+ '3h': '3h',
114
+ '4h': '4h',
115
+ '6h': '6h',
116
+ '12h': '12h',
117
+ '1d': '1d',
118
+ '1w': '1w',
119
+ '1M': '1M',
120
+ },
121
+ 'urls': {
122
+ 'logo': 'https://user-images.githubusercontent.com/1294454/84547058-5fb27d80-ad0b-11ea-8711-78ac8b3c7f31.jpg',
123
+ 'test': {
124
+ 'matcher': 'https://matcher-testnet.wx.network',
125
+ 'node': 'https://nodes-testnet.wavesnodes.com',
126
+ 'public': 'https://api-testnet.wavesplatform.com/v0',
127
+ 'private': 'https://api-testnet.wx.network/v1',
128
+ 'forward': 'https://testnet.wx.network/api/v1/forward/matcher',
129
+ 'market': 'https://testnet.wx.network/api/v1/forward/marketdata/api/v1',
130
+ },
131
+ 'api': {
132
+ 'matcher': 'https://matcher.wx.network',
133
+ 'node': 'https://nodes.wx.network',
134
+ 'public': 'https://api.wavesplatform.com/v0',
135
+ 'private': 'https://api.wx.network/v1',
136
+ 'forward': 'https://wx.network/api/v1/forward/matcher',
137
+ 'market': 'https://wx.network/api/v1/forward/marketdata/api/v1',
138
+ },
139
+ 'doc': 'https://docs.wx.network',
140
+ 'www': 'https://wx.network',
141
+ },
142
+ 'api': {
143
+ 'matcher': {
144
+ 'get': [
145
+ 'matcher',
146
+ 'matcher/settings',
147
+ 'matcher/settings/rates',
148
+ 'matcher/balance/reserved/{publicKey}',
149
+ 'matcher/debug/allSnashotOffsets',
150
+ 'matcher/debug/currentOffset',
151
+ 'matcher/debug/lastOffset',
152
+ 'matcher/debug/oldestSnapshotOffset',
153
+ 'matcher/debug/config',
154
+ 'matcher/debug/address/{address}',
155
+ 'matcher/debug/status',
156
+ 'matcher/debug/address/{address}/check',
157
+ 'matcher/orderbook',
158
+ 'matcher/orderbook/{baseId}/{quoteId}',
159
+ 'matcher/orderbook/{baseId}/{quoteId}/publicKey/{publicKey}',
160
+ 'matcher/orderbook/{baseId}/{quoteId}/{orderId}',
161
+ 'matcher/orderbook/{baseId}/{quoteId}/info',
162
+ 'matcher/orderbook/{baseId}/{quoteId}/status',
163
+ 'matcher/orderbook/{baseId}/{quoteId}/tradableBalance/{address}',
164
+ 'matcher/orderbook/{publicKey}',
165
+ 'matcher/orderbook/{publicKey}/{orderId}',
166
+ 'matcher/orders/{address}',
167
+ 'matcher/orders/{address}/{orderId}',
168
+ 'matcher/transactions/{orderId}',
169
+ 'api/v1/orderbook/{baseId}/{quoteId}',
170
+ ],
171
+ 'post': [
172
+ 'matcher/orderbook',
173
+ 'matcher/orderbook/market',
174
+ 'matcher/orderbook/cancel',
175
+ 'matcher/orderbook/{baseId}/{quoteId}/cancel',
176
+ 'matcher/orderbook/{baseId}/{quoteId}/calculateFee',
177
+ 'matcher/orderbook/{baseId}/{quoteId}/delete',
178
+ 'matcher/orderbook/{baseId}/{quoteId}/cancelAll',
179
+ 'matcher/debug/saveSnapshots',
180
+ 'matcher/orders/{address}/cancel',
181
+ 'matcher/orders/cancel/{orderId}',
182
+ 'matcher/orders/serialize',
183
+ ],
184
+ 'delete': [
185
+ 'matcher/orderbook/{baseId}/{quoteId}',
186
+ 'matcher/settings/rates/{assetId}',
187
+ ],
188
+ 'put': [
189
+ 'matcher/settings/rates/{assetId}',
190
+ ],
191
+ },
192
+ 'node': {
193
+ 'get': [
194
+ 'addresses',
195
+ 'addresses/balance/{address}',
196
+ 'addresses/balance/{address}/{confirmations}',
197
+ 'addresses/balance/details/{address}',
198
+ 'addresses/data/{address}',
199
+ 'addresses/data/{address}/{key}',
200
+ 'addresses/effectiveBalance/{address}',
201
+ 'addresses/effectiveBalance/{address}/{confirmations}',
202
+ 'addresses/publicKey/{publicKey}',
203
+ 'addresses/scriptInfo/{address}',
204
+ 'addresses/scriptInfo/{address}/meta',
205
+ 'addresses/seed/{address}',
206
+ 'addresses/seq/{from}/{to}',
207
+ 'addresses/validate/{address}',
208
+ 'alias/by-address/{address}',
209
+ 'alias/by-alias/{alias}',
210
+ 'assets/{assetId}/distribution/{height}/{limit}',
211
+ 'assets/balance/{address}',
212
+ 'assets/balance/{address}/{assetId}',
213
+ 'assets/details/{assetId}',
214
+ 'assets/nft/{address}/limit/{limit}',
215
+ 'blockchain/rewards',
216
+ 'blockchain/rewards/height',
217
+ 'blocks/address/{address}/{from}/{to}/',
218
+ 'blocks/at/{height}',
219
+ 'blocks/delay/{signature}/{blockNum}',
220
+ 'blocks/first',
221
+ 'blocks/headers/last',
222
+ 'blocks/headers/seq/{from}/{to}',
223
+ 'blocks/height',
224
+ 'blocks/height/{signature}',
225
+ 'blocks/last',
226
+ 'blocks/seq/{from}/{to}',
227
+ 'blocks/signature/{signature}',
228
+ 'consensus/algo',
229
+ 'consensus/basetarget',
230
+ 'consensus/basetarget/{blockId}',
231
+ 'consensus/{generatingbalance}/address',
232
+ 'consensus/generationsignature',
233
+ 'consensus/generationsignature/{blockId}',
234
+ 'debug/balances/history/{address}',
235
+ 'debug/blocks/{howMany}',
236
+ 'debug/configInfo',
237
+ 'debug/historyInfo',
238
+ 'debug/info',
239
+ 'debug/minerInfo',
240
+ 'debug/portfolios/{address}',
241
+ 'debug/state',
242
+ 'debug/stateChanges/address/{address}',
243
+ 'debug/stateChanges/info/{id}',
244
+ 'debug/stateWaves/{height}',
245
+ 'leasing/active/{address}',
246
+ 'node/state',
247
+ 'node/version',
248
+ 'peers/all',
249
+ 'peers/blacklisted',
250
+ 'peers/connected',
251
+ 'peers/suspended',
252
+ 'transactions/address/{address}/limit/{limit}',
253
+ 'transactions/info/{id}',
254
+ 'transactions/status',
255
+ 'transactions/unconfirmed',
256
+ 'transactions/unconfirmed/info/{id}',
257
+ 'transactions/unconfirmed/size',
258
+ 'utils/seed',
259
+ 'utils/seed/{length}',
260
+ 'utils/time',
261
+ 'wallet/seed',
262
+ ],
263
+ 'post': [
264
+ 'addresses',
265
+ 'addresses/data/{address}',
266
+ 'addresses/sign/{address}',
267
+ 'addresses/signText/{address}',
268
+ 'addresses/verify/{address}',
269
+ 'addresses/verifyText/{address}',
270
+ 'debug/blacklist',
271
+ 'debug/print',
272
+ 'debug/rollback',
273
+ 'debug/validate',
274
+ 'node/stop',
275
+ 'peers/clearblacklist',
276
+ 'peers/connect',
277
+ 'transactions/broadcast',
278
+ 'transactions/calculateFee',
279
+ 'tranasctions/sign',
280
+ 'transactions/sign/{signerAddress}',
281
+ 'tranasctions/status',
282
+ 'utils/hash/fast',
283
+ 'utils/hash/secure',
284
+ 'utils/script/compileCode',
285
+ 'utils/script/compileWithImports',
286
+ 'utils/script/decompile',
287
+ 'utils/script/estimate',
288
+ 'utils/sign/{privateKey}',
289
+ 'utils/transactionsSerialize',
290
+ ],
291
+ 'delete': [
292
+ 'addresses/{address}',
293
+ 'debug/rollback-to/{signature}',
294
+ ],
295
+ },
296
+ 'public': {
297
+ 'get': [
298
+ 'assets',
299
+ 'pairs',
300
+ 'candles/{baseId}/{quoteId}',
301
+ 'transactions/exchange',
302
+ ],
303
+ },
304
+ 'private': {
305
+ 'get': [
306
+ 'deposit/addresses/{currency}',
307
+ 'deposit/addresses/{currency}/{platform}',
308
+ 'platforms',
309
+ 'deposit/currencies',
310
+ 'withdraw/currencies',
311
+ 'withdraw/addresses/{currency}/{address}',
312
+ ],
313
+ 'post': [
314
+ 'oauth2/token',
315
+ ],
316
+ },
317
+ 'forward': {
318
+ 'get': [
319
+ 'matcher/orders/{address}', # can't get the orders endpoint to work with the matcher api
320
+ 'matcher/orders/{address}/{orderId}',
321
+ ],
322
+ 'post': [
323
+ 'matcher/orders/{wavesAddress}/cancel',
324
+ ],
325
+ },
326
+ 'market': {
327
+ 'get': [
328
+ 'tickers',
329
+ ],
330
+ },
331
+ },
332
+ 'currencies': {
333
+ 'WX': self.safe_currency_structure({'id': 'EMAMLxDnv3xiz8RXg8Btj33jcEw3wLczL3JKYYmuubpc', 'numericId': None, 'code': 'WX', 'precision': self.parse_number('1e-8')}),
334
+ },
335
+ 'precisionMode': TICK_SIZE,
336
+ 'options': {
337
+ 'allowedCandles': 1440,
338
+ 'accessToken': None,
339
+ 'createMarketBuyOrderRequiresPrice': True,
340
+ 'matcherPublicKey': None,
341
+ 'quotes': None,
342
+ 'createOrderDefaultExpiry': 2419200000, # 60 * 60 * 24 * 28 * 1000
343
+ 'wavesAddress': None,
344
+ 'withdrawFeeUSDN': 7420,
345
+ 'withdrawFeeWAVES': 100000,
346
+ 'wavesPrecision': 1e-8,
347
+ 'messagePrefix': 'W', # W for production, T for testnet
348
+ 'networks': {
349
+ 'ERC20': 'ETH',
350
+ 'BEP20': 'BSC',
351
+ },
352
+ },
353
+ 'commonCurrencies': {
354
+ 'EGG': 'Waves Ducks',
355
+ },
356
+ 'requiresEddsa': True,
357
+ 'exceptions': {
358
+ '3147270': InsufficientFunds, # https://github.com/wavesplatform/matcher/wiki/List-of-all-errors
359
+ '112': InsufficientFunds,
360
+ '4': ExchangeError,
361
+ '13': ExchangeNotAvailable,
362
+ '14': ExchangeNotAvailable,
363
+ '3145733': AccountSuspended,
364
+ '3148040': DuplicateOrderId,
365
+ '3148801': AuthenticationError,
366
+ '9440512': AuthenticationError,
367
+ '9440771': BadSymbol,
368
+ '9441026': InvalidOrder,
369
+ '9441282': InvalidOrder,
370
+ '9441286': InvalidOrder,
371
+ '9441295': InvalidOrder,
372
+ '9441540': InvalidOrder,
373
+ '9441542': InvalidOrder,
374
+ '106954752': AuthenticationError,
375
+ '106954769': AuthenticationError,
376
+ '106957828': AuthenticationError,
377
+ '106960131': AuthenticationError,
378
+ '106981137': AuthenticationError,
379
+ '9437184': BadRequest, # {"error":9437184,"message":"The order is invalid: SpendAmount should be > 0","template":"The order is invalid: {{details}}","params":{"details":"SpendAmount should be > 0"},"status":"OrderRejected","success":false}
380
+ '9437193': OrderNotFound,
381
+ '1048577': BadRequest,
382
+ '1051904': AuthenticationError,
383
+ },
384
+ })
385
+
386
+ def set_sandbox_mode(self, enabled):
387
+ self.options['messagePrefix'] = 'T' if enabled else 'W'
388
+ self.options['sandboxMode'] = enabled
389
+ super(wavesexchange, self).set_sandbox_mode(enabled)
390
+
391
+ async def get_fees_for_asset(self, symbol: str, side, amount, price, params={}):
392
+ await self.load_markets()
393
+ market = self.market(symbol)
394
+ amount = self.to_real_symbol_amount(symbol, amount)
395
+ price = self.to_real_symbol_price(symbol, price)
396
+ request = self.extend({
397
+ 'baseId': market['baseId'],
398
+ 'quoteId': market['quoteId'],
399
+ 'orderType': side,
400
+ 'amount': amount,
401
+ 'price': price,
402
+ }, params)
403
+ return await self.matcherPostMatcherOrderbookBaseIdQuoteIdCalculateFee(request)
404
+
405
+ async def custom_calculate_fee(self, symbol: str, type, side, amount, price, takerOrMaker='taker', params={}):
406
+ response = await self.get_fees_for_asset(symbol, side, amount, price)
407
+ # {
408
+ # "base":{
409
+ # "feeAssetId":"WAVES",
410
+ # "matcherFee":"1000000"
411
+ # },
412
+ # "discount":{
413
+ # "feeAssetId":"EMAMLxDnv3xiz8RXg8Btj33jcEw3wLczL3JKYYmuubpc",
414
+ # "matcherFee":"4077612"
415
+ # }
416
+ # }
417
+ isDiscountFee = self.safe_bool(params, 'isDiscountFee', False)
418
+ mode = None
419
+ if isDiscountFee:
420
+ mode = self.safe_value(response, 'discount')
421
+ else:
422
+ mode = self.safe_value(response, 'base')
423
+ matcherFee = self.safe_string(mode, 'matcherFee')
424
+ feeAssetId = self.safe_string(mode, 'feeAssetId')
425
+ feeAsset = self.safe_currency_code(feeAssetId)
426
+ adjustedMatcherFee = self.from_real_currency_amount(feeAsset, matcherFee)
427
+ amountAsString = self.number_to_string(amount)
428
+ priceAsString = self.number_to_string(price)
429
+ feeCost = self.fee_to_precision(symbol, self.parse_number(adjustedMatcherFee))
430
+ feeRate = Precise.string_div(adjustedMatcherFee, Precise.string_mul(amountAsString, priceAsString))
431
+ return {
432
+ 'type': takerOrMaker,
433
+ 'currency': feeAsset,
434
+ 'rate': self.parse_number(feeRate),
435
+ 'cost': self.parse_number(feeCost),
436
+ }
437
+
438
+ async def get_quotes(self):
439
+ quotes = self.safe_value(self.options, 'quotes')
440
+ if quotes:
441
+ return quotes
442
+ else:
443
+ # currencies can have any name because you can create you own token
444
+ # result someone can create a fake token called BTC
445
+ # we use self mapping to determine the real tokens
446
+ # https://docs.wx.network/en/waves-matcher/matcher-api#asset-pair
447
+ response = await self.matcherGetMatcherSettings()
448
+ # {
449
+ # "orderVersions": [
450
+ # 1,
451
+ # 2,
452
+ # 3
453
+ # ],
454
+ # "success": True,
455
+ # "matcherPublicKey": "9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5",
456
+ # "orderFee": {
457
+ # "dynamic": {
458
+ # "baseFee": 300000,
459
+ # "rates": {
460
+ # "34N9YcEETLWn93qYQ64EsP1x89tSruJU44RrEMSXXEPJ": 1.22639597,
461
+ # "62LyMjcr2DtiyF5yVXFhoQ2q414VPPJXjsNYp72SuDCH": 0.00989643,
462
+ # "HZk1mbfuJpmxU1Fs4AX5MWLVYtctsNcg6e2C6VKqK8zk": 0.0395674,
463
+ # "8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS": 0.00018814,
464
+ # "4LHHvYGNKJUg5hj65aGD5vgScvCBmLpdRFtjokvCjSL8": 26.19721262,
465
+ # "474jTeYx2r2Va35794tCScAXWJG9hU2HcgxzMowaZUnu": 0.00752978,
466
+ # "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p": 1.84575,
467
+ # "B3uGHFRpSUuGEDWjqB9LWWxafQj8VTvpMucEyoxzws5H": 0.02330273,
468
+ # "zMFqXuoyrn5w17PFurTqxB7GsS71fp9dfk6XFwxbPCy": 0.00721412,
469
+ # "5WvPKSJXzVE2orvbkJ8wsQmmQKqTv9sGBPksV4adViw3": 0.02659103,
470
+ # "WAVES": 1,
471
+ # "BrjUWjndUanm5VsJkbUip8VRYy6LWJePtxya3FNv4TQa": 0.03433583
472
+ # }
473
+ # }
474
+ # },
475
+ # "networkByte": 87,
476
+ # "matcherVersion": "2.1.3.5",
477
+ # "status": "SimpleResponse",
478
+ # "priceAssets": [
479
+ # "Ft8X1v1LTa1ABafufpaCWyVj8KkaxUWE6xBhW6sNFJck",
480
+ # "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p",
481
+ # "34N9YcEETLWn93qYQ64EsP1x89tSruJU44RrEMSXXEPJ",
482
+ # "Gtb1WRznfchDnTh37ezoDTJ4wcoKaRsKqKjJjy7nm2zU",
483
+ # "2mX5DzVKWrAJw8iwdJnV2qtoeVG9h5nTDpTqC1wb1WEN",
484
+ # "8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS",
485
+ # "WAVES",
486
+ # "474jTeYx2r2Va35794tCScAXWJG9hU2HcgxzMowaZUnu",
487
+ # "zMFqXuoyrn5w17PFurTqxB7GsS71fp9dfk6XFwxbPCy",
488
+ # "62LyMjcr2DtiyF5yVXFhoQ2q414VPPJXjsNYp72SuDCH",
489
+ # "HZk1mbfuJpmxU1Fs4AX5MWLVYtctsNcg6e2C6VKqK8zk",
490
+ # "B3uGHFRpSUuGEDWjqB9LWWxafQj8VTvpMucEyoxzws5H",
491
+ # "5WvPKSJXzVE2orvbkJ8wsQmmQKqTv9sGBPksV4adViw3",
492
+ # "BrjUWjndUanm5VsJkbUip8VRYy6LWJePtxya3FNv4TQa",
493
+ # "4LHHvYGNKJUg5hj65aGD5vgScvCBmLpdRFtjokvCjSL8"
494
+ # ]
495
+ # }
496
+ quotes = {}
497
+ priceAssets = self.safe_value(response, 'priceAssets')
498
+ for i in range(0, len(priceAssets)):
499
+ quotes[priceAssets[i]] = True
500
+ self.options['quotes'] = quotes
501
+ return quotes
502
+
503
+ async def fetch_markets(self, params={}) -> List[Market]:
504
+ """
505
+ retrieves data on all markets for wavesexchange
506
+ :param dict [params]: extra parameters specific to the exchange API endpoint
507
+ :returns dict[]: an array of objects representing market data
508
+ """
509
+ response = await self.marketGetTickers()
510
+ #
511
+ # [
512
+ # {
513
+ # "symbol": "WAVES/BTC",
514
+ # "amountAssetID": "WAVES",
515
+ # "amountAssetName": "Waves",
516
+ # "amountAssetDecimals": 8,
517
+ # "amountAssetTotalSupply": "106908766.00000000",
518
+ # "amountAssetMaxSupply": "106908766.00000000",
519
+ # "amountAssetCirculatingSupply": "106908766.00000000",
520
+ # "priceAssetID": "8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS",
521
+ # "priceAssetName": "WBTC",
522
+ # "priceAssetDecimals": 8,
523
+ # "priceAssetTotalSupply": "20999999.96007507",
524
+ # "priceAssetMaxSupply": "20999999.96007507",
525
+ # "priceAssetCirculatingSupply": "20999999.66019601",
526
+ # "24h_open": "0.00032688",
527
+ # "24h_high": "0.00033508",
528
+ # "24h_low": "0.00032443",
529
+ # "24h_close": "0.00032806",
530
+ # "24h_vwap": "0.00032988",
531
+ # "24h_volume": "42349.69440104",
532
+ # "24h_priceVolume": "13.97037207",
533
+ # "timestamp":1640232379124
534
+ # }
535
+ # ...
536
+ # ]
537
+ #
538
+ result = []
539
+ for i in range(0, len(response)):
540
+ entry = response[i]
541
+ baseId = self.safe_string(entry, 'amountAssetID')
542
+ quoteId = self.safe_string(entry, 'priceAssetID')
543
+ id = baseId + '/' + quoteId
544
+ marketId = self.safe_string(entry, 'symbol')
545
+ base, quote = marketId.split('/')
546
+ base = self.safe_currency_code(base)
547
+ quote = self.safe_currency_code(quote)
548
+ symbol = base + '/' + quote
549
+ result.append({
550
+ 'id': id,
551
+ 'symbol': symbol,
552
+ 'base': base,
553
+ 'quote': quote,
554
+ 'settle': None,
555
+ 'baseId': baseId,
556
+ 'quoteId': quoteId,
557
+ 'settleId': None,
558
+ 'type': 'spot',
559
+ 'spot': True,
560
+ 'margin': False,
561
+ 'swap': False,
562
+ 'future': False,
563
+ 'option': False,
564
+ 'active': None,
565
+ 'contract': False,
566
+ 'linear': None,
567
+ 'inverse': None,
568
+ 'contractSize': None,
569
+ 'expiry': None,
570
+ 'expiryDatetime': None,
571
+ 'strike': None,
572
+ 'optionType': None,
573
+ 'precision': {
574
+ 'amount': self.parse_number(self.parse_precision(self.safe_string(entry, 'amountAssetDecimals'))),
575
+ 'price': self.parse_number(self.parse_precision(self.safe_string(entry, 'priceAssetDecimals'))),
576
+ },
577
+ 'limits': {
578
+ 'leverage': {
579
+ 'min': None,
580
+ 'max': None,
581
+ },
582
+ 'amount': {
583
+ 'min': None,
584
+ 'max': None,
585
+ },
586
+ 'price': {
587
+ 'min': None,
588
+ 'max': None,
589
+ },
590
+ 'cost': {
591
+ 'min': None,
592
+ 'max': None,
593
+ },
594
+ },
595
+ 'created': None,
596
+ 'info': entry,
597
+ })
598
+ return result
599
+
600
+ async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
601
+ """
602
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
603
+ :param str symbol: unified symbol of the market to fetch the order book for
604
+ :param int [limit]: the maximum amount of order book entries to return
605
+ :param dict [params]: extra parameters specific to the exchange API endpoint
606
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
607
+ """
608
+ await self.load_markets()
609
+ market = self.market(symbol)
610
+ request = self.extend({
611
+ 'baseId': market['baseId'],
612
+ 'quoteId': market['quoteId'],
613
+ }, params)
614
+ response = await self.matcherGetMatcherOrderbookBaseIdQuoteId(request)
615
+ timestamp = self.safe_integer(response, 'timestamp')
616
+ bids = self.parse_order_book_side(self.safe_value(response, 'bids'), market, limit)
617
+ asks = self.parse_order_book_side(self.safe_value(response, 'asks'), market, limit)
618
+ return {
619
+ 'symbol': symbol,
620
+ 'bids': bids,
621
+ 'asks': asks,
622
+ 'timestamp': timestamp,
623
+ 'datetime': self.iso8601(timestamp),
624
+ 'nonce': None,
625
+ }
626
+
627
+ def parse_order_book_side(self, bookSide, market=None, limit: Int = None):
628
+ precision = market['precision']
629
+ wavesPrecision = self.safe_string(self.options, 'wavesPrecision', '1e-8')
630
+ amountPrecisionString = self.safe_string(precision, 'amount')
631
+ pricePrecisionString = self.safe_string(precision, 'price')
632
+ difference = Precise.string_div(amountPrecisionString, pricePrecisionString)
633
+ pricePrecision = Precise.string_div(wavesPrecision, difference)
634
+ result = []
635
+ for i in range(0, len(bookSide)):
636
+ entry = bookSide[i]
637
+ entryPrice = self.safe_string(entry, 'price', '0')
638
+ entryAmount = self.safe_string(entry, 'amount', '0')
639
+ price = None
640
+ amount = None
641
+ if (pricePrecision is not None) and (entryPrice is not None):
642
+ price = Precise.string_mul(entryPrice, pricePrecision)
643
+ if (amountPrecisionString is not None) and (entryAmount is not None):
644
+ amount = Precise.string_mul(entryAmount, amountPrecisionString)
645
+ if (limit is not None) and (i > limit):
646
+ break
647
+ result.append([
648
+ self.parse_number(price),
649
+ self.parse_number(amount),
650
+ ])
651
+ return result
652
+
653
+ def check_required_keys(self):
654
+ if self.apiKey is None:
655
+ raise AuthenticationError(self.id + ' requires apiKey credential')
656
+ if self.secret is None:
657
+ raise AuthenticationError(self.id + ' requires secret credential')
658
+ apiKeyBytes = None
659
+ secretKeyBytes = None
660
+ try:
661
+ apiKeyBytes = self.base58_to_binary(self.apiKey)
662
+ except Exception as e:
663
+ raise AuthenticationError(self.id + ' apiKey must be a base58 encoded public key')
664
+ try:
665
+ secretKeyBytes = self.base58_to_binary(self.secret)
666
+ except Exception as e:
667
+ raise AuthenticationError(self.id + ' secret must be a base58 encoded private key')
668
+ hexApiKeyBytes = self.binary_to_base16(apiKeyBytes)
669
+ hexSecretKeyBytes = self.binary_to_base16(secretKeyBytes)
670
+ if len(hexApiKeyBytes) != 64:
671
+ raise AuthenticationError(self.id + ' apiKey must be a base58 encoded public key')
672
+ if len(hexSecretKeyBytes) != 64:
673
+ raise AuthenticationError(self.id + ' secret must be a base58 encoded private key')
674
+
675
+ def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
676
+ query = self.omit(params, self.extract_params(path))
677
+ isCancelOrder = path == 'matcher/orders/{wavesAddress}/cancel'
678
+ path = self.implode_params(path, params)
679
+ url = self.urls['api'][api] + '/' + path
680
+ queryString = self.urlencode_with_array_repeat(query)
681
+ if (api == 'private') or (api == 'forward'):
682
+ headers = {
683
+ 'Accept': 'application/json',
684
+ }
685
+ accessToken = self.safe_string(self.options, 'accessToken')
686
+ if accessToken:
687
+ headers['Authorization'] = 'Bearer ' + accessToken
688
+ if method == 'POST':
689
+ headers['content-type'] = 'application/json'
690
+ else:
691
+ headers['content-type'] = 'application/x-www-form-urlencoded'
692
+ if isCancelOrder:
693
+ body = self.json([query['orderId']])
694
+ queryString = ''
695
+ if len(queryString) > 0:
696
+ url += '?' + queryString
697
+ elif api == 'matcher':
698
+ if method == 'POST':
699
+ headers = {
700
+ 'Accept': 'application/json',
701
+ 'Content-Type': 'application/json',
702
+ }
703
+ body = self.json(query)
704
+ else:
705
+ headers = query
706
+ else:
707
+ if method == 'POST':
708
+ headers = {
709
+ 'content-type': 'application/json',
710
+ }
711
+ body = self.json(query)
712
+ else:
713
+ headers = {
714
+ 'content-type': 'application/x-www-form-urlencoded',
715
+ }
716
+ if len(queryString) > 0:
717
+ url += '?' + queryString
718
+ return {'url': url, 'method': method, 'body': body, 'headers': headers}
719
+
720
+ async def sign_in(self, params={}):
721
+ """
722
+ sign in, must be called prior to using other authenticated methods
723
+ :param dict [params]: extra parameters specific to the exchange API endpoint
724
+ :returns: response from exchange
725
+ """
726
+ if not self.safe_string(self.options, 'accessToken'):
727
+ prefix = 'ffffff01'
728
+ expiresDelta = 60 * 60 * 24 * 7
729
+ seconds = self.sum(self.seconds(), expiresDelta)
730
+ seconds = str(seconds)
731
+ clientId = 'wx.network'
732
+ # W for production, T for testnet
733
+ defaultMessagePrefix = self.safe_string(self.options, 'messagePrefix', 'W')
734
+ message = defaultMessagePrefix + ':' + clientId + ':' + seconds
735
+ messageHex = self.binary_to_base16(self.encode(message))
736
+ payload = prefix + messageHex
737
+ hexKey = self.binary_to_base16(self.base58_to_binary(self.secret))
738
+ signature = self.axolotl(payload, hexKey, 'ed25519')
739
+ request: dict = {
740
+ 'grant_type': 'password',
741
+ 'scope': 'general',
742
+ 'username': self.apiKey,
743
+ 'password': seconds + ':' + signature,
744
+ 'client_id': clientId,
745
+ }
746
+ response = await self.privatePostOauth2Token(request)
747
+ # {access_token: "eyJhbGciOXJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzaWciOiJiaTZiMVhMQlo0M1Q4QmRTSlVSejJBZGlQdVlpaFZQYVhhVjc4ZGVIOEpTM3M3NUdSeEU1VkZVOE5LRUI0UXViNkFHaUhpVFpuZ3pzcnhXdExUclRvZTgiLCJhIjoiM1A4VnpMU2EyM0VXNUNWY2tIYlY3ZDVCb043NWZGMWhoRkgiLCJuYiI6IlciLCJ1c2VyX25hbWUiOiJBSFhuOG5CQTRTZkxRRjdoTFFpU24xNmt4eWVoaml6QkdXMVRkcm1TWjFnRiIsInNjb3BlIjpbImdlbmVyYWwiXSwibHQiOjYwNDc5OSwicGsiOiJBSFhuOG5CQTRTZkxRRjdoTFFpU24xNmt4eWVoaml6QkdXMVRkcm1TWjFnRiIsImV4cCI6MTU5MTk3NTA1NywiZXhwMCI6MTU5MTk3NTA1NywianRpIjoiN2JhOTUxMTMtOGI2MS00NjEzLTlkZmYtNTEwYTc0NjlkOWI5IiwiY2lkIjoid2F2ZXMuZXhjaGFuZ2UifQ.B-XwexBnUAzbWknVN68RKT0ZP5w6Qk1SKJ8usL3OIwDEzCUUX9PjW-5TQHmiCRcA4oft8lqXEiCwEoNfsblCo_jTpRo518a1vZkIbHQk0-13Dm1K5ewGxfxAwBk0g49odcbKdjl64TN1yM_PO1VtLVuiTeZP-XF-S42Uj-7fcO-r7AulyQLuTE0uo-Qdep8HDCk47rduZwtJOmhFbCCnSgnLYvKWy3CVTeldsR77qxUY-vy8q9McqeP7Id-_MWnsob8vWXpkeJxaEsw1Fke1dxApJaJam09VU8EB3ZJWpkT7V8PdafIrQGeexx3jhKKxo7rRb4hDV8kfpVoCgkvFan",
748
+ # "token_type": "bearer",
749
+ # "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzaWciOiJiaTZiMVhMQlo0M1Q4QmRTSlVSejJBZGlQdVlpaFZQYVhhVjc4ZGVIOEpTM3M3NUdSeEU1VkZVOE5LRUI0UXViNkFHaUhpVFpuZ3pzcnhXdExUclRvZTgiLCJhIjoiM1A4VnpMU2EyM0VXNUNWY2tIYlY3ZDVCb043NWZGMWhoRkgiLCJuYiI6IlciLCJ1c2VyX25hbWUiOiJBSFhuOG5CQTRTZkxRRjdoTFFpU24xNmt4eWVoaml6QkdXMVRkcm1TWjFnRiIsInNjb3BlIjpbImdlbmVyYWwiXSwiYXRpIjoiN2JhOTUxMTMtOGI2MS00NjEzLTlkZmYtNTEwYTc0NjlkXWI5IiwibHQiOjYwNDc5OSwicGsiOiJBSFhuOG5CQTRTZkxRRjdoTFFpU24xNmt4eWVoaml6QkdXMVRkcm1TWjFnRiIsImV4cCI6MTU5Mzk2MjI1OCwiZXhwMCI6MTU5MTk3NTA1NywianRpIjoiM2MzZWRlMTktNjI5My00MTNlLWJmMWUtZTRlZDZlYzUzZTgzIiwiY2lkIjoid2F2ZXMuZXhjaGFuZ2UifQ.gD1Qj0jfqayfZpBvNY0t3ccMyK5hdbT7dY-_5L6LxwV0Knan4ndEtvygxlTOczmJUKtnA4T1r5GBFgNMZTvtViKZIbqZNysEg2OY8UxwDaF4VPeGJLg_QXEnn8wBeBQdyMafh9UQdwD2ci7x-saM4tOAGmncAygfTDxy80201gwDhfAkAGerb9kL00oWzSJScldxu--pNLDBUEHZt52MSEel10HGrzvZkkvvSh67vcQo5TOGb5KG6nh65UdJCwr41AVz4fbQPP-N2Nkxqy0TE_bqVzZxExXgvcS8TS0Z82T3ijJa_ct7B9wblpylBnvmyj3VycUzufD6uy8MUGq32D",
750
+ # "expires_in": 604798,
751
+ # "scope": "general"}
752
+ self.options['accessToken'] = self.safe_string(response, 'access_token')
753
+ return self.options['accessToken']
754
+ return None
755
+
756
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
757
+ #
758
+ # {
759
+ # "symbol": "WAVES/BTC",
760
+ # "amountAssetID": "WAVES",
761
+ # "amountAssetName": "Waves",
762
+ # "amountAssetDecimals": 8,
763
+ # "amountAssetTotalSupply": "106908766.00000000",
764
+ # "amountAssetMaxSupply": "106908766.00000000",
765
+ # "amountAssetCirculatingSupply": "106908766.00000000",
766
+ # "priceAssetID": "8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS",
767
+ # "priceAssetName": "WBTC",
768
+ # "priceAssetDecimals": 8,
769
+ # "priceAssetTotalSupply": "20999999.96007507",
770
+ # "priceAssetMaxSupply": "20999999.96007507",
771
+ # "priceAssetCirculatingSupply": "20999999.66019601",
772
+ # "24h_open": "0.00032688",
773
+ # "24h_high": "0.00033508",
774
+ # "24h_low": "0.00032443",
775
+ # "24h_close": "0.00032806",
776
+ # "24h_vwap": "0.00032988",
777
+ # "24h_volume": "42349.69440104",
778
+ # "24h_priceVolume": "13.97037207",
779
+ # "timestamp":1640232379124
780
+ # }
781
+ #
782
+ # fetch ticker
783
+ #
784
+ # {
785
+ # "firstPrice": "21749",
786
+ # "lastPrice": "22000",
787
+ # "volume": "0.73747149",
788
+ # "quoteVolume": "16409.44564928645471",
789
+ # "high": "23589.999941",
790
+ # "low": "21010.000845",
791
+ # "weightedAveragePrice": "22250.955964",
792
+ # "txsCount": "148",
793
+ # "volumeWaves": "0.0000000000680511203072"
794
+ # }
795
+ #
796
+ timestamp = self.safe_integer(ticker, 'timestamp')
797
+ marketId = self.safe_string(ticker, 'symbol')
798
+ market = self.safe_market(marketId, market, '/')
799
+ symbol = market['symbol']
800
+ last = self.safe_string_2(ticker, '24h_close', 'lastPrice')
801
+ low = self.safe_string_2(ticker, '24h_low', 'low')
802
+ high = self.safe_string_2(ticker, '24h_high', 'high')
803
+ vwap = self.safe_string_2(ticker, '24h_vwap', 'weightedAveragePrice')
804
+ baseVolume = self.safe_string_2(ticker, '24h_volume', 'volume')
805
+ quoteVolume = self.safe_string_2(ticker, '24h_priceVolume', 'quoteVolume')
806
+ open = self.safe_string_2(ticker, '24h_open', 'firstPrice')
807
+ return self.safe_ticker({
808
+ 'symbol': symbol,
809
+ 'timestamp': timestamp,
810
+ 'datetime': self.iso8601(timestamp),
811
+ 'high': high,
812
+ 'low': low,
813
+ 'bid': None,
814
+ 'bidVolume': None,
815
+ 'ask': None,
816
+ 'askVolume': None,
817
+ 'vwap': vwap,
818
+ 'open': open,
819
+ 'close': last,
820
+ 'last': last,
821
+ 'previousClose': None,
822
+ 'change': None,
823
+ 'percentage': None,
824
+ 'average': None,
825
+ 'baseVolume': baseVolume,
826
+ 'quoteVolume': quoteVolume,
827
+ 'info': ticker,
828
+ }, market)
829
+
830
+ async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
831
+ """
832
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
833
+ :param str symbol: unified symbol of the market to fetch the ticker for
834
+ :param dict [params]: extra parameters specific to the exchange API endpoint
835
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
836
+ """
837
+ await self.load_markets()
838
+ market = self.market(symbol)
839
+ request: dict = {
840
+ 'pairs': market['id'],
841
+ }
842
+ response = await self.publicGetPairs(self.extend(request, params))
843
+ #
844
+ # {
845
+ # "__type":"list",
846
+ # "data":[
847
+ # {
848
+ # "__type":"pair",
849
+ # "data":{
850
+ # "firstPrice":0.00012512,
851
+ # "lastPrice":0.00012441,
852
+ # "low":0.00012167,
853
+ # "high":0.00012768,
854
+ # "weightedAveragePrice":0.000124710697407246,
855
+ # "volume":209554.26356614,
856
+ # "quoteVolume":26.1336583539951,
857
+ # "volumeWaves":209554.26356614,
858
+ # "txsCount":6655
859
+ # },
860
+ # "amountAsset":"WAVES",
861
+ # "priceAsset":"8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS"
862
+ # }
863
+ # ]
864
+ # }
865
+ #
866
+ data = self.safe_value(response, 'data', [])
867
+ ticker = self.safe_value(data, 0, {})
868
+ dataTicker = self.safe_dict(ticker, 'data', {})
869
+ return self.parse_ticker(dataTicker, market)
870
+
871
+ async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
872
+ """
873
+ fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
874
+ :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
875
+ :param dict [params]: extra parameters specific to the exchange API endpoint
876
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
877
+ """
878
+ await self.load_markets()
879
+ response = await self.marketGetTickers(params)
880
+ #
881
+ # [
882
+ # {
883
+ # "symbol": "WAVES/BTC",
884
+ # "amountAssetID": "WAVES",
885
+ # "amountAssetName": "Waves",
886
+ # "amountAssetDecimals": 8,
887
+ # "amountAssetTotalSupply": "106908766.00000000",
888
+ # "amountAssetMaxSupply": "106908766.00000000",
889
+ # "amountAssetCirculatingSupply": "106908766.00000000",
890
+ # "priceAssetID": "8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS",
891
+ # "priceAssetName": "WBTC",
892
+ # "priceAssetDecimals": 8,
893
+ # "priceAssetTotalSupply": "20999999.96007507",
894
+ # "priceAssetMaxSupply": "20999999.96007507",
895
+ # "priceAssetCirculatingSupply": "20999999.66019601",
896
+ # "24h_open": "0.00032688",
897
+ # "24h_high": "0.00033508",
898
+ # "24h_low": "0.00032443",
899
+ # "24h_close": "0.00032806",
900
+ # "24h_vwap": "0.00032988",
901
+ # "24h_volume": "42349.69440104",
902
+ # "24h_priceVolume": "13.97037207",
903
+ # "timestamp":1640232379124
904
+ # }
905
+ # ...
906
+ # ]
907
+ #
908
+ return self.parse_tickers(response, symbols)
909
+
910
+ async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
911
+ """
912
+ fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
913
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
914
+ :param str timeframe: the length of time each candle represents
915
+ :param int [since]: timestamp in ms of the earliest candle to fetch
916
+ :param int [limit]: the maximum amount of candles to fetch
917
+ :param dict [params]: extra parameters specific to the exchange API endpoint
918
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
919
+ """
920
+ await self.load_markets()
921
+ market = self.market(symbol)
922
+ request: dict = {
923
+ 'baseId': market['baseId'],
924
+ 'quoteId': market['quoteId'],
925
+ 'interval': self.safe_string(self.timeframes, timeframe, timeframe),
926
+ }
927
+ allowedCandles = self.safe_integer(self.options, 'allowedCandles', 1440)
928
+ if limit is None:
929
+ limit = allowedCandles
930
+ limit = min(allowedCandles, limit)
931
+ duration = self.parse_timeframe(timeframe) * 1000
932
+ if since is None:
933
+ durationRoundedTimestamp = self.parse_to_int(self.milliseconds() / duration) * duration
934
+ delta = (limit - 1) * duration
935
+ timeStart = durationRoundedTimestamp - delta
936
+ request['timeStart'] = str(timeStart)
937
+ else:
938
+ request['timeStart'] = str(since)
939
+ timeEnd = self.sum(since, duration * limit)
940
+ request['timeEnd'] = str(timeEnd)
941
+ response = await self.publicGetCandlesBaseIdQuoteId(self.extend(request, params))
942
+ #
943
+ # {
944
+ # "__type": "list",
945
+ # "data": [
946
+ # {
947
+ # "__type": "candle",
948
+ # "data": {
949
+ # "time": "2020-06-09T14:47:00.000Z",
950
+ # "open": 0.0250385,
951
+ # "close": 0.0250385,
952
+ # "high": 0.0250385,
953
+ # "low": 0.0250385,
954
+ # "volume": 0.01033012,
955
+ # "quoteVolume": 0.00025865,
956
+ # "weightedAveragePrice": 0.0250385,
957
+ # "maxHeight": 2099399,
958
+ # "txsCount": 5,
959
+ # "timeClose": "2020-06-09T14:47:59.999Z"
960
+ # }
961
+ # }
962
+ # ]
963
+ # }
964
+ #
965
+ data = self.safe_value(response, 'data', [])
966
+ result = self.parse_ohlcvs(data, market, timeframe, since, limit)
967
+ result = self.filter_future_candles(result)
968
+ lastClose = None
969
+ length = len(result)
970
+ for i in range(0, len(result)):
971
+ j = length - i - 1
972
+ entry = result[j]
973
+ open = entry[1]
974
+ if open is None:
975
+ entry[1] = lastClose
976
+ entry[2] = lastClose
977
+ entry[3] = lastClose
978
+ entry[4] = lastClose
979
+ result[j] = entry
980
+ lastClose = entry[4]
981
+ return result
982
+
983
+ def filter_future_candles(self, ohlcvs):
984
+ result = []
985
+ timestamp = self.milliseconds()
986
+ for i in range(0, len(ohlcvs)):
987
+ if ohlcvs[i][0] > timestamp:
988
+ # stop when getting data from the future
989
+ break
990
+ result.append(ohlcvs[i])
991
+ return result
992
+
993
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
994
+ #
995
+ # {
996
+ # "__type": "candle",
997
+ # "data": {
998
+ # "time": "2020-06-05T20:46:00.000Z",
999
+ # "open": 240.573975,
1000
+ # "close": 240.573975,
1001
+ # "high": 240.573975,
1002
+ # "low": 240.573975,
1003
+ # "volume": 0.01278413,
1004
+ # "quoteVolume": 3.075528,
1005
+ # "weightedAveragePrice": 240.573975,
1006
+ # "maxHeight": 2093895,
1007
+ # "txsCount": 5,
1008
+ # "timeClose": "2020-06-05T20:46:59.999Z"
1009
+ # }
1010
+ # }
1011
+ #
1012
+ data = self.safe_value(ohlcv, 'data', {})
1013
+ return [
1014
+ self.parse8601(self.safe_string(data, 'time')),
1015
+ self.safe_number(data, 'open'),
1016
+ self.safe_number(data, 'high'),
1017
+ self.safe_number(data, 'low'),
1018
+ self.safe_number(data, 'close'),
1019
+ self.safe_number(data, 'volume', 0),
1020
+ ]
1021
+
1022
+ async def fetch_deposit_address(self, code: str, params={}):
1023
+ """
1024
+ fetch the deposit address for a currency associated with self account
1025
+ :param str code: unified currency code
1026
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1027
+ :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
1028
+ """
1029
+ await self.sign_in()
1030
+ networks = self.safe_value(self.options, 'networks', {})
1031
+ rawNetwork = self.safe_string_upper(params, 'network')
1032
+ network = self.safe_string(networks, rawNetwork, rawNetwork)
1033
+ params = self.omit(params, ['network'])
1034
+ supportedCurrencies = await self.privateGetPlatforms()
1035
+ #
1036
+ # {
1037
+ # "type": "list",
1038
+ # "page_info": {
1039
+ # "has_next_page": False,
1040
+ # "last_cursor": null
1041
+ # },
1042
+ # "items": [
1043
+ # {
1044
+ # "type": "platform",
1045
+ # "id": "ETH",
1046
+ # "name": "Ethereum",
1047
+ # "currencies": [
1048
+ # "BAG",
1049
+ # "BNT",
1050
+ # "CRV",
1051
+ # "EGG",
1052
+ # "ETH",
1053
+ # "EURN",
1054
+ # "FL",
1055
+ # "NSBT",
1056
+ # "USDAP",
1057
+ # "USDC",
1058
+ # "USDFL",
1059
+ # "USDN",
1060
+ # "USDT",
1061
+ # "WAVES"
1062
+ # ]
1063
+ # }
1064
+ # ]
1065
+ # }
1066
+ #
1067
+ currencies: dict = {}
1068
+ networksByCurrency: dict = {}
1069
+ items = self.safe_value(supportedCurrencies, 'items', [])
1070
+ for i in range(0, len(items)):
1071
+ entry = items[i]
1072
+ currencyId = self.safe_string(entry, 'id')
1073
+ innerCurrencies = self.safe_value(entry, 'currencies', [])
1074
+ for j in range(0, len(innerCurrencies)):
1075
+ currencyCode = self.safe_string(innerCurrencies, j)
1076
+ currencies[currencyCode] = True
1077
+ if not (currencyCode in networksByCurrency):
1078
+ networksByCurrency[currencyCode] = {}
1079
+ networksByCurrency[currencyCode][currencyId] = True
1080
+ if not (code in currencies):
1081
+ codes = list(currencies.keys())
1082
+ raise ExchangeError(self.id + ' fetchDepositAddress() ' + code + ' not supported. Currency code must be one of ' + ', '.join(codes))
1083
+ response = None
1084
+ if network is None:
1085
+ request: dict = {
1086
+ 'currency': code,
1087
+ }
1088
+ response = await self.privateGetDepositAddressesCurrency(self.extend(request, params))
1089
+ else:
1090
+ supportedNetworks = networksByCurrency[code]
1091
+ if not (network in supportedNetworks):
1092
+ supportedNetworkKeys = list(supportedNetworks.keys())
1093
+ raise ExchangeError(self.id + ' ' + network + ' network ' + code + ' deposit address not supported. Network must be one of ' + ', '.join(supportedNetworkKeys))
1094
+ if network == 'WAVES':
1095
+ request: dict = {
1096
+ 'publicKey': self.apiKey,
1097
+ }
1098
+ responseInner = await self.nodeGetAddressesPublicKeyPublicKey(self.extend(request, request))
1099
+ addressInner = self.safe_string(response, 'address')
1100
+ return {
1101
+ 'address': addressInner,
1102
+ 'code': code, # kept here for backward-compatibility, but will be removed soon
1103
+ 'currency': code,
1104
+ 'network': network,
1105
+ 'tag': None,
1106
+ 'info': responseInner,
1107
+ }
1108
+ else:
1109
+ request: dict = {
1110
+ 'currency': code,
1111
+ 'platform': network,
1112
+ }
1113
+ response = await self.privateGetDepositAddressesCurrencyPlatform(self.extend(request, params))
1114
+ #
1115
+ # {
1116
+ # "type": "deposit_addresses",
1117
+ # "currency": {
1118
+ # "type": "deposit_currency",
1119
+ # "id": "ERGO",
1120
+ # "waves_asset_id": "5dJj4Hn9t2Ve3tRpNGirUHy4yBK6qdJRAJYV21yPPuGz",
1121
+ # "platform_id": "BSC",
1122
+ # "decimals": 9,
1123
+ # "status": "active",
1124
+ # "allowed_amount": {
1125
+ # "min": 0.001,
1126
+ # "max": 100000
1127
+ # },
1128
+ # "fees": {
1129
+ # "flat": 0,
1130
+ # "rate": 0
1131
+ # }
1132
+ # },
1133
+ # "deposit_addresses": [
1134
+ # "9fRAAQjF8Yqg7qicQCL884zjimsRnuwsSavsM1rUdDaoG8mThku"
1135
+ # ]
1136
+ # }
1137
+ currency = self.safe_value(response, 'currency')
1138
+ networkId = self.safe_string(currency, 'platform_id')
1139
+ networkByIds = self.safe_value(self.options, 'networkByIds', {})
1140
+ unifiedNetwork = self.safe_string(networkByIds, networkId, networkId)
1141
+ addresses = self.safe_value(response, 'deposit_addresses')
1142
+ address = self.safe_string(addresses, 0)
1143
+ return {
1144
+ 'address': address,
1145
+ 'code': code, # kept here for backward-compatibility, but will be removed soon
1146
+ 'currency': code,
1147
+ 'tag': None,
1148
+ 'network': unifiedNetwork,
1149
+ 'info': response,
1150
+ }
1151
+
1152
+ async def get_matcher_public_key(self):
1153
+ # self method returns a single string
1154
+ matcherPublicKey = self.safe_string(self.options, 'matcherPublicKey')
1155
+ if matcherPublicKey:
1156
+ return matcherPublicKey
1157
+ else:
1158
+ response = await self.matcherGetMatcher()
1159
+ # remove trailing quotes from string response
1160
+ self.options['matcherPublicKey'] = response[1:len(response) - 1]
1161
+ return self.options['matcherPublicKey']
1162
+
1163
+ def get_asset_bytes(self, currencyId):
1164
+ if currencyId == 'WAVES':
1165
+ return self.number_to_be(0, 1)
1166
+ else:
1167
+ return self.binary_concat(self.number_to_be(1, 1), self.base58_to_binary(currencyId))
1168
+
1169
+ def get_asset_id(self, currencyId):
1170
+ if currencyId == 'WAVES':
1171
+ return ''
1172
+ return currencyId
1173
+
1174
+ def to_real_currency_amount(self, code: str, amount: float, networkCode=None):
1175
+ currency = self.currency(code)
1176
+ stringValue = Precise.string_div(self.number_to_string(amount), self.safe_string(currency, 'precision'))
1177
+ return int(stringValue)
1178
+
1179
+ def from_real_currency_amount(self, code: str, amountString: str):
1180
+ if not (code in self.currencies):
1181
+ return amountString
1182
+ currency = self.currency(code)
1183
+ precisionAmount = self.safe_string(currency, 'precision')
1184
+ return Precise.string_mul(amountString, precisionAmount)
1185
+
1186
+ def to_real_symbol_price(self, symbol: str, price: float):
1187
+ market = self.market(symbol)
1188
+ stringValue = Precise.string_div(self.number_to_string(price), self.safe_string(market['precision'], 'price'))
1189
+ return int(stringValue)
1190
+
1191
+ def from_real_symbol_price(self, symbol: str, priceString: str):
1192
+ market = self.markets[symbol]
1193
+ return Precise.string_mul(priceString, self.safe_string(market['precision'], 'price'))
1194
+
1195
+ def to_real_symbol_amount(self, symbol: str, amount: float):
1196
+ market = self.market(symbol)
1197
+ stringValue = Precise.string_div(self.number_to_string(amount), self.safe_string(market['precision'], 'amount'))
1198
+ return int(stringValue)
1199
+
1200
+ def from_real_symbol_amount(self, symbol: str, amountString: str):
1201
+ market = self.markets[symbol]
1202
+ return Precise.string_mul(amountString, market['precision']['amount'])
1203
+
1204
+ def safe_get_dynamic(self, settings):
1205
+ orderFee = self.safe_value(settings, 'orderFee')
1206
+ if 'dynamic' in orderFee:
1207
+ return self.safe_value(orderFee, 'dynamic')
1208
+ else:
1209
+ return self.safe_value(orderFee['composite']['default'], 'dynamic')
1210
+
1211
+ def safe_get_rates(self, dynamic):
1212
+ rates = self.safe_value(dynamic, 'rates')
1213
+ if rates is None:
1214
+ return {'WAVES': 1}
1215
+ return rates
1216
+
1217
+ async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1218
+ """
1219
+ create a trade order
1220
+ :param str symbol: unified symbol of the market to create an order in
1221
+ :param str type: 'market' or 'limit'
1222
+ :param str side: 'buy' or 'sell'
1223
+ :param float amount: how much of currency you want to trade in units of base currency
1224
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1225
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1226
+ :param float [params.stopPrice]: The price at which a stop order is triggered at
1227
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1228
+ """
1229
+ self.check_required_dependencies()
1230
+ self.check_required_keys()
1231
+ await self.load_markets()
1232
+ market = self.market(symbol)
1233
+ matcherPublicKey = await self.get_matcher_public_key()
1234
+ amountAsset = self.get_asset_id(market['baseId'])
1235
+ priceAsset = self.get_asset_id(market['quoteId'])
1236
+ isMarketOrder = (type == 'market')
1237
+ stopPrice = self.safe_float_2(params, 'triggerPrice', 'stopPrice')
1238
+ isStopOrder = (stopPrice is not None)
1239
+ if (isMarketOrder) and (price is None):
1240
+ raise InvalidOrder(self.id + ' createOrder() requires a price argument for ' + type + ' orders to determine the max price for buy and the min price for sell')
1241
+ timestamp = self.milliseconds()
1242
+ defaultExpiryDelta = self.safe_integer(self.options, 'createOrderDefaultExpiry', 2419200000)
1243
+ expiration = self.sum(timestamp, defaultExpiryDelta)
1244
+ matcherFees = await self.get_fees_for_asset(symbol, side, amount, price)
1245
+ # {
1246
+ # "base":{
1247
+ # "feeAssetId":"WAVES", # varies depending on the trading pair
1248
+ # "matcherFee":"1000000"
1249
+ # },
1250
+ # "discount":{
1251
+ # "feeAssetId":"EMAMLxDnv3xiz8RXg8Btj33jcEw3wLczL3JKYYmuubpc",
1252
+ # "matcherFee":"4077612"
1253
+ # }
1254
+ # }
1255
+ base = self.safe_value_2(matcherFees, 'base', 'discount')
1256
+ baseFeeAssetId = self.safe_string(base, 'feeAssetId')
1257
+ baseFeeAsset = self.safe_currency_code(baseFeeAssetId)
1258
+ baseMatcherFee = self.safe_string(base, 'matcherFee')
1259
+ discount = self.safe_value(matcherFees, 'discount')
1260
+ discountFeeAssetId = self.safe_string(discount, 'feeAssetId')
1261
+ discountFeeAsset = self.safe_currency_code(discountFeeAssetId)
1262
+ discountMatcherFee = self.safe_string(discount, 'matcherFee')
1263
+ matcherFeeAssetId = None
1264
+ matcherFee = None
1265
+ # check first if user supplied asset fee is valid
1266
+ if ('feeAsset' in params) or ('feeAsset' in self.options):
1267
+ feeAsset = self.safe_string(params, 'feeAsset', self.safe_string(self.options, 'feeAsset'))
1268
+ feeCurrency = self.currency(feeAsset)
1269
+ matcherFeeAssetId = self.safe_string(feeCurrency, 'id')
1270
+ balances = await self.fetch_balance()
1271
+ if matcherFeeAssetId is not None:
1272
+ if baseFeeAssetId != matcherFeeAssetId and discountFeeAssetId != matcherFeeAssetId:
1273
+ raise InvalidOrder(self.id + ' asset fee must be ' + baseFeeAsset + ' or ' + discountFeeAsset)
1274
+ matcherFeeAsset = self.safe_currency_code(matcherFeeAssetId)
1275
+ rawMatcherFee = baseMatcherFee if (matcherFeeAssetId == baseFeeAssetId) else discountMatcherFee
1276
+ floatMatcherFee = float(self.from_real_currency_amount(matcherFeeAsset, rawMatcherFee))
1277
+ if (matcherFeeAsset in balances) and (balances[matcherFeeAsset]['free'] >= floatMatcherFee):
1278
+ matcherFee = int(rawMatcherFee)
1279
+ else:
1280
+ raise InsufficientFunds(self.id + ' not enough funds of the selected asset fee')
1281
+ floatBaseMatcherFee = self.from_real_currency_amount(baseFeeAsset, baseMatcherFee)
1282
+ floatDiscountMatcherFee = self.from_real_currency_amount(discountFeeAsset, discountMatcherFee)
1283
+ if matcherFeeAssetId is None:
1284
+ # try to the pay the fee using the base first then discount asset
1285
+ if (baseFeeAsset in balances) and (balances[baseFeeAsset]['free'] >= float(floatBaseMatcherFee)):
1286
+ matcherFeeAssetId = baseFeeAssetId
1287
+ matcherFee = int(baseMatcherFee)
1288
+ else:
1289
+ if (discountFeeAsset in balances) and (balances[discountFeeAsset]['free'] >= float(floatDiscountMatcherFee)):
1290
+ matcherFeeAssetId = discountFeeAssetId
1291
+ matcherFee = int(discountMatcherFee)
1292
+ if matcherFeeAssetId is None:
1293
+ raise InsufficientFunds(self.id + ' not enough funds on none of the eligible asset fees: ' + baseFeeAsset + ' ' + floatBaseMatcherFee + ' or ' + discountFeeAsset + ' ' + floatDiscountMatcherFee)
1294
+ amount = self.to_real_symbol_amount(symbol, amount)
1295
+ price = self.to_real_symbol_price(symbol, price)
1296
+ assetPair: dict = {
1297
+ 'amountAsset': amountAsset,
1298
+ 'priceAsset': priceAsset,
1299
+ }
1300
+ sandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
1301
+ chainId = 84 if (sandboxMode) else 87
1302
+ body: dict = {
1303
+ 'senderPublicKey': self.apiKey,
1304
+ 'matcherPublicKey': matcherPublicKey,
1305
+ 'assetPair': assetPair,
1306
+ 'orderType': side,
1307
+ 'price': price,
1308
+ 'amount': amount,
1309
+ 'timestamp': timestamp,
1310
+ 'expiration': expiration,
1311
+ 'matcherFee': int(matcherFee),
1312
+ 'priceMode': 'assetDecimals',
1313
+ 'version': 4,
1314
+ 'chainId': chainId,
1315
+ }
1316
+ if isStopOrder:
1317
+ #
1318
+ # {
1319
+ # "v": 1, # version(int)
1320
+ # "c": { # condition(object)
1321
+ # "t": "sp", # condition type. for now only "stop-price"(string)
1322
+ # "v": { # value(object)
1323
+ # "p": "123", # price(long)
1324
+ # },
1325
+ # },
1326
+ # }
1327
+ #
1328
+ attachment: dict = {
1329
+ 'v': 1,
1330
+ 'c': {
1331
+ 't': 'sp',
1332
+ 'v': {
1333
+ 'p': self.to_real_symbol_price(symbol, stopPrice),
1334
+ },
1335
+ },
1336
+ }
1337
+ body['attachment'] = self.binary_to_base58(self.encode(json.dumps(attachment)))
1338
+ if matcherFeeAssetId != 'WAVES':
1339
+ body['matcherFeeAssetId'] = matcherFeeAssetId
1340
+ serializedOrder = await self.matcherPostMatcherOrdersSerialize(body)
1341
+ if (serializedOrder[0] == '"') and (serializedOrder[(len(serializedOrder) - 1)] == '"'):
1342
+ serializedOrder = serializedOrder[1:len(serializedOrder) - 1]
1343
+ signature = self.axolotl(self.binary_to_base16(self.base58_to_binary(serializedOrder)), self.binary_to_base16(self.base58_to_binary(self.secret)), 'ed25519')
1344
+ body['signature'] = signature
1345
+ #
1346
+ # {
1347
+ # "success": True,
1348
+ # "message": {
1349
+ # "version": 4,
1350
+ # "id": "8VR49dLZFaYcVwzx9TqVMTAZCSUoyB74kLUHrEPCSJgN",
1351
+ # "sender": "3MpEdBXtsRHRj2TvZURSb8uLDxzneVbYczW",
1352
+ # "senderPublicKey": "8aUTNqHGCBiubySBRhcS1N6NC5jLczhVcndRfMAuwtkY",
1353
+ # "matcherPublicKey": "8QUAqtTckM5B8gvcuP7mMswat9SjKUuafJMusEoSn1Gy",
1354
+ # "assetPair": {
1355
+ # "amountAsset": "EMAMLxDnv3xiz8RXg8Btj33jcEw3wLczL3JKYYmuubpc",
1356
+ # "priceAsset": "25FEqEjRkqK6yCkiT7Lz6SAYz7gUFCtxfCChnrVFD5AT"
1357
+ # },
1358
+ # "orderType": "sell",
1359
+ # "amount": 100000,
1360
+ # "price": 480000,
1361
+ # "timestamp": 1690852043772,
1362
+ # "expiration": 1693271243772,
1363
+ # "matcherFee": 83327570,
1364
+ # "signature": "3QYDWQVSP4kdqpTLodCuboh8bpWd6GW5s1pQyKdce1JBDwX6t4kH5Xtuq35pqo94gxjo3cfG6k6Xuic2JaYLubkK",
1365
+ # "proofs": [
1366
+ # "3QYDWQVSP4kdqpTLodCuboh8bpWd6GW5s1pQyKdce1JBDwX6t4kH5Xtuq35pqo94gxjo3cfG6k6Xuic2JaYLubkK"
1367
+ # ],
1368
+ # "matcherFeeAssetId": "EMAMLxDnv3xiz8RXg8Btj33jcEw3wLczL3JKYYmuubpc",
1369
+ # "eip712Signature": null,
1370
+ # "priceMode": "assetDecimals",
1371
+ # "attachment": "2PQ4akZHnMSZrQissuu5uudoXbgsipeDnFcRtXtjVgkdm1gUWEgGzp"
1372
+ # },
1373
+ # "status": "OrderAccepted"
1374
+ # }
1375
+ #
1376
+ if isMarketOrder:
1377
+ response = await self.matcherPostMatcherOrderbookMarket(body)
1378
+ value = self.safe_dict(response, 'message')
1379
+ return self.parse_order(value, market)
1380
+ else:
1381
+ response = await self.matcherPostMatcherOrderbook(body)
1382
+ value = self.safe_dict(response, 'message')
1383
+ return self.parse_order(value, market)
1384
+
1385
+ async def cancel_order(self, id: str, symbol: Str = None, params={}):
1386
+ """
1387
+ cancels an open order
1388
+ :param str id: order id
1389
+ :param str symbol: unified symbol of the market the order was made in
1390
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1391
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1392
+ """
1393
+ self.check_required_dependencies()
1394
+ self.check_required_keys()
1395
+ await self.sign_in()
1396
+ wavesAddress = await self.get_waves_address()
1397
+ response = await self.forwardPostMatcherOrdersWavesAddressCancel({
1398
+ 'wavesAddress': wavesAddress,
1399
+ 'orderId': id,
1400
+ })
1401
+ # {
1402
+ # "success":true,
1403
+ # "message":[[{"orderId":"EBpJeGM36KKFz5gTJAUKDBm89V8wqxKipSFBdU35AN3c","success":true,"status":"OrderCanceled"}]],
1404
+ # "status":"BatchCancelCompleted"
1405
+ # }
1406
+ message = self.safe_value(response, 'message')
1407
+ firstMessage = self.safe_value(message, 0)
1408
+ firstOrder = self.safe_value(firstMessage, 0)
1409
+ returnedId = self.safe_string(firstOrder, 'orderId')
1410
+ return self.safe_order({
1411
+ 'info': response,
1412
+ 'id': returnedId,
1413
+ 'clientOrderId': None,
1414
+ 'timestamp': None,
1415
+ 'datetime': None,
1416
+ 'lastTradeTimestamp': None,
1417
+ 'symbol': symbol,
1418
+ 'type': None,
1419
+ 'side': None,
1420
+ 'price': None,
1421
+ 'amount': None,
1422
+ 'cost': None,
1423
+ 'average': None,
1424
+ 'filled': None,
1425
+ 'remaining': None,
1426
+ 'status': None,
1427
+ 'fee': None,
1428
+ 'trades': None,
1429
+ })
1430
+
1431
+ async def fetch_order(self, id: str, symbol: Str = None, params={}):
1432
+ """
1433
+ fetches information on an order made by the user
1434
+ :param str symbol: unified symbol of the market the order was made in
1435
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1436
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1437
+ """
1438
+ self.check_required_dependencies()
1439
+ self.check_required_keys()
1440
+ await self.load_markets()
1441
+ market = None
1442
+ if symbol is not None:
1443
+ market = self.market(symbol)
1444
+ timestamp = self.milliseconds()
1445
+ byteArray = [
1446
+ self.base58_to_binary(self.apiKey),
1447
+ self.number_to_be(timestamp, 8),
1448
+ ]
1449
+ binary = self.binary_concat_array(byteArray)
1450
+ hexSecret = self.binary_to_base16(self.base58_to_binary(self.secret))
1451
+ signature = self.axolotl(self.binary_to_base16(binary), hexSecret, 'ed25519')
1452
+ request: dict = {
1453
+ 'Timestamp': str(timestamp),
1454
+ 'Signature': signature,
1455
+ 'publicKey': self.apiKey,
1456
+ 'orderId': id,
1457
+ }
1458
+ response = await self.matcherGetMatcherOrderbookPublicKeyOrderId(self.extend(request, params))
1459
+ return self.parse_order(response, market)
1460
+
1461
+ async def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1462
+ """
1463
+ fetches information on multiple orders made by the user
1464
+ :param str symbol: unified market symbol of the market orders were made in
1465
+ :param int [since]: the earliest time in ms to fetch orders for
1466
+ :param int [limit]: the maximum number of order structures to retrieve
1467
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1468
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1469
+ """
1470
+ self.check_required_dependencies()
1471
+ self.check_required_keys()
1472
+ if symbol is None:
1473
+ raise ArgumentsRequired(self.id + ' fetchOrders() requires a symbol argument')
1474
+ await self.load_markets()
1475
+ market = self.market(symbol)
1476
+ timestamp = self.milliseconds()
1477
+ byteArray = [
1478
+ self.base58_to_binary(self.apiKey),
1479
+ self.number_to_be(timestamp, 8),
1480
+ ]
1481
+ binary = self.binary_concat_array(byteArray)
1482
+ hexSecret = self.binary_to_base16(self.base58_to_binary(self.secret))
1483
+ signature = self.axolotl(self.binary_to_base16(binary), hexSecret, 'ed25519')
1484
+ request: dict = {
1485
+ 'Accept': 'application/json',
1486
+ 'Timestamp': str(timestamp),
1487
+ 'Signature': signature,
1488
+ 'publicKey': self.apiKey,
1489
+ 'baseId': market['baseId'],
1490
+ 'quoteId': market['quoteId'],
1491
+ }
1492
+ response = await self.matcherGetMatcherOrderbookBaseIdQuoteIdPublicKeyPublicKey(self.extend(request, params))
1493
+ # [{id: "3KicDeWayY2mdrRoYdCkP3gUAoUZUNT1AA6GAtWuPLfa",
1494
+ # "type": "sell",
1495
+ # "orderType": "limit",
1496
+ # "amount": 1,
1497
+ # "fee": 300000,
1498
+ # "price": 100000000,
1499
+ # "timestamp": 1591651254076,
1500
+ # "filled": 0,
1501
+ # "filledFee": 0,
1502
+ # "feeAsset": "WAVES",
1503
+ # "status": "Accepted",
1504
+ # "assetPair":
1505
+ # {amountAsset: null,
1506
+ # "priceAsset": "8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS"},
1507
+ # "avgWeighedPrice": 0}, ...]
1508
+ return self.parse_orders(response, market, since, limit)
1509
+
1510
+ async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1511
+ """
1512
+ fetch all unfilled currently open orders
1513
+ :param str symbol: unified market symbol
1514
+ :param int [since]: the earliest time in ms to fetch open orders for
1515
+ :param int [limit]: the maximum number of open orders structures to retrieve
1516
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1517
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1518
+ """
1519
+ await self.load_markets()
1520
+ await self.sign_in()
1521
+ market = None
1522
+ if symbol is not None:
1523
+ market = self.market(symbol)
1524
+ address = await self.get_waves_address()
1525
+ request: dict = {
1526
+ 'address': address,
1527
+ 'activeOnly': True,
1528
+ }
1529
+ response = await self.forwardGetMatcherOrdersAddress(request)
1530
+ return self.parse_orders(response, market, since, limit)
1531
+
1532
+ async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1533
+ """
1534
+ fetches information on multiple closed orders made by the user
1535
+ :param str symbol: unified market symbol of the market orders were made in
1536
+ :param int [since]: the earliest time in ms to fetch orders for
1537
+ :param int [limit]: the maximum number of order structures to retrieve
1538
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1539
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1540
+ """
1541
+ await self.load_markets()
1542
+ await self.sign_in()
1543
+ market = None
1544
+ if symbol is not None:
1545
+ market = self.market(symbol)
1546
+ address = await self.get_waves_address()
1547
+ request: dict = {
1548
+ 'address': address,
1549
+ 'closedOnly': True,
1550
+ }
1551
+ response = await self.forwardGetMatcherOrdersAddress(request)
1552
+ # [
1553
+ # {
1554
+ # "id": "9aXcxvXai73jbAm7tQNnqaQ2PwUjdmWuyjvRTKAHsw4f",
1555
+ # "type": "buy",
1556
+ # "orderType": "limit",
1557
+ # "amount": 23738330,
1558
+ # "fee": 300000,
1559
+ # "price": 3828348334,
1560
+ # "timestamp": 1591926905636,
1561
+ # "filled": 23738330,
1562
+ # "filledFee": 300000,
1563
+ # "feeAsset": "WAVES",
1564
+ # "status": "Filled",
1565
+ # "assetPair": {
1566
+ # "amountAsset": "HZk1mbfuJpmxU1Fs4AX5MWLVYtctsNcg6e2C6VKqK8zk",
1567
+ # "priceAsset": null
1568
+ # },
1569
+ # "avgWeighedPrice": 3828348334
1570
+ # }, ...
1571
+ # ]
1572
+ return self.parse_orders(response, market, since, limit)
1573
+
1574
+ def parse_order_status(self, status: Str):
1575
+ statuses: dict = {
1576
+ 'Cancelled': 'canceled',
1577
+ 'Accepted': 'open',
1578
+ 'Filled': 'closed',
1579
+ 'PartiallyFilled': 'open',
1580
+ }
1581
+ return self.safe_string(statuses, status, status)
1582
+
1583
+ def get_symbol_from_asset_pair(self, assetPair):
1584
+ # a blank string or null can indicate WAVES
1585
+ baseId = self.safe_string(assetPair, 'amountAsset', 'WAVES')
1586
+ quoteId = self.safe_string(assetPair, 'priceAsset', 'WAVES')
1587
+ return self.safe_currency_code(baseId) + '/' + self.safe_currency_code(quoteId)
1588
+
1589
+ def parse_order(self, order: dict, market: Market = None) -> Order:
1590
+ #
1591
+ # createOrder
1592
+ #
1593
+ # {
1594
+ # "version": 4,
1595
+ # "id": "BshyeHXDfJmTnjTdBYt371jD4yWaT3JTP6KpjpsiZepS",
1596
+ # "sender": "3P8VzLSa23EW5CVckHbV7d5BoN75fF1hhFH",
1597
+ # "senderPublicKey": "AHXn8nBA4SfLQF7hLQiSn16kxyehjizBGW1TdrmSZ1gF",
1598
+ # "matcherPublicKey": "9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5",
1599
+ # "assetPair": {
1600
+ # "amountAsset": "474jTeYx2r2Va35794tCScAXWJG9hU2HcgxzMowaZUnu",
1601
+ # "priceAsset": "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p",
1602
+ # },
1603
+ # "orderType": "buy",
1604
+ # "amount": 10000,
1605
+ # "price": 400000000,
1606
+ # "timestamp": 1599848586891,
1607
+ # "expiration": 1602267786891,
1608
+ # "matcherFee": 3008,
1609
+ # "matcherFeeAssetId": "474jTeYx2r2Va35794tCScAXWJG9hU2HcgxzMowaZUnu",
1610
+ # "signature": "3D2h8ubrhuWkXbVn4qJ3dvjmZQxLoRNfjTqb9uNpnLxUuwm4fGW2qGH6yKFe2SQPrcbgkS3bDVe7SNtMuatEJ7qy",
1611
+ # "proofs": [
1612
+ # "3D2h8ubrhuWkXbVn4qJ3dvjmZQxLoRNfjTqb9uNpnLxUuwm4fGW2qGH6yKFe2SQPrcbgkS3bDVe7SNtMuatEJ7qy",
1613
+ # ],
1614
+ # "attachment":"77rnoyFX5BDr15hqZiUtgXKSN46zsbHHQjVNrTMLZcLz62mmFKr39FJ"
1615
+ # }
1616
+ #
1617
+ #
1618
+ # fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders
1619
+ #
1620
+ # {
1621
+ # "id": "81D9uKk2NfmZzfG7uaJsDtxqWFbJXZmjYvrL88h15fk8",
1622
+ # "type": "buy",
1623
+ # "orderType": "limit",
1624
+ # "amount": 30000000000,
1625
+ # "filled": 0,
1626
+ # "price": 1000000,
1627
+ # "fee": 300000,
1628
+ # "filledFee": 0,
1629
+ # "feeAsset": "WAVES",
1630
+ # "timestamp": 1594303779322,
1631
+ # "status": "Cancelled",
1632
+ # "assetPair": {
1633
+ # "amountAsset": "474jTeYx2r2Va35794tCScAXWJG9hU2HcgxzMowaZUnu",
1634
+ # "priceAsset": "WAVES"
1635
+ # },
1636
+ # "avgWeighedPrice": 0,
1637
+ # "version": 4,
1638
+ # "totalExecutedPriceAssets": 0, # in fetchOpenOrder/s
1639
+ # "attachment":"77rnoyFX5BDr15hqZiUtgXKSN46zsbHHQjVNrTMLZcLz62mmFKr39FJ"
1640
+ # }
1641
+ #
1642
+ timestamp = self.safe_integer(order, 'timestamp')
1643
+ side = self.safe_string_2(order, 'type', 'orderType')
1644
+ type = 'limit'
1645
+ if 'type' in order:
1646
+ # fetchOrders
1647
+ type = self.safe_string(order, 'orderType', type)
1648
+ id = self.safe_string(order, 'id')
1649
+ filledString = self.safe_string(order, 'filled')
1650
+ priceString = self.safe_string(order, 'price')
1651
+ amountString = self.safe_string(order, 'amount')
1652
+ assetPair = self.safe_value(order, 'assetPair')
1653
+ symbol = None
1654
+ if assetPair is not None:
1655
+ symbol = self.get_symbol_from_asset_pair(assetPair)
1656
+ elif market is not None:
1657
+ symbol = market['symbol']
1658
+ amountCurrency = self.safe_currency_code(self.safe_string(assetPair, 'amountAsset', 'WAVES'))
1659
+ price = self.from_real_symbol_price(symbol, priceString)
1660
+ amount = self.from_real_currency_amount(amountCurrency, amountString)
1661
+ filled = self.from_real_currency_amount(amountCurrency, filledString)
1662
+ average = self.from_real_symbol_price(symbol, self.safe_string(order, 'avgWeighedPrice'))
1663
+ status = self.parse_order_status(self.safe_string(order, 'status'))
1664
+ fee = None
1665
+ if 'type' in order:
1666
+ code = self.safe_currency_code(self.safe_string(order, 'feeAsset'))
1667
+ fee = {
1668
+ 'currency': code,
1669
+ 'fee': self.parse_number(self.from_real_currency_amount(code, self.safe_string(order, 'filledFee'))),
1670
+ }
1671
+ else:
1672
+ code = self.safe_currency_code(self.safe_string(order, 'matcherFeeAssetId', 'WAVES'))
1673
+ fee = {
1674
+ 'currency': code,
1675
+ 'fee': self.parse_number(self.from_real_currency_amount(code, self.safe_string(order, 'matcherFee'))),
1676
+ }
1677
+ triggerPrice = None
1678
+ attachment = self.safe_string(order, 'attachment')
1679
+ if attachment is not None:
1680
+ decodedAttachment = self.parse_json(self.decode(self.base58_to_binary(attachment)))
1681
+ if decodedAttachment is not None:
1682
+ c = self.safe_value(decodedAttachment, 'c')
1683
+ if c is not None:
1684
+ v = self.safe_value(c, 'v')
1685
+ if v is not None:
1686
+ triggerPrice = self.safe_string(v, 'p')
1687
+ return self.safe_order({
1688
+ 'info': order,
1689
+ 'id': id,
1690
+ 'clientOrderId': None,
1691
+ 'timestamp': timestamp,
1692
+ 'datetime': self.iso8601(timestamp),
1693
+ 'lastTradeTimestamp': None,
1694
+ 'symbol': symbol,
1695
+ 'type': type,
1696
+ 'timeInForce': None,
1697
+ 'postOnly': None,
1698
+ 'side': side,
1699
+ 'price': price,
1700
+ 'stopPrice': triggerPrice,
1701
+ 'triggerPrice': triggerPrice,
1702
+ 'amount': amount,
1703
+ 'cost': None,
1704
+ 'average': average,
1705
+ 'filled': filled,
1706
+ 'remaining': None,
1707
+ 'status': status,
1708
+ 'fee': fee,
1709
+ 'trades': None,
1710
+ }, market)
1711
+
1712
+ async def get_waves_address(self):
1713
+ cachedAddreess = self.safe_string(self.options, 'wavesAddress')
1714
+ if cachedAddreess is None:
1715
+ request: dict = {
1716
+ 'publicKey': self.apiKey,
1717
+ }
1718
+ response = await self.nodeGetAddressesPublicKeyPublicKey(request)
1719
+ self.options['wavesAddress'] = self.safe_string(response, 'address')
1720
+ return self.options['wavesAddress']
1721
+ else:
1722
+ return cachedAddreess
1723
+
1724
+ async def fetch_balance(self, params={}) -> Balances:
1725
+ """
1726
+ query for balance and get the amount of funds available for trading or funds locked in orders
1727
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1728
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1729
+ """
1730
+ # makes a lot of different requests to get all the data
1731
+ # in particular:
1732
+ # fetchMarkets, getWavesAddress,
1733
+ # getTotalBalance(doesn't include waves), getReservedBalance(doesn't include waves)
1734
+ # getReservedBalance(includes WAVES)
1735
+ # I couldn't find another way to get all the data
1736
+ self.check_required_dependencies()
1737
+ self.check_required_keys()
1738
+ await self.load_markets()
1739
+ wavesAddress = await self.get_waves_address()
1740
+ request: dict = {
1741
+ 'address': wavesAddress,
1742
+ }
1743
+ totalBalance = await self.nodeGetAssetsBalanceAddress(request)
1744
+ # {
1745
+ # "address": "3P8VzLSa23EW5CVckHbV7d5BoN75fF1hhFH",
1746
+ # "balances": [
1747
+ # {
1748
+ # "assetId": "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p",
1749
+ # "balance": 1177200,
1750
+ # "reissuable": False,
1751
+ # "minSponsoredAssetFee": 7420,
1752
+ # "sponsorBalance": 47492147189709,
1753
+ # "quantity": 999999999775381400,
1754
+ # "issueTransaction": {
1755
+ # "senderPublicKey": "BRnVwSVctnV8pge5vRpsJdWnkjWEJspFb6QvrmZvu3Ht",
1756
+ # "quantity": 1000000000000000000,
1757
+ # "fee": 100400000,
1758
+ # "description": "Neutrino USD",
1759
+ # "type": 3,
1760
+ # "version": 2,
1761
+ # "reissuable": False,
1762
+ # "script": null,
1763
+ # "sender": "3PC9BfRwJWWiw9AREE2B3eWzCks3CYtg4yo",
1764
+ # "feeAssetId": null,
1765
+ # "chainId": 87,
1766
+ # "proofs": [
1767
+ # "3HNpbVkgP69NWSeb9hGYauiQDaXrRXh3tXFzNsGwsAAXnFrA29SYGbLtziW9JLpXEq7qW1uytv5Fnm5XTUMB2BxU"
1768
+ # ],
1769
+ # "assetId": "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p",
1770
+ # "decimals": 6,
1771
+ # "name": "USD-N",
1772
+ # "id": "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p",
1773
+ # "timestamp": 1574429393962
1774
+ # }
1775
+ # }
1776
+ # ]
1777
+ # }
1778
+ balances = self.safe_value(totalBalance, 'balances', [])
1779
+ result: dict = {}
1780
+ timestamp = None
1781
+ assetIds = []
1782
+ nonStandardBalances = []
1783
+ for i in range(0, len(balances)):
1784
+ entry = balances[i]
1785
+ entryTimestamp = self.safe_integer(entry, 'timestamp')
1786
+ timestamp = entryTimestamp if (timestamp is None) else max(timestamp, entryTimestamp)
1787
+ issueTransaction = self.safe_value(entry, 'issueTransaction')
1788
+ currencyId = self.safe_string(entry, 'assetId')
1789
+ balance = self.safe_string(entry, 'balance')
1790
+ currencyExists = (currencyId in self.currencies_by_id)
1791
+ if currencyExists:
1792
+ code = self.safe_currency_code(currencyId)
1793
+ result[code] = self.account()
1794
+ result[code]['total'] = self.from_real_currency_amount(code, balance)
1795
+ elif issueTransaction is None:
1796
+ assetIds.append(currencyId)
1797
+ nonStandardBalances.append(balance)
1798
+ nonStandardAssets = len(assetIds)
1799
+ if nonStandardAssets:
1800
+ requestInner: dict = {
1801
+ 'ids': assetIds,
1802
+ }
1803
+ response = await self.publicGetAssets(requestInner)
1804
+ data = self.safe_value(response, 'data', [])
1805
+ for i in range(0, len(data)):
1806
+ entry = data[i]
1807
+ balance = nonStandardBalances[i]
1808
+ inner = self.safe_value(entry, 'data')
1809
+ precision = self.parse_precision(self.safe_string(inner, 'precision'))
1810
+ ticker = self.safe_string(inner, 'ticker')
1811
+ code = self.safe_currency_code(ticker)
1812
+ result[code] = self.account()
1813
+ result[code]['total'] = Precise.string_mul(balance, precision)
1814
+ currentTimestamp = self.milliseconds()
1815
+ byteArray = [
1816
+ self.base58_to_binary(self.apiKey),
1817
+ self.number_to_be(currentTimestamp, 8),
1818
+ ]
1819
+ binary = self.binary_concat_array(byteArray)
1820
+ hexSecret = self.binary_to_base16(self.base58_to_binary(self.secret))
1821
+ signature = self.axolotl(self.binary_to_base16(binary), hexSecret, 'ed25519')
1822
+ matcherRequest: dict = {
1823
+ 'publicKey': self.apiKey,
1824
+ 'signature': signature,
1825
+ 'timestamp': str(currentTimestamp),
1826
+ }
1827
+ reservedBalance = await self.matcherGetMatcherBalanceReservedPublicKey(matcherRequest)
1828
+ # {WAVES: 200300000}
1829
+ reservedKeys = list(reservedBalance.keys())
1830
+ for i in range(0, len(reservedKeys)):
1831
+ currencyId = reservedKeys[i]
1832
+ code = self.safe_currency_code(currencyId)
1833
+ if not (code in result):
1834
+ result[code] = self.account()
1835
+ amount = self.safe_string(reservedBalance, currencyId)
1836
+ result[code]['used'] = self.from_real_currency_amount(code, amount)
1837
+ wavesRequest: dict = {
1838
+ 'address': wavesAddress,
1839
+ }
1840
+ wavesTotal = await self.nodeGetAddressesBalanceAddress(wavesRequest)
1841
+ # {
1842
+ # "address": "3P8VzLSa23EW5CVckHbV7d5BoN75fF1hhFH",
1843
+ # "confirmations": 0,
1844
+ # "balance": 909085978
1845
+ # }
1846
+ result['WAVES'] = self.safe_value(result, 'WAVES', self.account())
1847
+ result['WAVES']['total'] = self.from_real_currency_amount('WAVES', self.safe_string(wavesTotal, 'balance'))
1848
+ result = self.set_undefined_balances_to_zero(result)
1849
+ result['timestamp'] = timestamp
1850
+ result['datetime'] = self.iso8601(timestamp)
1851
+ return self.safe_balance(result)
1852
+
1853
+ def set_undefined_balances_to_zero(self, balances, key='used'):
1854
+ codes = list(balances.keys())
1855
+ for i in range(0, len(codes)):
1856
+ code = codes[i]
1857
+ if self.safe_value(balances[code], 'used') is None:
1858
+ balances[code][key] = '0'
1859
+ return balances
1860
+
1861
+ async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1862
+ """
1863
+ fetch all trades made by the user
1864
+ :param str symbol: unified market symbol
1865
+ :param int [since]: the earliest time in ms to fetch trades for
1866
+ :param int [limit]: the maximum number of trades structures to retrieve
1867
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1868
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1869
+ """
1870
+ await self.load_markets()
1871
+ address = await self.get_waves_address()
1872
+ request: dict = {
1873
+ 'sender': address,
1874
+ }
1875
+ market = None
1876
+ if symbol is not None:
1877
+ market = self.market(symbol)
1878
+ request['amountAsset'] = market['baseId']
1879
+ request['priceAsset'] = market['quoteId']
1880
+ response = await self.publicGetTransactionsExchange(request)
1881
+ data = self.safe_value(response, 'data')
1882
+ #
1883
+ # {
1884
+ # "__type":"list",
1885
+ # "isLastPage":true,
1886
+ # "lastCursor":"MzA2MjQ0MzAwMDI5OjpkZXNj",
1887
+ # "data": [
1888
+ # {
1889
+ # "__type":"transaction",
1890
+ # "data": {
1891
+ # "id":"GbjPqco2wRP5QSrY5LimFrUyJaM535K9nhK5zaQ7J7Tx",
1892
+ # "timestamp":"2022-04-06T19:56:31.479Z",
1893
+ # "height":3062443,
1894
+ # "type":7,
1895
+ # "version":2,
1896
+ # "proofs":[
1897
+ # "57mYrANw61eiArCTv2eYwzXm71jYC2KpZ5AeM9zHEstuRaYSAWSuSE7njAJYJu8zap6DMCm3nzqc6es3wQFDpRCN"
1898
+ # ],
1899
+ # "fee":0.003,
1900
+ # "applicationStatus":"succeeded",
1901
+ # "sender":"3PEjHv3JGjcWNpYEEkif2w8NXV4kbhnoGgu",
1902
+ # "senderPublicKey":"9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5",
1903
+ # "buyMatcherFee":0,
1904
+ # "sellMatcherFee":0.00141728,
1905
+ # "price":215.7431,
1906
+ # "amount":0.09,
1907
+ # "order1": {
1908
+ # "id":"49qiuQj5frdZ6zpTCEpMuKPMAh1EimwXpXWB4BeCw33h",
1909
+ # "senderPublicKey":"CjUfoH3dsDZsf5UuAjqqzpWHXgvKzBZpVG9YixF7L48K",
1910
+ # "matcherPublicKey":"9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5",
1911
+ # "assetPair": {
1912
+ # "amountAsset":"7TMu26hAs7B2oW6c5sfx45KSZT7GQA3TZNYuCav8Dcqt",
1913
+ # "priceAsset":"DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p"
1914
+ # },
1915
+ # "orderType":"buy",
1916
+ # "price":215.7431,
1917
+ # "sender":"3PR9WmaHV5ueVw2Wr9xsiCG3t4ySXzkkGLy",
1918
+ # "amount":0.36265477,
1919
+ # "timestamp":"2022-04-06T19:55:06.832Z",
1920
+ # "expiration":"2022-05-05T19:55:06.832Z",
1921
+ # "matcherFee":3.000334,
1922
+ # "signature":"2rBWhdeuRJNpQfXfTFtcR8x8Lpic8FUHPdLML9uxABRUuxe48YRJcZxbncwWAh9LWFCEUZiztv7RZBZfGMWfFxTs",
1923
+ # "matcherFeeAssetId":"DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p"
1924
+ # },
1925
+ # "order2": {
1926
+ # "id":"AkxiJqCuv6wm8K41TUSgFNwShZMnCbMDT78MqrcWpQ53",
1927
+ # "senderPublicKey":"72o7qNKyne5hthB1Ww6famE7uHrk5vTVB2ZfUMBEqL3Y",
1928
+ # "matcherPublicKey":"9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5",
1929
+ # "assetPair": {
1930
+ # "amountAsset":"7TMu26hAs7B2oW6c5sfx45KSZT7GQA3TZNYuCav8Dcqt",
1931
+ # "priceAsset":"DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p"
1932
+ # },
1933
+ # "orderType":"sell",
1934
+ # "price":210,
1935
+ # "sender":"3P3CzbjGgiqEyUBeKZYfgZtyaZfMG8fjoUD",
1936
+ # "amount":0.09,
1937
+ # "timestamp":"2022-04-06T19:56:18.535Z",
1938
+ # "expiration":"2022-05-04T19:56:18.535Z",
1939
+ # "matcherFee":0.00141728,
1940
+ # "signature":"5BZCjYn6QzVkMXBFDBnzcAUBdCZqhq9hQfRXFHfLUQCsbis4zeriw4sUqLa1BZRT2isC6iY4Z4HtekikPqZ461PT",
1941
+ # "matcherFeeAssetId":"7TMu26hAs7B2oW6c5sfx45KSZT7GQA3TZNYuCav8Dcqt"
1942
+ # }
1943
+ # }
1944
+ # },...
1945
+ # ]
1946
+ # }
1947
+ #
1948
+ return self.parse_trades(data, market, since, limit)
1949
+
1950
+ async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1951
+ """
1952
+ get the list of most recent trades for a particular symbol
1953
+ :param str symbol: unified symbol of the market to fetch trades for
1954
+ :param int [since]: timestamp in ms of the earliest trade to fetch
1955
+ :param int [limit]: the maximum amount of trades to fetch
1956
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1957
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
1958
+ """
1959
+ await self.load_markets()
1960
+ market = self.market(symbol)
1961
+ request: dict = {
1962
+ 'amountAsset': market['baseId'],
1963
+ 'priceAsset': market['quoteId'],
1964
+ }
1965
+ if limit is not None:
1966
+ request['limit'] = min(limit, 100)
1967
+ if since is not None:
1968
+ request['timeStart'] = since
1969
+ response = await self.publicGetTransactionsExchange(request)
1970
+ data = self.safe_value(response, 'data')
1971
+ #
1972
+ # {
1973
+ # "__type":"list",
1974
+ # "isLastPage":false,
1975
+ # "lastCursor":"MzA2MjM2MTAwMDU0OjpkZXNj",
1976
+ # "data": [
1977
+ # {
1978
+ # "__type":"transaction",
1979
+ # "data": {
1980
+ # "id":"F42WsvSsyEzvpPLFjVhQKkSNuopooP4zMkjSUs47NeML",
1981
+ # "timestamp":"2022-04-06T18:39:49.145Z",
1982
+ # "height":3062361,
1983
+ # "type":7,
1984
+ # "version":2,
1985
+ # "proofs": [
1986
+ # "39iJv82kFi4pyuBxYeZpP45NXXjbrCXdVsHPAAvj32UMLmTXLjMTfV43PcmZDSAuS93HKSDo1aKJrin8UvkeE9Bs"
1987
+ # ],
1988
+ # "fee":0.003,
1989
+ # "applicationStatus":"succeeded",
1990
+ # "sender":"3PEjHv3JGjcWNpYEEkif2w8NXV4kbhnoGgu",
1991
+ # "senderPublicKey":"9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5",
1992
+ # "buyMatcherFee":0.02314421,
1993
+ # "sellMatcherFee":0,
1994
+ # "price":217.3893,
1995
+ # "amount":0.34523025,
1996
+ # "order1": {
1997
+ # "id":"HkM36PHGaeeZdDKT1mYgZXhaU9PRZ54RZiJc2K4YMT3Q",
1998
+ # "senderPublicKey":"7wYCaDcc6GX1Jx2uS7QgLHBypBKvrezTS1HfiW6Xe4Bk",
1999
+ # "matcherPublicKey":"9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5",
2000
+ # "assetPair": {
2001
+ # "amountAsset":"7TMu26hAs7B2oW6c5sfx45KSZT7GQA3TZNYuCav8Dcqt",
2002
+ # "priceAsset":"DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p"
2003
+ # },
2004
+ # "orderType":"buy",
2005
+ # "price":225.2693,
2006
+ # "sender":"3PLPc8f4DGYaF9C9bwJ2uVmHqRv3NCjg5VQ",
2007
+ # "amount":2.529,
2008
+ # "timestamp":"2022-04-06T18:39:48.796Z",
2009
+ # "expiration":"2022-05-05T18:39:48.796Z",
2010
+ # "matcherFee":0.17584444,
2011
+ # "signature":"2yQfJoomv86evQDw36fg1uiRkHvPDZtRp3qvxqTBWPvz4JLTHGQtEHJF5NGTvym6U93CtgNprngzmD9ecHBjxf6U",
2012
+ # "matcherFeeAssetId":"Atqv59EYzjFGuitKVnMRk6H8FukjoV3ktPorbEys25on"
2013
+ # },
2014
+ # "order2": {
2015
+ # "id":"F7HKmeuzwWdk3wKitHLnVx5MuD4wBWPpphQ8kUGx4tT9",
2016
+ # "senderPublicKey":"CjUfoH3dsDZsf5UuAjqqzpWHXgvKzBZpVG9YixF7L48K",
2017
+ # "matcherPublicKey":"9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5",
2018
+ # "assetPair": {
2019
+ # "amountAsset":"7TMu26hAs7B2oW6c5sfx45KSZT7GQA3TZNYuCav8Dcqt",
2020
+ # "priceAsset":"DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p"
2021
+ # },
2022
+ # "orderType":"sell",
2023
+ # "price":217.3893,
2024
+ # "sender":"3PR9WmaHV5ueVw2Wr9xsiCG3t4ySXzkkGLy",
2025
+ # "amount":0.35767793,
2026
+ # "timestamp":"2022-04-06T18:32:01.390Z",
2027
+ # "expiration":"2022-05-05T18:32:01.390Z",
2028
+ # "matcherFee":0.0139168,
2029
+ # "signature":"34HgWVLPgeYWkiSvAc5ChVepGTYDQDug2dMTSincs6idEyoM7AtaZuH3mqQ5RJG2fcxxH2QSB723Qq3dgLQwQmKf",
2030
+ # "matcherFeeAssetId":"7TMu26hAs7B2oW6c5sfx45KSZT7GQA3TZNYuCav8Dcqt"
2031
+ # }
2032
+ # }
2033
+ # }, ...
2034
+ # ]
2035
+ # }
2036
+ #
2037
+ return self.parse_trades(data, market, since, limit)
2038
+
2039
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
2040
+ #
2041
+ # {__type: "transaction",
2042
+ # "data":
2043
+ # {id: "HSdruioHqvYHeyn9hhyoHdRWPB2bFA8ujeCPZMK6992c",
2044
+ # "timestamp": "2020-06-09T19:34:51.897Z",
2045
+ # "height": 2099684,
2046
+ # "type": 7,
2047
+ # "version": 2,
2048
+ # "proofs":
2049
+ # ["26teDHERQgwjjHqEn4REcDotNG8M21xjou3X42XuDuCvrRkQo6aPyrswByH3UrkWG8v27ZAaVNzoxDg4teNcLtde"],
2050
+ # "fee": 0.003,
2051
+ # "sender": "3PEjHv3JGjcWNpYEEkif2w8NXV4kbhnoGgu",
2052
+ # "senderPublicKey": "9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5",
2053
+ # "buyMatcherFee": 0.00299999,
2054
+ # "sellMatcherFee": 0.00299999,
2055
+ # "price": 0.00012003,
2056
+ # "amount": 60.80421562,
2057
+ # "order1":
2058
+ # {id: "CBRwP3ar4oMvvpUiGyfxc1syh41488SDi2GkrjuBDegv",
2059
+ # "senderPublicKey": "DBXSHBz96NFsMu7xh4fi2eT9ZnyxefAHXsMxUayzgC6a",
2060
+ # "matcherPublicKey": "9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5",
2061
+ # "assetPair": [Object],
2062
+ # "orderType": "buy",
2063
+ # "price": 0.00012003,
2064
+ # "sender": "3PJfFRgVuJ47UY4ckb74EGzEBzkHXtmG1LA",
2065
+ # "amount": 60.80424773,
2066
+ # "timestamp": "2020-06-09T19:34:51.885Z",
2067
+ # "expiration": "2020-06-10T12:31:31.885Z",
2068
+ # "matcherFee": 0.003,
2069
+ # "signature": "4cA3ZAb3XAEEXaFG7caqpto5TRbpR5PkhZpxoNQZ9ZReNvjuJQs5a3THnumv7rcqmVUiVtuHAgk2f67ANcqtKyJ8",
2070
+ # "matcherFeeAssetId": null},
2071
+ # "order2":
2072
+ # {id: "CHJSLQ6dfSPs6gu2mAegrMUcRiDEDqaj2GKfvptMjS3M",
2073
+ # "senderPublicKey": "3RUC4NGFZm9H8VJhSSjJyFLdiE42qNiUagDcZPwjgDf8",
2074
+ # "matcherPublicKey": "9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5",
2075
+ # "assetPair": [Object],
2076
+ # "orderType": "sell",
2077
+ # "price": 0.00012003,
2078
+ # "sender": "3P9vKoQpMZtaSkHKpNh977YY9ZPzTuntLAq",
2079
+ # "amount": 60.80424773,
2080
+ # "timestamp": "2020-06-09T19:34:51.887Z",
2081
+ # "expiration": "2020-06-10T12:31:31.887Z",
2082
+ # "matcherFee": 0.003,
2083
+ # "signature": "3SFyrcqzou2ddZyNisnLYaGhLt5qRjKxH8Nw3s4T5U7CEKGX9DDo8dS27RgThPVGbYF1rYET1FwrWoQ2UFZ6SMTR",
2084
+ # "matcherFeeAssetId": null}}}
2085
+ #
2086
+ data = self.safe_value(trade, 'data')
2087
+ datetime = self.safe_string(data, 'timestamp')
2088
+ timestamp = self.parse8601(datetime)
2089
+ id = self.safe_string(data, 'id')
2090
+ priceString = self.safe_string(data, 'price')
2091
+ amountString = self.safe_string(data, 'amount')
2092
+ order1 = self.safe_value(data, 'order1')
2093
+ order2 = self.safe_value(data, 'order2')
2094
+ order = None
2095
+ # order2 arrived after order1
2096
+ if self.safe_string(order1, 'senderPublicKey') == self.apiKey:
2097
+ order = order1
2098
+ else:
2099
+ order = order2
2100
+ symbol = None
2101
+ assetPair = self.safe_value(order, 'assetPair')
2102
+ if assetPair is not None:
2103
+ symbol = self.get_symbol_from_asset_pair(assetPair)
2104
+ elif market is not None:
2105
+ symbol = market['symbol']
2106
+ side = self.safe_string(order, 'orderType')
2107
+ orderId = self.safe_string(order, 'id')
2108
+ fee = {
2109
+ 'cost': self.safe_string(order, 'matcherFee'),
2110
+ 'currency': self.safe_currency_code(self.safe_string(order, 'matcherFeeAssetId', 'WAVES')),
2111
+ }
2112
+ return self.safe_trade({
2113
+ 'info': trade,
2114
+ 'timestamp': timestamp,
2115
+ 'datetime': datetime,
2116
+ 'symbol': symbol,
2117
+ 'id': id,
2118
+ 'order': orderId,
2119
+ 'type': None,
2120
+ 'side': side,
2121
+ 'takerOrMaker': None,
2122
+ 'price': priceString,
2123
+ 'amount': amountString,
2124
+ 'cost': None,
2125
+ 'fee': fee,
2126
+ }, market)
2127
+
2128
+ def parse_deposit_withdraw_fees(self, response, codes: Strings = None, currencyIdKey=None) -> Any:
2129
+ depositWithdrawFees: dict = {}
2130
+ codes = self.market_codes(codes)
2131
+ for i in range(0, len(response)):
2132
+ entry = response[i]
2133
+ dictionary = entry
2134
+ currencyId = self.safe_string(dictionary, currencyIdKey)
2135
+ currency = self.safe_value(self.currencies_by_id, currencyId)
2136
+ code = self.safe_string(currency, 'code', currencyId)
2137
+ if (codes is None) or (self.in_array(code, codes)):
2138
+ depositWithdrawFee = self.safe_value(depositWithdrawFees, code)
2139
+ if depositWithdrawFee is None:
2140
+ depositWithdrawFee = {
2141
+ 'info': [dictionary],
2142
+ 'withdraw': {
2143
+ 'fee': None,
2144
+ 'percentage': None,
2145
+ },
2146
+ 'deposit': {
2147
+ 'fee': None,
2148
+ 'percentage': None,
2149
+ },
2150
+ 'networks': {},
2151
+ }
2152
+ else:
2153
+ depositWithdrawFee = depositWithdrawFees[code]
2154
+ depositWithdrawFee['info'] = self.array_concat(depositWithdrawFee['info'], [dictionary])
2155
+ networkId = self.safe_string(dictionary, 'platform_id')
2156
+ currencyCode = self.safe_string(currency, 'code')
2157
+ networkCode = self.network_id_to_code(networkId, currencyCode)
2158
+ network = self.safe_value(depositWithdrawFee['networks'], networkCode)
2159
+ if network is None:
2160
+ network = {
2161
+ 'withdraw': {
2162
+ 'fee': None,
2163
+ 'percentage': None,
2164
+ },
2165
+ 'deposit': {
2166
+ 'fee': None,
2167
+ 'percentage': None,
2168
+ },
2169
+ }
2170
+ feeType = self.safe_string(dictionary, 'type')
2171
+ fees = self.safe_value(dictionary, 'fees')
2172
+ networkKey = 'deposit'
2173
+ if feeType == 'withdrawal_currency':
2174
+ networkKey = 'withdraw'
2175
+ network[networkKey] = {'fee': self.safe_number(fees, 'flat'), 'percentage': False}
2176
+ depositWithdrawFee['networks'][networkCode] = network
2177
+ depositWithdrawFees[code] = depositWithdrawFee
2178
+ depositWithdrawFeesKeys = list(depositWithdrawFees.keys())
2179
+ for i in range(0, len(depositWithdrawFeesKeys)):
2180
+ code = depositWithdrawFeesKeys[i]
2181
+ entry = depositWithdrawFees[code]
2182
+ networks = self.safe_value(entry, 'networks')
2183
+ networkKeys = list(networks.keys())
2184
+ networkKeysLength = len(networkKeys)
2185
+ if networkKeysLength == 1:
2186
+ network = self.safe_value(networks, networkKeys[0])
2187
+ depositWithdrawFees[code]['withdraw'] = self.safe_value(network, 'withdraw')
2188
+ depositWithdrawFees[code]['deposit'] = self.safe_value(network, 'deposit')
2189
+ return depositWithdrawFees
2190
+
2191
+ async def fetch_deposit_withdraw_fees(self, codes: Strings = None, params={}):
2192
+ """
2193
+ fetch deposit and withdraw fees
2194
+ :see: https://docs.wx.network/en/api/gateways/deposit/currencies
2195
+ :see: https://docs.wx.network/en/api/gateways/withdraw/currencies
2196
+ :param str[]|None codes: list of unified currency codes
2197
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2198
+ :returns dict: a list of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>`
2199
+ """
2200
+ await self.load_markets()
2201
+ data = []
2202
+ promises = []
2203
+ promises.append(self.privateGetDepositCurrencies(params))
2204
+ promises.append(self.privateGetWithdrawCurrencies(params))
2205
+ promises = await asyncio.gather(*promises)
2206
+ #
2207
+ # {
2208
+ # "type": "list",
2209
+ # "page_info": {
2210
+ # "has_next_page": False,
2211
+ # "last_cursor": null
2212
+ # },
2213
+ # "items": [
2214
+ # {
2215
+ # "type": "deposit_currency",
2216
+ # "id": "WEST",
2217
+ # "platform_id": "WEST",
2218
+ # "waves_asset_id": "4LHHvYGNKJUg5hj65aGD5vgScvCBmLpdRFtjokvCjSL8",
2219
+ # "platform_asset_id": "WEST",
2220
+ # "decimals": 8,
2221
+ # "status": "active",
2222
+ # "allowed_amount": {
2223
+ # "min": 0.1,
2224
+ # "max": 2000000
2225
+ # },
2226
+ # "fees": {
2227
+ # "flat": 0,
2228
+ # "rate": 0
2229
+ # }
2230
+ # },
2231
+ # ]
2232
+ # }
2233
+ #
2234
+ #
2235
+ # {
2236
+ # "type": "list",
2237
+ # "page_info": {
2238
+ # "has_next_page": False,
2239
+ # "last_cursor": null
2240
+ # },
2241
+ # "items": [
2242
+ # {
2243
+ # "type": "withdrawal_currency",
2244
+ # "id": "BTC",
2245
+ # "platform_id": "BTC",
2246
+ # "waves_asset_id": "8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS",
2247
+ # "platform_asset_id": "BTC",
2248
+ # "decimals": 8,
2249
+ # "status": "inactive",
2250
+ # "allowed_amount": {
2251
+ # "min": 0.001,
2252
+ # "max": 10
2253
+ # },
2254
+ # "fees": {
2255
+ # "flat": 0.001,
2256
+ # "rate": 0
2257
+ # }
2258
+ # },
2259
+ # ]
2260
+ # }
2261
+ #
2262
+ for i in range(0, len(promises)):
2263
+ items = self.safe_value(promises[i], 'items')
2264
+ data = self.array_concat(data, items)
2265
+ return self.parse_deposit_withdraw_fees(data, codes, 'id')
2266
+
2267
+ def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
2268
+ errorCode = self.safe_string(response, 'error')
2269
+ success = self.safe_bool(response, 'success', True)
2270
+ Exception = self.safe_value(self.exceptions, errorCode)
2271
+ if Exception is not None:
2272
+ messageInner = self.safe_string(response, 'message')
2273
+ raise Exception(self.id + ' ' + messageInner)
2274
+ message = self.safe_string(response, 'message')
2275
+ if message == 'Validation Error':
2276
+ raise BadRequest(self.id + ' ' + body)
2277
+ if not success:
2278
+ raise ExchangeError(self.id + ' ' + body)
2279
+ return None
2280
+
2281
+ async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
2282
+ """
2283
+ make a withdrawal
2284
+ :param str code: unified currency code
2285
+ :param float amount: the amount to withdraw
2286
+ :param str address: the address to withdraw to
2287
+ :param str tag:
2288
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2289
+ :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
2290
+ """
2291
+ tag, params = self.handle_withdraw_tag_and_params(tag, params)
2292
+ # currently only works for BTC and WAVES
2293
+ if code != 'WAVES':
2294
+ supportedCurrencies = await self.privateGetWithdrawCurrencies()
2295
+ currencies: dict = {}
2296
+ items = self.safe_value(supportedCurrencies, 'items', [])
2297
+ for i in range(0, len(items)):
2298
+ entry = items[i]
2299
+ currencyCode = self.safe_string(entry, 'id')
2300
+ currencies[currencyCode] = True
2301
+ if not (code in currencies):
2302
+ codes = list(currencies.keys())
2303
+ raise ExchangeError(self.id + ' withdraw() ' + code + ' not supported. Currency code must be one of ' + str(codes))
2304
+ await self.load_markets()
2305
+ hexChars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
2306
+ set: dict = {}
2307
+ for i in range(0, len(hexChars)):
2308
+ key = hexChars[i]
2309
+ set[key] = True
2310
+ isErc20 = True
2311
+ noPrefix = self.remove0x_prefix(address)
2312
+ lower = noPrefix.lower()
2313
+ stringLength = len(lower) * 1
2314
+ for i in range(0, stringLength):
2315
+ character = lower[i]
2316
+ if not (character in set):
2317
+ isErc20 = False
2318
+ break
2319
+ await self.sign_in()
2320
+ proxyAddress = None
2321
+ if code == 'WAVES' and not isErc20:
2322
+ proxyAddress = address
2323
+ else:
2324
+ withdrawAddressRequest: dict = {
2325
+ 'address': address,
2326
+ 'currency': code,
2327
+ }
2328
+ withdrawAddress = await self.privateGetWithdrawAddressesCurrencyAddress(withdrawAddressRequest)
2329
+ currencyInner = self.safe_value(withdrawAddress, 'currency')
2330
+ allowedAmount = self.safe_value(currencyInner, 'allowed_amount')
2331
+ minimum = self.safe_number(allowedAmount, 'min')
2332
+ if amount <= minimum:
2333
+ raise BadRequest(self.id + ' ' + code + ' withdraw failed, amount ' + str(amount) + ' must be greater than the minimum allowed amount of ' + str(minimum))
2334
+ # {
2335
+ # "type": "withdrawal_addresses",
2336
+ # "currency": {
2337
+ # "type": "withdrawal_currency",
2338
+ # "id": "BTC",
2339
+ # "waves_asset_id": "8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS",
2340
+ # "decimals": 8,
2341
+ # "status": "active",
2342
+ # "allowed_amount": {
2343
+ # "min": 0.001,
2344
+ # "max": 20
2345
+ # },
2346
+ # "fees": {
2347
+ # "flat": 0.001,
2348
+ # "rate": 0
2349
+ # }
2350
+ # },
2351
+ # "proxy_addresses": [
2352
+ # "3P3qqmkiLwNHB7x1FeoE8bvkRtULwGpo9ga"
2353
+ # ]
2354
+ # }
2355
+ proxyAddresses = self.safe_value(withdrawAddress, 'proxy_addresses', [])
2356
+ proxyAddress = self.safe_string(proxyAddresses, 0)
2357
+ fee = self.safe_integer(self.options, 'withdrawFeeWAVES', 100000) # 0.001 WAVES
2358
+ feeAssetId = 'WAVES'
2359
+ type = 4 # transfer
2360
+ version = 2
2361
+ amountInteger = self.to_real_currency_amount(code, amount)
2362
+ currency = self.currency(code)
2363
+ timestamp = self.milliseconds()
2364
+ byteArray = [
2365
+ self.number_to_be(4, 1),
2366
+ self.number_to_be(2, 1),
2367
+ self.base58_to_binary(self.apiKey),
2368
+ self.get_asset_bytes(currency['id']),
2369
+ self.get_asset_bytes(feeAssetId),
2370
+ self.number_to_be(timestamp, 8),
2371
+ self.number_to_be(amountInteger, 8),
2372
+ self.number_to_be(fee, 8),
2373
+ self.base58_to_binary(proxyAddress),
2374
+ self.number_to_be(0, 2),
2375
+ ]
2376
+ binary = self.binary_concat_array(byteArray)
2377
+ hexSecret = self.binary_to_base16(self.base58_to_binary(self.secret))
2378
+ signature = self.axolotl(self.binary_to_base16(binary), hexSecret, 'ed25519')
2379
+ request: dict = {
2380
+ 'senderPublicKey': self.apiKey,
2381
+ 'amount': amountInteger,
2382
+ 'fee': fee,
2383
+ 'type': type,
2384
+ 'version': version,
2385
+ 'attachment': '',
2386
+ 'feeAssetId': self.get_asset_id(feeAssetId),
2387
+ 'proofs': [
2388
+ signature,
2389
+ ],
2390
+ 'assetId': self.get_asset_id(currency['id']),
2391
+ 'recipient': proxyAddress,
2392
+ 'timestamp': timestamp,
2393
+ 'signature': signature,
2394
+ }
2395
+ result = await self.nodePostTransactionsBroadcast(request)
2396
+ #
2397
+ # {
2398
+ # "id": "string",
2399
+ # "signature": "string",
2400
+ # "fee": 0,
2401
+ # "timestamp": 1460678400000,
2402
+ # "recipient": "3P274YB5qseSE9DTTL3bpSjosZrYBPDpJ8k",
2403
+ # "amount": 0
2404
+ # }
2405
+ #
2406
+ return self.parse_transaction(result, currency)
2407
+
2408
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
2409
+ #
2410
+ # withdraw
2411
+ #
2412
+ # {
2413
+ # "id": "string",
2414
+ # "signature": "string",
2415
+ # "fee": 0,
2416
+ # "timestamp": 1460678400000,
2417
+ # "recipient": "3P274YB5qseSE9DTTL3bpSjosZrYBPDpJ8k",
2418
+ # "amount": 0
2419
+ # }
2420
+ #
2421
+ # withdraw new:
2422
+ # {
2423
+ # type: "4",
2424
+ # id: "2xnWTqG9ar7jEDrLxfbVyyspPZ6XZNrrw9ai9sQ81Eya",
2425
+ # fee: "100000",
2426
+ # feeAssetId: null,
2427
+ # timestamp: "1715786263807",
2428
+ # version: "2",
2429
+ # sender: "3P81LLX1kk2CSJC9L8C2enxdHB7XvnSGAEE",
2430
+ # senderPublicKey: "DdmzmXf9mty1FBE8AdVGnrncVLEAzP4gR4nWoTFAJoXz",
2431
+ # proofs: ["RyoKwdSYv3EqotJCYftfFM9JE2j1ZpDRxKwYfiRhLAFeyNp6VfJUXNDS884XfeCeHeNypNmTCZt5NYR1ekyjCX3",],
2432
+ # recipient: "3P9tXxu38a8tgewNEKFzourVxeqHd11ppOc",
2433
+ # assetId: null,
2434
+ # feeAsset: null,
2435
+ # amount: "2000000",
2436
+ # attachment: "",
2437
+ # }
2438
+ #
2439
+ currency = self.safe_currency(None, currency)
2440
+ code = currency['code']
2441
+ typeRaw = self.safe_string(transaction, 'type')
2442
+ type = 'withdraw' if (typeRaw == '4') else 'deposit'
2443
+ amount = self.parse_number(self.from_real_currency_amount(code, self.safe_string(transaction, 'amount')))
2444
+ feeString = self.safe_string(transaction, 'fee')
2445
+ feeAssetId = self.safe_string(transaction, 'feeAssetId', 'WAVES')
2446
+ feeCode = self.safe_currency_code(feeAssetId)
2447
+ feeAmount = self.parse_number(self.from_real_currency_amount(feeCode, feeString))
2448
+ timestamp = self.safe_integer(transaction, 'timestamp')
2449
+ return {
2450
+ 'id': self.safe_string(transaction, 'id'),
2451
+ 'txid': None,
2452
+ 'timestamp': timestamp,
2453
+ 'datetime': self.iso8601(timestamp),
2454
+ 'network': None,
2455
+ 'addressFrom': self.safe_string(transaction, 'sender'),
2456
+ 'address': None,
2457
+ 'addressTo': self.safe_string(transaction, 'recipient'),
2458
+ 'amount': amount,
2459
+ 'type': type,
2460
+ 'currency': currency['code'],
2461
+ 'status': None,
2462
+ 'updated': None,
2463
+ 'tagFrom': None,
2464
+ 'tag': None,
2465
+ 'tagTo': None,
2466
+ 'comment': None,
2467
+ 'internal': None,
2468
+ 'fee': {
2469
+ 'currency': feeCode,
2470
+ 'cost': feeAmount,
2471
+ },
2472
+ 'info': transaction,
2473
+ }