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,3960 @@
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.digifinex import ImplicitAPI
8
+ import asyncio
9
+ import hashlib
10
+ import json
11
+ from ccxt.base.types import Balances, CrossBorrowRate, CrossBorrowRates, Currencies, Currency, Int, LeverageTier, LeverageTiers, MarginModification, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry, TransferEntries
12
+ from typing import List
13
+ from ccxt.base.errors import ExchangeError
14
+ from ccxt.base.errors import AuthenticationError
15
+ from ccxt.base.errors import PermissionDenied
16
+ from ccxt.base.errors import AccountSuspended
17
+ from ccxt.base.errors import ArgumentsRequired
18
+ from ccxt.base.errors import BadRequest
19
+ from ccxt.base.errors import BadSymbol
20
+ from ccxt.base.errors import BadResponse
21
+ from ccxt.base.errors import InsufficientFunds
22
+ from ccxt.base.errors import InvalidAddress
23
+ from ccxt.base.errors import InvalidOrder
24
+ from ccxt.base.errors import OrderNotFound
25
+ from ccxt.base.errors import NotSupported
26
+ from ccxt.base.errors import NetworkError
27
+ from ccxt.base.errors import DDoSProtection
28
+ from ccxt.base.errors import RateLimitExceeded
29
+ from ccxt.base.errors import InvalidNonce
30
+ from ccxt.base.decimal_to_precision import TICK_SIZE
31
+ from ccxt.base.precise import Precise
32
+
33
+
34
+ class digifinex(Exchange, ImplicitAPI):
35
+
36
+ def describe(self):
37
+ return self.deep_extend(super(digifinex, self).describe(), {
38
+ 'id': 'digifinex',
39
+ 'name': 'DigiFinex',
40
+ 'countries': ['SG'],
41
+ 'version': 'v3',
42
+ 'rateLimit': 900, # 300 for posts
43
+ 'has': {
44
+ 'CORS': None,
45
+ 'spot': True,
46
+ 'margin': True,
47
+ 'swap': True,
48
+ 'future': False,
49
+ 'option': False,
50
+ 'addMargin': True,
51
+ 'cancelOrder': True,
52
+ 'cancelOrders': True,
53
+ 'createMarketBuyOrderWithCost': True,
54
+ 'createMarketOrderWithCost': False,
55
+ 'createMarketSellOrderWithCost': False,
56
+ 'createOrder': True,
57
+ 'createOrders': True,
58
+ 'createPostOnlyOrder': True,
59
+ 'createReduceOnlyOrder': True,
60
+ 'createStopLimitOrder': False,
61
+ 'createStopMarketOrder': False,
62
+ 'createStopOrder': False,
63
+ 'fetchBalance': True,
64
+ 'fetchBorrowInterest': True,
65
+ 'fetchBorrowRateHistories': False,
66
+ 'fetchBorrowRateHistory': False,
67
+ 'fetchCrossBorrowRate': True,
68
+ 'fetchCrossBorrowRates': True,
69
+ 'fetchCurrencies': True,
70
+ 'fetchDepositAddress': True,
71
+ 'fetchDeposits': True,
72
+ 'fetchDepositWithdrawFee': 'emulated',
73
+ 'fetchDepositWithdrawFees': True,
74
+ 'fetchFundingHistory': True,
75
+ 'fetchFundingRate': True,
76
+ 'fetchFundingRateHistory': True,
77
+ 'fetchFundingRates': False,
78
+ 'fetchIndexOHLCV': False,
79
+ 'fetchIsolatedBorrowRate': False,
80
+ 'fetchIsolatedBorrowRates': False,
81
+ 'fetchLedger': True,
82
+ 'fetchLeverage': False,
83
+ 'fetchLeverageTiers': True,
84
+ 'fetchMarginMode': False,
85
+ 'fetchMarketLeverageTiers': True,
86
+ 'fetchMarkets': True,
87
+ 'fetchMarkOHLCV': False,
88
+ 'fetchMyTrades': True,
89
+ 'fetchOHLCV': True,
90
+ 'fetchOpenOrders': True,
91
+ 'fetchOrder': True,
92
+ 'fetchOrderBook': True,
93
+ 'fetchOrders': True,
94
+ 'fetchPosition': True,
95
+ 'fetchPositionMode': False,
96
+ 'fetchPositions': True,
97
+ 'fetchPositionsRisk': False,
98
+ 'fetchPremiumIndexOHLCV': False,
99
+ 'fetchStatus': True,
100
+ 'fetchTicker': True,
101
+ 'fetchTickers': True,
102
+ 'fetchTime': True,
103
+ 'fetchTrades': True,
104
+ 'fetchTradingFee': True,
105
+ 'fetchTradingFees': False,
106
+ 'fetchTransfers': True,
107
+ 'fetchWithdrawals': True,
108
+ 'reduceMargin': True,
109
+ 'setLeverage': True,
110
+ 'setMargin': False,
111
+ 'setMarginMode': True,
112
+ 'setPositionMode': False,
113
+ 'transfer': True,
114
+ 'withdraw': True,
115
+ },
116
+ 'timeframes': {
117
+ '1m': '1',
118
+ '5m': '5',
119
+ '15m': '15',
120
+ '30m': '30',
121
+ '1h': '60',
122
+ '4h': '240',
123
+ '12h': '720',
124
+ '1d': '1D',
125
+ '1w': '1W',
126
+ },
127
+ 'urls': {
128
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87443315-01283a00-c5fe-11ea-8628-c2a0feaf07ac.jpg',
129
+ 'api': {
130
+ 'rest': 'https://openapi.digifinex.com',
131
+ },
132
+ 'www': 'https://www.digifinex.com',
133
+ 'doc': [
134
+ 'https://docs.digifinex.com',
135
+ ],
136
+ 'fees': 'https://digifinex.zendesk.com/hc/en-us/articles/360000328422-Fee-Structure-on-DigiFinex',
137
+ 'referral': 'https://www.digifinex.com/en-ww/from/DhOzBg?channelCode=ljaUPp',
138
+ },
139
+ 'api': {
140
+ 'public': {
141
+ 'spot': {
142
+ 'get': [
143
+ '{market}/symbols',
144
+ 'kline',
145
+ 'margin/currencies',
146
+ 'margin/symbols',
147
+ 'markets',
148
+ 'order_book',
149
+ 'ping',
150
+ 'spot/symbols',
151
+ 'time',
152
+ 'trades',
153
+ 'trades/symbols',
154
+ 'ticker',
155
+ 'currencies',
156
+ ],
157
+ },
158
+ 'swap': {
159
+ 'get': [
160
+ 'public/api_weight',
161
+ 'public/candles',
162
+ 'public/candles_history',
163
+ 'public/depth',
164
+ 'public/funding_rate',
165
+ 'public/funding_rate_history',
166
+ 'public/instrument',
167
+ 'public/instruments',
168
+ 'public/ticker',
169
+ 'public/tickers',
170
+ 'public/time',
171
+ 'public/trades',
172
+ ],
173
+ },
174
+ },
175
+ 'private': {
176
+ 'spot': {
177
+ 'get': [
178
+ '{market}/financelog',
179
+ '{market}/mytrades',
180
+ '{market}/order',
181
+ '{market}/order/detail',
182
+ '{market}/order/current',
183
+ '{market}/order/history',
184
+ 'margin/assets',
185
+ 'margin/financelog',
186
+ 'margin/mytrades',
187
+ 'margin/order',
188
+ 'margin/order/current',
189
+ 'margin/order/history',
190
+ 'margin/positions',
191
+ 'otc/financelog',
192
+ 'spot/assets',
193
+ 'spot/financelog',
194
+ 'spot/mytrades',
195
+ 'spot/order',
196
+ 'spot/order/current',
197
+ 'spot/order/history',
198
+ 'deposit/address',
199
+ 'deposit/history',
200
+ 'withdraw/history',
201
+ ],
202
+ 'post': [
203
+ '{market}/order/cancel',
204
+ '{market}/order/new',
205
+ '{market}/order/batch_new',
206
+ 'margin/order/cancel',
207
+ 'margin/order/new',
208
+ 'margin/position/close',
209
+ 'spot/order/cancel',
210
+ 'spot/order/new',
211
+ 'transfer',
212
+ 'withdraw/new',
213
+ 'withdraw/cancel',
214
+ ],
215
+ },
216
+ 'swap': {
217
+ 'get': [
218
+ 'account/balance',
219
+ 'account/positions',
220
+ 'account/finance_record',
221
+ 'account/trading_fee_rate',
222
+ 'account/transfer_record',
223
+ 'account/funding_fee',
224
+ 'trade/history_orders',
225
+ 'trade/history_trades',
226
+ 'trade/open_orders',
227
+ 'trade/order_info',
228
+ ],
229
+ 'post': [
230
+ 'account/leverage',
231
+ 'account/position_mode',
232
+ 'account/position_margin',
233
+ 'trade/batch_cancel_order',
234
+ 'trade/batch_order',
235
+ 'trade/cancel_order',
236
+ 'trade/order_place',
237
+ 'follow/sponsor_order',
238
+ 'follow/close_order',
239
+ 'follow/cancel_order',
240
+ 'follow/user_center_current',
241
+ 'follow/user_center_history',
242
+ 'follow/expert_current_open_order',
243
+ 'follow/add_algo',
244
+ 'follow/cancel_algo',
245
+ 'follow/account_available',
246
+ 'follow/plan_task',
247
+ 'follow/instrument_list',
248
+ ],
249
+ },
250
+ },
251
+ },
252
+ 'fees': {
253
+ 'trading': {
254
+ 'tierBased': True,
255
+ 'percentage': True,
256
+ 'maker': self.parse_number('0.002'),
257
+ 'taker': self.parse_number('0.002'),
258
+ },
259
+ },
260
+ 'precisionMode': TICK_SIZE,
261
+ 'exceptions': {
262
+ 'exact': {
263
+ '10001': [BadRequest, "Wrong request method, please check it's a GET ot POST request"],
264
+ '10002': [AuthenticationError, 'Invalid ApiKey'],
265
+ '10003': [AuthenticationError, "Sign doesn't match"],
266
+ '10004': [BadRequest, 'Illegal request parameters'],
267
+ '10005': [DDoSProtection, 'Request frequency exceeds the limit'],
268
+ '10006': [PermissionDenied, 'Unauthorized to execute self request'],
269
+ '10007': [PermissionDenied, 'IP address Unauthorized'],
270
+ '10008': [InvalidNonce, 'Timestamp for self request is invalid, timestamp must within 1 minute'],
271
+ '10009': [NetworkError, 'Unexist endpoint, please check endpoint URL'],
272
+ '10011': [AccountSuspended, 'ApiKey expired. Please go to client side to re-create an ApiKey'],
273
+ '20001': [PermissionDenied, 'Trade is not open for self trading pair'],
274
+ '20002': [PermissionDenied, 'Trade of self trading pair is suspended'],
275
+ '20003': [InvalidOrder, 'Invalid price or amount'],
276
+ '20007': [InvalidOrder, 'Price precision error'],
277
+ '20008': [InvalidOrder, 'Amount precision error'],
278
+ '20009': [InvalidOrder, 'Amount is less than the minimum requirement'],
279
+ '20010': [InvalidOrder, 'Cash Amount is less than the minimum requirement'],
280
+ '20011': [InsufficientFunds, 'Insufficient balance'],
281
+ '20012': [BadRequest, 'Invalid trade type, valid value: buy/sell)'],
282
+ '20013': [InvalidOrder, 'No order info found'],
283
+ '20014': [BadRequest, 'Invalid date, Valid format: 2018-07-25)'],
284
+ '20015': [BadRequest, 'Date exceeds the limit'],
285
+ '20018': [PermissionDenied, 'Your trading rights have been banned by the system'],
286
+ '20019': [BadSymbol, 'Wrong trading pair symbol. Correct format:"usdt_btc". Quote asset is in the front'],
287
+ '20020': [DDoSProtection, "You have violated the API operation trading rules and temporarily forbid trading. At present, we have certain restrictions on the user's transaction rate and withdrawal rate."],
288
+ '50000': [ExchangeError, 'Exception error'],
289
+ '20021': [BadRequest, 'Invalid currency'],
290
+ '20022': [BadRequest, 'The ending timestamp must be larger than the starting timestamp'],
291
+ '20023': [BadRequest, 'Invalid transfer type'],
292
+ '20024': [BadRequest, 'Invalid amount'],
293
+ '20025': [BadRequest, 'This currency is not transferable at the moment'],
294
+ '20026': [InsufficientFunds, 'Transfer amount exceed your balance'],
295
+ '20027': [PermissionDenied, 'Abnormal account status'],
296
+ '20028': [PermissionDenied, 'Blacklist for transfer'],
297
+ '20029': [PermissionDenied, 'Transfer amount exceed your daily limit'],
298
+ '20030': [BadRequest, 'You have no position on self trading pair'],
299
+ '20032': [PermissionDenied, 'Withdrawal limited'],
300
+ '20033': [BadRequest, 'Wrong Withdrawal ID'],
301
+ '20034': [PermissionDenied, 'Withdrawal service of self crypto has been closed'],
302
+ '20035': [PermissionDenied, 'Withdrawal limit'],
303
+ '20036': [ExchangeError, 'Withdrawal cancellation failed'],
304
+ '20037': [InvalidAddress, 'The withdrawal address, Tag or chain type is not included in the withdrawal management list'],
305
+ '20038': [InvalidAddress, 'The withdrawal address is not on the white list'],
306
+ '20039': [ExchangeError, "Can't be canceled in current status"],
307
+ '20040': [RateLimitExceeded, 'Withdraw too frequently; limitation: 3 times a minute, 100 times a day'],
308
+ '20041': [PermissionDenied, 'Beyond the daily withdrawal limit'],
309
+ '20042': [BadSymbol, 'Current trading pair does not support API trading'],
310
+ '400002': [BadRequest, 'Invalid Parameter'],
311
+ },
312
+ 'broad': {
313
+ },
314
+ },
315
+ 'options': {
316
+ 'defaultType': 'spot',
317
+ 'types': ['spot', 'margin', 'otc'],
318
+ 'createMarketBuyOrderRequiresPrice': True,
319
+ 'accountsByType': {
320
+ 'spot': '1',
321
+ 'margin': '2',
322
+ 'OTC': '3',
323
+ },
324
+ 'networks': {
325
+ 'ARBITRUM': 'Arbitrum',
326
+ 'AVALANCEC': 'AVAX-CCHAIN',
327
+ 'AVALANCEX': 'AVAX-XCHAIN',
328
+ 'BEP20': 'BEP20',
329
+ 'BSC': 'BEP20',
330
+ 'CARDANO': 'Cardano',
331
+ 'CELO': 'Celo',
332
+ 'CHILIZ': 'Chiliz',
333
+ 'COSMOS': 'COSMOS',
334
+ 'CRC20': 'Crypto.com',
335
+ 'CRONOS': 'Crypto.com',
336
+ 'DOGECOIN': 'DogeChain',
337
+ 'ERC20': 'ERC20',
338
+ 'ETH': 'ERC20',
339
+ 'ETHW': 'ETHW',
340
+ 'IOTA': 'MIOTA',
341
+ 'KLAYTN': 'KLAY',
342
+ 'MATIC': 'Polygon',
343
+ 'METIS': 'MetisDAO',
344
+ 'MOONBEAM': 'GLMR',
345
+ 'MOONRIVER': 'Moonriver',
346
+ 'OPTIMISM': 'OPETH',
347
+ 'POLYGON': 'Polygon',
348
+ 'RIPPLE': 'XRP',
349
+ 'SOLANA': 'SOL', # SOL & SPL
350
+ 'STELLAR': 'Stella', # XLM
351
+ 'TERRACLASSIC': 'TerraClassic',
352
+ 'TERRA': 'Terra',
353
+ 'TON': 'Ton',
354
+ 'TRC20': 'TRC20',
355
+ 'TRON': 'TRC20',
356
+ 'TRX': 'TRC20',
357
+ 'VECHAIN': 'Vechain', # VET
358
+ },
359
+ },
360
+ 'commonCurrencies': {
361
+ 'BHT': 'Black House Test',
362
+ 'EPS': 'Epanus',
363
+ 'FREE': 'FreeRossDAO',
364
+ 'MBN': 'Mobilian Coin',
365
+ 'TEL': 'TEL666',
366
+ },
367
+ })
368
+
369
+ async def fetch_currencies(self, params={}) -> Currencies:
370
+ """
371
+ fetches all available currencies on an exchange
372
+ :param dict [params]: extra parameters specific to the exchange API endpoint
373
+ :returns dict: an associative dictionary of currencies
374
+ """
375
+ response = await self.publicSpotGetCurrencies(params)
376
+ #
377
+ # {
378
+ # "data":[
379
+ # {
380
+ # "deposit_status":1,
381
+ # "min_deposit_amount":10,
382
+ # "withdraw_fee_rate":0,
383
+ # "min_withdraw_amount":10,
384
+ # "min_withdraw_fee":5,
385
+ # "currency":"USDT",
386
+ # "withdraw_status":0,
387
+ # "chain":"OMNI"
388
+ # },
389
+ # {
390
+ # "deposit_status":1,
391
+ # "min_deposit_amount":10,
392
+ # "withdraw_fee_rate":0,
393
+ # "min_withdraw_amount":10,
394
+ # "min_withdraw_fee":3,
395
+ # "currency":"USDT",
396
+ # "withdraw_status":1,
397
+ # "chain":"ERC20"
398
+ # },
399
+ # {
400
+ # "deposit_status":0,
401
+ # "min_deposit_amount":0,
402
+ # "withdraw_fee_rate":0,
403
+ # "min_withdraw_amount":0,
404
+ # "min_withdraw_fee":0,
405
+ # "currency":"DGF13",
406
+ # "withdraw_status":0,
407
+ # "chain":""
408
+ # },
409
+ # ],
410
+ # "code":200
411
+ # }
412
+ #
413
+ data = self.safe_value(response, 'data', [])
414
+ result: dict = {}
415
+ for i in range(0, len(data)):
416
+ currency = data[i]
417
+ id = self.safe_string(currency, 'currency')
418
+ code = self.safe_currency_code(id)
419
+ depositStatus = self.safe_integer(currency, 'deposit_status', 1)
420
+ withdrawStatus = self.safe_integer(currency, 'withdraw_status', 1)
421
+ deposit = depositStatus > 0
422
+ withdraw = withdrawStatus > 0
423
+ active = deposit and withdraw
424
+ feeString = self.safe_string(currency, 'min_withdraw_fee') # withdraw_fee_rate was zero for all currencies, so self was the worst case scenario
425
+ minWithdrawString = self.safe_string(currency, 'min_withdraw_amount')
426
+ minDepositString = self.safe_string(currency, 'min_deposit_amount')
427
+ minDeposit = self.parse_number(minDepositString)
428
+ minWithdraw = self.parse_number(minWithdrawString)
429
+ fee = self.parse_number(feeString)
430
+ # define precision with temporary way
431
+ minFoundPrecision = Precise.string_min(feeString, Precise.string_min(minDepositString, minWithdrawString))
432
+ precision = self.parse_number(minFoundPrecision)
433
+ networkId = self.safe_string(currency, 'chain')
434
+ networkCode = None
435
+ if networkId is not None:
436
+ networkCode = self.network_id_to_code(networkId)
437
+ network: dict = {
438
+ 'info': currency,
439
+ 'id': networkId,
440
+ 'network': networkCode,
441
+ 'active': active,
442
+ 'fee': fee,
443
+ 'precision': precision,
444
+ 'deposit': deposit,
445
+ 'withdraw': withdraw,
446
+ 'limits': {
447
+ 'amount': {
448
+ 'min': None,
449
+ 'max': None,
450
+ },
451
+ 'withdraw': {
452
+ 'min': minWithdraw,
453
+ 'max': None,
454
+ },
455
+ 'deposit': {
456
+ 'min': minDeposit,
457
+ 'max': None,
458
+ },
459
+ },
460
+ }
461
+ if code in result:
462
+ if isinstance(result[code]['info'], list):
463
+ result[code]['info'].append(currency)
464
+ else:
465
+ result[code]['info'] = [result[code]['info'], currency]
466
+ if withdraw:
467
+ result[code]['withdraw'] = True
468
+ result[code]['limits']['withdraw']['min'] = min(result[code]['limits']['withdraw']['min'], minWithdraw)
469
+ if deposit:
470
+ result[code]['deposit'] = True
471
+ result[code]['limits']['deposit']['min'] = min(result[code]['limits']['deposit']['min'], minDeposit)
472
+ if active:
473
+ result[code]['active'] = True
474
+ else:
475
+ result[code] = {
476
+ 'id': id,
477
+ 'code': code,
478
+ 'info': currency,
479
+ 'type': None,
480
+ 'name': None,
481
+ 'active': active,
482
+ 'deposit': deposit,
483
+ 'withdraw': withdraw,
484
+ 'fee': self.parse_number(feeString),
485
+ 'precision': None,
486
+ 'limits': {
487
+ 'amount': {
488
+ 'min': None,
489
+ 'max': None,
490
+ },
491
+ 'withdraw': {
492
+ 'min': minWithdraw,
493
+ 'max': None,
494
+ },
495
+ 'deposit': {
496
+ 'min': minDeposit,
497
+ 'max': None,
498
+ },
499
+ },
500
+ 'networks': {},
501
+ }
502
+ if networkId is not None:
503
+ result[code]['networks'][networkId] = network
504
+ else:
505
+ result[code]['active'] = active
506
+ result[code]['fee'] = self.parse_number(feeString)
507
+ result[code]['deposit'] = deposit
508
+ result[code]['withdraw'] = withdraw
509
+ result[code]['limits'] = {
510
+ 'amount': {
511
+ 'min': None,
512
+ 'max': None,
513
+ },
514
+ 'withdraw': {
515
+ 'min': minWithdraw,
516
+ 'max': None,
517
+ },
518
+ 'deposit': {
519
+ 'min': minDeposit,
520
+ 'max': None,
521
+ },
522
+ }
523
+ result[code]['precision'] = precision if (result[code]['precision'] is None) else max(result[code]['precision'], precision)
524
+ return result
525
+
526
+ async def fetch_markets(self, params={}) -> List[Market]:
527
+ """
528
+ retrieves data on all markets for digifinex
529
+ :param dict [params]: extra parameters specific to the exchange API endpoint
530
+ :returns dict[]: an array of objects representing market data
531
+ """
532
+ options = self.safe_value(self.options, 'fetchMarkets', {})
533
+ method = self.safe_string(options, 'method', 'fetch_markets_v2')
534
+ if method == 'fetch_markets_v2':
535
+ return await self.fetch_markets_v2(params)
536
+ return await self.fetch_markets_v1(params)
537
+
538
+ async def fetch_markets_v2(self, params={}):
539
+ defaultType = self.safe_string(self.options, 'defaultType')
540
+ marginMode, query = self.handle_margin_mode_and_params('fetchMarketsV2', params)
541
+ promisesRaw = []
542
+ if marginMode is not None:
543
+ promisesRaw.append(self.publicSpotGetMarginSymbols(query))
544
+ else:
545
+ promisesRaw.append(self.publicSpotGetTradesSymbols(query))
546
+ promisesRaw.append(self.publicSwapGetPublicInstruments(params))
547
+ promises = await asyncio.gather(*promisesRaw)
548
+ spotMarkets = promises[0]
549
+ swapMarkets = promises[1]
550
+ #
551
+ # spot and margin
552
+ #
553
+ # {
554
+ # "symbol_list":[
555
+ # {
556
+ # "order_types":["LIMIT","MARKET"],
557
+ # "quote_asset":"USDT",
558
+ # "minimum_value":2,
559
+ # "amount_precision":4,
560
+ # "status":"TRADING",
561
+ # "minimum_amount":0.0001,
562
+ # "symbol":"BTC_USDT",
563
+ # "is_allow":1,
564
+ # "zone":"MAIN",
565
+ # "base_asset":"BTC",
566
+ # "price_precision":2
567
+ # }
568
+ # ],
569
+ # "code":0
570
+ # }
571
+ #
572
+ # swap
573
+ #
574
+ # {
575
+ # "code": 0,
576
+ # "data": [
577
+ # {
578
+ # "instrument_id": "BTCUSDTPERP",
579
+ # "type": "REAL",
580
+ # "contract_type": "PERPETUAL",
581
+ # "base_currency": "BTC",
582
+ # "quote_currency": "USDT",
583
+ # "clear_currency": "USDT",
584
+ # "contract_value": "0.001",
585
+ # "contract_value_currency": "BTC",
586
+ # "is_inverse": False,
587
+ # "is_trading": True,
588
+ # "status": "ONLINE",
589
+ # "price_precision": 4,
590
+ # "tick_size": "0.0001",
591
+ # "min_order_amount": 1,
592
+ # "open_max_limits": [
593
+ # {
594
+ # "leverage": "50",
595
+ # "max_limit": "1000000"
596
+ # }
597
+ # ]
598
+ # },
599
+ # ]
600
+ # }
601
+ #
602
+ spotData = self.safe_value(spotMarkets, 'symbol_list', [])
603
+ swapData = self.safe_value(swapMarkets, 'data', [])
604
+ response = self.array_concat(spotData, swapData)
605
+ result = []
606
+ for i in range(0, len(response)):
607
+ market = response[i]
608
+ id = self.safe_string_2(market, 'symbol', 'instrument_id')
609
+ baseId = self.safe_string_2(market, 'base_asset', 'base_currency')
610
+ quoteId = self.safe_string_2(market, 'quote_asset', 'quote_currency')
611
+ settleId = self.safe_string(market, 'clear_currency')
612
+ base = self.safe_currency_code(baseId)
613
+ quote = self.safe_currency_code(quoteId)
614
+ settle = self.safe_currency_code(settleId)
615
+ #
616
+ # The status is documented in the exchange API docs:
617
+ # TRADING, HALT(delisted), BREAK(trading paused)
618
+ # https://docs.digifinex.vip/en-ww/v3/#/public/spot/symbols
619
+ # However, all spot markets actually have status == 'HALT'
620
+ # despite that they appear to be active on the exchange website.
621
+ # Apparently, we can't trust self status.
622
+ # status = self.safe_string(market, 'status')
623
+ # active = (status == 'TRADING')
624
+ #
625
+ isAllowed = self.safe_integer(market, 'is_allow', 1)
626
+ type = 'margin' if (defaultType == 'margin') else 'spot'
627
+ spot = settle is None
628
+ swap = not spot
629
+ margin = True if (marginMode is not None) else None
630
+ symbol = base + '/' + quote
631
+ isInverse = None
632
+ isLinear = None
633
+ if swap:
634
+ type = 'swap'
635
+ symbol = base + '/' + quote + ':' + settle
636
+ isInverse = self.safe_value(market, 'is_inverse')
637
+ isLinear = True if (not isInverse) else False
638
+ isTrading = self.safe_value(market, 'isTrading')
639
+ if isTrading:
640
+ isAllowed = 1
641
+ result.append({
642
+ 'id': id,
643
+ 'symbol': symbol,
644
+ 'base': base,
645
+ 'quote': quote,
646
+ 'settle': settle,
647
+ 'baseId': baseId,
648
+ 'quoteId': quoteId,
649
+ 'settleId': settleId,
650
+ 'type': type,
651
+ 'spot': spot,
652
+ 'margin': margin,
653
+ 'swap': swap,
654
+ 'future': False,
655
+ 'option': False,
656
+ 'active': True if isAllowed else False,
657
+ 'contract': swap,
658
+ 'linear': isLinear,
659
+ 'inverse': isInverse,
660
+ 'contractSize': self.safe_number(market, 'contract_value'),
661
+ 'expiry': None,
662
+ 'expiryDatetime': None,
663
+ 'strike': None,
664
+ 'optionType': None,
665
+ 'precision': {
666
+ 'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'amount_precision'))),
667
+ 'price': self.parse_number(self.parse_precision(self.safe_string(market, 'price_precision'))),
668
+ },
669
+ 'limits': {
670
+ 'leverage': {
671
+ 'min': None,
672
+ 'max': None,
673
+ },
674
+ 'amount': {
675
+ 'min': self.safe_number_2(market, 'minimum_amount', 'min_order_amount'),
676
+ 'max': None,
677
+ },
678
+ 'price': {
679
+ 'min': self.safe_number(market, 'tick_size'),
680
+ 'max': None,
681
+ },
682
+ 'cost': {
683
+ 'min': self.safe_number(market, 'minimum_value'),
684
+ 'max': None,
685
+ },
686
+ },
687
+ 'created': None,
688
+ 'info': market,
689
+ })
690
+ return result
691
+
692
+ async def fetch_markets_v1(self, params={}):
693
+ response = await self.publicSpotGetMarkets(params)
694
+ #
695
+ # {
696
+ # "data": [
697
+ # {
698
+ # "volume_precision":4,
699
+ # "price_precision":2,
700
+ # "market":"btc_usdt",
701
+ # "min_amount":2,
702
+ # "min_volume":0.0001
703
+ # },
704
+ # ],
705
+ # "date":1564507456,
706
+ # "code":0
707
+ # }
708
+ #
709
+ markets = self.safe_value(response, 'data', [])
710
+ result = []
711
+ for i in range(0, len(markets)):
712
+ market = markets[i]
713
+ id = self.safe_string(market, 'market')
714
+ baseId, quoteId = id.split('_')
715
+ base = self.safe_currency_code(baseId)
716
+ quote = self.safe_currency_code(quoteId)
717
+ result.append({
718
+ 'id': id,
719
+ 'symbol': base + '/' + quote,
720
+ 'base': base,
721
+ 'quote': quote,
722
+ 'settle': None,
723
+ 'baseId': baseId,
724
+ 'quoteId': quoteId,
725
+ 'settleId': None,
726
+ 'type': 'spot',
727
+ 'spot': True,
728
+ 'margin': None,
729
+ 'swap': False,
730
+ 'future': False,
731
+ 'option': False,
732
+ 'active': None,
733
+ 'contract': False,
734
+ 'linear': None,
735
+ 'inverse': None,
736
+ 'contractSize': None,
737
+ 'expiry': None,
738
+ 'expiryDatetime': None,
739
+ 'strike': None,
740
+ 'optionType': None,
741
+ 'precision': {
742
+ 'price': self.parse_number(self.parse_precision(self.safe_string(market, 'price_precision'))),
743
+ 'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'volume_precision'))),
744
+ },
745
+ 'limits': {
746
+ 'leverage': {
747
+ 'min': None,
748
+ 'max': None,
749
+ },
750
+ 'amount': {
751
+ 'min': self.safe_number(market, 'min_volume'),
752
+ 'max': None,
753
+ },
754
+ 'price': {
755
+ 'min': None,
756
+ 'max': None,
757
+ },
758
+ 'cost': {
759
+ 'min': self.safe_number(market, 'min_amount'),
760
+ 'max': None,
761
+ },
762
+ },
763
+ 'info': market,
764
+ })
765
+ return result
766
+
767
+ def parse_balance(self, response) -> Balances:
768
+ #
769
+ # spot and margin
770
+ #
771
+ # {
772
+ # "currency": "BTC",
773
+ # "free": 4723846.89208129,
774
+ # "total": 0
775
+ # }
776
+ #
777
+ # swap
778
+ #
779
+ # {
780
+ # "equity": "0",
781
+ # "currency": "BTC",
782
+ # "margin": "0",
783
+ # "frozen_margin": "0",
784
+ # "frozen_money": "0",
785
+ # "margin_ratio": "0",
786
+ # "realized_pnl": "0",
787
+ # "avail_balance": "0",
788
+ # "unrealized_pnl": "0",
789
+ # "time_stamp": 1661487402396
790
+ # }
791
+ #
792
+ result: dict = {'info': response}
793
+ for i in range(0, len(response)):
794
+ balance = response[i]
795
+ currencyId = self.safe_string(balance, 'currency')
796
+ code = self.safe_currency_code(currencyId)
797
+ account = self.account()
798
+ free = self.safe_string_2(balance, 'free', 'avail_balance')
799
+ total = self.safe_string_2(balance, 'total', 'equity')
800
+ account['free'] = free
801
+ account['used'] = Precise.string_sub(total, free)
802
+ account['total'] = total
803
+ result[code] = account
804
+ return self.safe_balance(result)
805
+
806
+ async def fetch_balance(self, params={}) -> Balances:
807
+ """
808
+ query for balance and get the amount of funds available for trading or funds locked in orders
809
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#spot-account-assets
810
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#margin-assets
811
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#accountbalance
812
+ :param dict [params]: extra parameters specific to the exchange API endpoint
813
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
814
+ """
815
+ await self.load_markets()
816
+ marketType = None
817
+ marketType, params = self.handle_market_type_and_params('fetchBalance', None, params)
818
+ marginMode, query = self.handle_margin_mode_and_params('fetchBalance', params)
819
+ response = None
820
+ if marginMode is not None or marketType == 'margin':
821
+ marketType = 'margin'
822
+ response = await self.privateSpotGetMarginAssets(query)
823
+ elif marketType == 'spot':
824
+ response = await self.privateSpotGetSpotAssets(query)
825
+ elif marketType == 'swap':
826
+ response = await self.privateSwapGetAccountBalance(query)
827
+ else:
828
+ raise NotSupported(self.id + ' fetchBalance() not support self market type')
829
+ #
830
+ # spot and margin
831
+ #
832
+ # {
833
+ # "code": 0,
834
+ # "list": [
835
+ # {
836
+ # "currency": "BTC",
837
+ # "free": 4723846.89208129,
838
+ # "total": 0
839
+ # },
840
+ # ...
841
+ # ]
842
+ # }
843
+ #
844
+ # swap
845
+ #
846
+ # {
847
+ # "code": 0,
848
+ # "data": [
849
+ # {
850
+ # "equity": "0",
851
+ # "currency": "BTC",
852
+ # "margin": "0",
853
+ # "frozen_margin": "0",
854
+ # "frozen_money": "0",
855
+ # "margin_ratio": "0",
856
+ # "realized_pnl": "0",
857
+ # "avail_balance": "0",
858
+ # "unrealized_pnl": "0",
859
+ # "time_stamp": 1661487402396
860
+ # },
861
+ # ...
862
+ # ]
863
+ # }
864
+ #
865
+ balanceRequest = 'data' if (marketType == 'swap') else 'list'
866
+ balances = self.safe_value(response, balanceRequest, [])
867
+ return self.parse_balance(balances)
868
+
869
+ async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
870
+ """
871
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
872
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#get-orderbook
873
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#orderbook
874
+ :param str symbol: unified symbol of the market to fetch the order book for
875
+ :param int [limit]: the maximum amount of order book entries to return
876
+ :param dict [params]: extra parameters specific to the exchange API endpoint
877
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
878
+ """
879
+ await self.load_markets()
880
+ market = self.market(symbol)
881
+ marketType, query = self.handle_market_type_and_params('fetchOrderBook', market, params)
882
+ request: dict = {}
883
+ if limit is not None:
884
+ request['limit'] = limit
885
+ response = None
886
+ if marketType == 'swap':
887
+ request['instrument_id'] = market['id']
888
+ response = await self.publicSwapGetPublicDepth(self.extend(request, query))
889
+ else:
890
+ request['symbol'] = market['id']
891
+ response = await self.publicSpotGetOrderBook(self.extend(request, query))
892
+ #
893
+ # spot
894
+ #
895
+ # {
896
+ # "bids": [
897
+ # [9605.77,0.0016],
898
+ # [9605.46,0.0003],
899
+ # [9602.04,0.0127],
900
+ # ],
901
+ # "asks": [
902
+ # [9627.22,0.025803],
903
+ # [9627.12,0.168543],
904
+ # [9626.52,0.0011529],
905
+ # ],
906
+ # "date":1564509499,
907
+ # "code":0
908
+ # }
909
+ #
910
+ # swap
911
+ #
912
+ # {
913
+ # "code": 0,
914
+ # "data": {
915
+ # "instrument_id": "BTCUSDTPERP",
916
+ # "timestamp": 1667975290425,
917
+ # "asks": [
918
+ # ["18384.7",3492],
919
+ # ["18402.7",5000],
920
+ # ["18406.7",5000],
921
+ # ],
922
+ # "bids": [
923
+ # ["18366.2",4395],
924
+ # ["18364.3",3070],
925
+ # ["18359.4",5000],
926
+ # ]
927
+ # }
928
+ # }
929
+ #
930
+ timestamp = None
931
+ orderBook = None
932
+ if marketType == 'swap':
933
+ orderBook = self.safe_value(response, 'data', {})
934
+ timestamp = self.safe_integer(orderBook, 'timestamp')
935
+ else:
936
+ orderBook = response
937
+ timestamp = self.safe_timestamp(response, 'date')
938
+ return self.parse_order_book(orderBook, market['symbol'], timestamp)
939
+
940
+ async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
941
+ """
942
+ fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
943
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#ticker-price
944
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#tickers
945
+ :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
946
+ :param dict [params]: extra parameters specific to the exchange API endpoint
947
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
948
+ """
949
+ await self.load_markets()
950
+ symbols = self.market_symbols(symbols)
951
+ first = self.safe_string(symbols, 0)
952
+ market = None
953
+ if first is not None:
954
+ market = self.market(first)
955
+ type = None
956
+ type, params = self.handle_market_type_and_params('fetchTickers', market, params)
957
+ request: dict = {}
958
+ response = None
959
+ if type == 'swap':
960
+ response = await self.publicSwapGetPublicTickers(self.extend(request, params))
961
+ else:
962
+ response = await self.publicSpotGetTicker(self.extend(request, params))
963
+ #
964
+ # spot
965
+ #
966
+ # {
967
+ # "ticker": [{
968
+ # "vol": 40717.4461,
969
+ # "change": -1.91,
970
+ # "base_vol": 392447999.65374,
971
+ # "sell": 9592.23,
972
+ # "last": 9592.22,
973
+ # "symbol": "btc_usdt",
974
+ # "low": 9476.24,
975
+ # "buy": 9592.03,
976
+ # "high": 9793.87
977
+ # }],
978
+ # "date": 1589874294,
979
+ # "code": 0
980
+ # }
981
+ #
982
+ # swap
983
+ #
984
+ # {
985
+ # "code": 0,
986
+ # "data": [
987
+ # {
988
+ # "instrument_id": "SUSHIUSDTPERP",
989
+ # "index_price": "1.1297",
990
+ # "mark_price": "1.1289",
991
+ # "max_buy_price": "1.1856",
992
+ # "min_sell_price": "1.0726",
993
+ # "best_bid": "1.1278",
994
+ # "best_bid_size": "500",
995
+ # "best_ask": "1.1302",
996
+ # "best_ask_size": "471",
997
+ # "high_24h": "1.2064",
998
+ # "open_24h": "1.1938",
999
+ # "low_24h": "1.1239",
1000
+ # "last": "1.1302",
1001
+ # "last_qty": "29",
1002
+ # "volume_24h": "4946163",
1003
+ # "price_change_percent": "-0.053275255486681085",
1004
+ # "open_interest": "-",
1005
+ # "timestamp": 1663222782100
1006
+ # },
1007
+ # ...
1008
+ # ]
1009
+ # }
1010
+ #
1011
+ result: dict = {}
1012
+ tickers = self.safe_value_2(response, 'ticker', 'data', [])
1013
+ date = self.safe_integer(response, 'date')
1014
+ for i in range(0, len(tickers)):
1015
+ rawTicker = self.extend({
1016
+ 'date': date,
1017
+ }, tickers[i])
1018
+ ticker = self.parse_ticker(rawTicker)
1019
+ symbol = ticker['symbol']
1020
+ result[symbol] = ticker
1021
+ return self.filter_by_array_tickers(result, 'symbol', symbols)
1022
+
1023
+ async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
1024
+ """
1025
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1026
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#ticker-price
1027
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#ticker
1028
+ :param str symbol: unified symbol of the market to fetch the ticker for
1029
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1030
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1031
+ """
1032
+ await self.load_markets()
1033
+ market = self.market(symbol)
1034
+ request: dict = {}
1035
+ response = None
1036
+ if market['swap']:
1037
+ request['instrument_id'] = market['id']
1038
+ response = await self.publicSwapGetPublicTicker(self.extend(request, params))
1039
+ else:
1040
+ request['symbol'] = market['id']
1041
+ response = await self.publicSpotGetTicker(self.extend(request, params))
1042
+ #
1043
+ # spot
1044
+ #
1045
+ # {
1046
+ # "ticker": [{
1047
+ # "vol": 40717.4461,
1048
+ # "change": -1.91,
1049
+ # "base_vol": 392447999.65374,
1050
+ # "sell": 9592.23,
1051
+ # "last": 9592.22,
1052
+ # "symbol": "btc_usdt",
1053
+ # "low": 9476.24,
1054
+ # "buy": 9592.03,
1055
+ # "high": 9793.87
1056
+ # }],
1057
+ # "date": 1589874294,
1058
+ # "code": 0
1059
+ # }
1060
+ #
1061
+ # swap
1062
+ #
1063
+ # {
1064
+ # "code": 0,
1065
+ # "data": {
1066
+ # "instrument_id": "BTCUSDTPERP",
1067
+ # "index_price": "20141.9967",
1068
+ # "mark_price": "20139.3404",
1069
+ # "max_buy_price": "21146.4838",
1070
+ # "min_sell_price": "19132.2725",
1071
+ # "best_bid": "20140.0998",
1072
+ # "best_bid_size": "3116",
1073
+ # "best_ask": "20140.0999",
1074
+ # "best_ask_size": "9004",
1075
+ # "high_24h": "20410.6496",
1076
+ # "open_24h": "20308.6998",
1077
+ # "low_24h": "19600",
1078
+ # "last": "20140.0999",
1079
+ # "last_qty": "2",
1080
+ # "volume_24h": "49382816",
1081
+ # "price_change_percent": "-0.008301855936636448",
1082
+ # "open_interest": "-",
1083
+ # "timestamp": 1663221614998
1084
+ # }
1085
+ # }
1086
+ #
1087
+ date = self.safe_integer(response, 'date')
1088
+ tickers = self.safe_value(response, 'ticker', [])
1089
+ data = self.safe_value(response, 'data', {})
1090
+ firstTicker = self.safe_value(tickers, 0, {})
1091
+ result = None
1092
+ if market['swap']:
1093
+ result = data
1094
+ else:
1095
+ result = self.extend({'date': date}, firstTicker)
1096
+ return self.parse_ticker(result, market)
1097
+
1098
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
1099
+ #
1100
+ # spot: fetchTicker, fetchTickers
1101
+ #
1102
+ # {
1103
+ # "last":0.021957,
1104
+ # "symbol": "btc_usdt",
1105
+ # "base_vol":2249.3521732227,
1106
+ # "change":-0.6,
1107
+ # "vol":102443.5111,
1108
+ # "sell":0.021978,
1109
+ # "low":0.021791,
1110
+ # "buy":0.021946,
1111
+ # "high":0.022266,
1112
+ # "date"1564518452, # injected from fetchTicker/fetchTickers
1113
+ # }
1114
+ #
1115
+ # swap: fetchTicker, fetchTickers
1116
+ #
1117
+ # {
1118
+ # "instrument_id": "BTCUSDTPERP",
1119
+ # "index_price": "20141.9967",
1120
+ # "mark_price": "20139.3404",
1121
+ # "max_buy_price": "21146.4838",
1122
+ # "min_sell_price": "19132.2725",
1123
+ # "best_bid": "20140.0998",
1124
+ # "best_bid_size": "3116",
1125
+ # "best_ask": "20140.0999",
1126
+ # "best_ask_size": "9004",
1127
+ # "high_24h": "20410.6496",
1128
+ # "open_24h": "20308.6998",
1129
+ # "low_24h": "19600",
1130
+ # "last": "20140.0999",
1131
+ # "last_qty": "2",
1132
+ # "volume_24h": "49382816",
1133
+ # "price_change_percent": "-0.008301855936636448",
1134
+ # "open_interest": "-",
1135
+ # "timestamp": 1663221614998
1136
+ # }
1137
+ #
1138
+ indexPrice = self.safe_number(ticker, 'index_price')
1139
+ marketType = 'contract' if (indexPrice is not None) else 'spot'
1140
+ marketId = self.safe_string_upper_2(ticker, 'symbol', 'instrument_id')
1141
+ symbol = self.safe_symbol(marketId, market, None, marketType)
1142
+ market = self.safe_market(marketId, market, None, marketType)
1143
+ timestamp = self.safe_timestamp(ticker, 'date')
1144
+ if market['swap']:
1145
+ timestamp = self.safe_integer(ticker, 'timestamp')
1146
+ last = self.safe_string(ticker, 'last')
1147
+ return self.safe_ticker({
1148
+ 'symbol': symbol,
1149
+ 'timestamp': timestamp,
1150
+ 'datetime': self.iso8601(timestamp),
1151
+ 'high': self.safe_string_2(ticker, 'high', 'high_24h'),
1152
+ 'low': self.safe_string_2(ticker, 'low', 'low_24h'),
1153
+ 'bid': self.safe_string_2(ticker, 'buy', 'best_bid'),
1154
+ 'bidVolume': self.safe_string(ticker, 'best_bid_size'),
1155
+ 'ask': self.safe_string_2(ticker, 'sell', 'best_ask'),
1156
+ 'askVolume': self.safe_string(ticker, 'best_ask_size'),
1157
+ 'vwap': None,
1158
+ 'open': self.safe_string(ticker, 'open_24h'),
1159
+ 'close': last,
1160
+ 'last': last,
1161
+ 'previousClose': None,
1162
+ 'change': None,
1163
+ 'percentage': self.safe_string_2(ticker, 'change', 'price_change_percent'),
1164
+ 'average': None,
1165
+ 'baseVolume': self.safe_string_2(ticker, 'vol', 'volume_24h'),
1166
+ 'quoteVolume': self.safe_string(ticker, 'base_vol'),
1167
+ 'info': ticker,
1168
+ }, market)
1169
+
1170
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
1171
+ #
1172
+ # spot: fetchTrades
1173
+ #
1174
+ # {
1175
+ # "date":1564520003,
1176
+ # "id":1596149203,
1177
+ # "amount":0.7073,
1178
+ # "type":"buy",
1179
+ # "price":0.02193,
1180
+ # }
1181
+ #
1182
+ # swap: fetchTrades
1183
+ #
1184
+ # {
1185
+ # "instrument_id": "BTCUSDTPERP",
1186
+ # "trade_id": "1595190773677035521",
1187
+ # "direction": "4",
1188
+ # "volume": "4",
1189
+ # "price": "16188.3",
1190
+ # "trade_time": 1669158092314
1191
+ # }
1192
+ #
1193
+ # spot: fetchMyTrades
1194
+ #
1195
+ # {
1196
+ # "symbol": "BTC_USDT",
1197
+ # "order_id": "6707cbdcda0edfaa7f4ab509e4cbf966",
1198
+ # "id": 28457,
1199
+ # "price": 0.1,
1200
+ # "amount": 0,
1201
+ # "fee": 0.096,
1202
+ # "fee_currency": "USDT",
1203
+ # "timestamp": 1499865549,
1204
+ # "side": "buy", # or "side": "sell_market"
1205
+ # "is_maker": True
1206
+ # }
1207
+ #
1208
+ # swap: fetchMyTrades
1209
+ #
1210
+ # {
1211
+ # "trade_id": "1590136768424841218",
1212
+ # "instrument_id": "BTCUSDTPERP",
1213
+ # "order_id": "1590136768156405760",
1214
+ # "type": 1,
1215
+ # "order_type": 8,
1216
+ # "price": "18514.5",
1217
+ # "size": "1",
1218
+ # "fee": "0.00925725",
1219
+ # "close_profit": "0",
1220
+ # "leverage": "20",
1221
+ # "trade_type": 0,
1222
+ # "match_role": 1,
1223
+ # "trade_time": 1667953123562
1224
+ # }
1225
+ #
1226
+ id = self.safe_string_2(trade, 'id', 'trade_id')
1227
+ orderId = self.safe_string(trade, 'order_id')
1228
+ priceString = self.safe_string(trade, 'price')
1229
+ amountString = self.safe_string_n(trade, ['amount', 'volume', 'size'])
1230
+ marketId = self.safe_string_upper_2(trade, 'symbol', 'instrument_id')
1231
+ symbol = self.safe_symbol(marketId, market)
1232
+ if market is None:
1233
+ market = self.safe_market(marketId)
1234
+ timestamp = self.safe_timestamp_2(trade, 'date', 'timestamp')
1235
+ side = self.safe_string_2(trade, 'type', 'side')
1236
+ type = None
1237
+ takerOrMaker = None
1238
+ if market['type'] == 'swap':
1239
+ timestamp = self.safe_integer(trade, 'trade_time')
1240
+ orderType = self.safe_string(trade, 'order_type')
1241
+ tradeRole = self.safe_string(trade, 'match_role')
1242
+ direction = self.safe_string(trade, 'direction')
1243
+ if orderType is not None:
1244
+ type = 'limit' if (orderType == '0') else None
1245
+ if tradeRole == '1':
1246
+ takerOrMaker = 'taker'
1247
+ elif tradeRole == '2':
1248
+ takerOrMaker = 'maker'
1249
+ else:
1250
+ takerOrMaker = None
1251
+ if (side == '1') or (direction == '1'):
1252
+ # side = 'open long'
1253
+ side = 'buy'
1254
+ elif (side == '2') or (direction == '2'):
1255
+ # side = 'open short'
1256
+ side = 'sell'
1257
+ elif (side == '3') or (direction == '3'):
1258
+ # side = 'close long'
1259
+ side = 'sell'
1260
+ elif (side == '4') or (direction == '4'):
1261
+ # side = 'close short'
1262
+ side = 'buy'
1263
+ else:
1264
+ parts = side.split('_')
1265
+ side = self.safe_string(parts, 0)
1266
+ type = self.safe_string(parts, 1)
1267
+ if type is None:
1268
+ type = 'limit'
1269
+ isMaker = self.safe_value(trade, 'is_maker')
1270
+ takerOrMaker = 'maker' if isMaker else 'taker'
1271
+ fee = None
1272
+ feeCostString = self.safe_string(trade, 'fee')
1273
+ if feeCostString is not None:
1274
+ feeCurrencyId = self.safe_string(trade, 'fee_currency')
1275
+ feeCurrencyCode = None
1276
+ if feeCurrencyId is not None:
1277
+ feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
1278
+ fee = {
1279
+ 'cost': feeCostString,
1280
+ 'currency': feeCurrencyCode,
1281
+ }
1282
+ return self.safe_trade({
1283
+ 'id': id,
1284
+ 'info': trade,
1285
+ 'timestamp': timestamp,
1286
+ 'datetime': self.iso8601(timestamp),
1287
+ 'symbol': symbol,
1288
+ 'type': type,
1289
+ 'order': orderId,
1290
+ 'side': side,
1291
+ 'price': priceString,
1292
+ 'amount': amountString,
1293
+ 'cost': None,
1294
+ 'takerOrMaker': takerOrMaker,
1295
+ 'fee': fee,
1296
+ }, market)
1297
+
1298
+ async def fetch_time(self, params={}):
1299
+ """
1300
+ fetches the current integer timestamp in milliseconds from the exchange server
1301
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1302
+ :returns int: the current integer timestamp in milliseconds from the exchange server
1303
+ """
1304
+ response = await self.publicSpotGetTime(params)
1305
+ #
1306
+ # {
1307
+ # "server_time": 1589873762,
1308
+ # "code": 0
1309
+ # }
1310
+ #
1311
+ return self.safe_timestamp(response, 'server_time')
1312
+
1313
+ async def fetch_status(self, params={}):
1314
+ """
1315
+ the latest known information on the availability of the exchange API
1316
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1317
+ :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
1318
+ """
1319
+ response = await self.publicSpotGetPing(params)
1320
+ #
1321
+ # {
1322
+ # "msg": "pong",
1323
+ # "code": 0
1324
+ # }
1325
+ #
1326
+ code = self.safe_integer(response, 'code')
1327
+ status = 'ok' if (code == 0) else 'maintenance'
1328
+ return {
1329
+ 'status': status,
1330
+ 'updated': None,
1331
+ 'eta': None,
1332
+ 'url': None,
1333
+ 'info': response,
1334
+ }
1335
+
1336
+ async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1337
+ """
1338
+ get the list of most recent trades for a particular symbol
1339
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#get-recent-trades
1340
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#recenttrades
1341
+ :param str symbol: unified symbol of the market to fetch trades for
1342
+ :param int [since]: timestamp in ms of the earliest trade to fetch
1343
+ :param int [limit]: the maximum amount of trades to fetch
1344
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1345
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
1346
+ """
1347
+ await self.load_markets()
1348
+ market = self.market(symbol)
1349
+ request: dict = {}
1350
+ if limit is not None:
1351
+ request['limit'] = min(limit, 100) if market['swap'] else limit
1352
+ response = None
1353
+ if market['swap']:
1354
+ request['instrument_id'] = market['id']
1355
+ response = await self.publicSwapGetPublicTrades(self.extend(request, params))
1356
+ else:
1357
+ request['symbol'] = market['id']
1358
+ response = await self.publicSpotGetTrades(self.extend(request, params))
1359
+ #
1360
+ # spot
1361
+ #
1362
+ # {
1363
+ # "data":[
1364
+ # {
1365
+ # "date":1564520003,
1366
+ # "id":1596149203,
1367
+ # "amount":0.7073,
1368
+ # "type":"buy",
1369
+ # "price":0.02193,
1370
+ # },
1371
+ # {
1372
+ # "date":1564520002,
1373
+ # "id":1596149165,
1374
+ # "amount":0.3232,
1375
+ # "type":"sell",
1376
+ # "price":0.021927,
1377
+ # },
1378
+ # ],
1379
+ # "code": 0,
1380
+ # "date": 1564520003,
1381
+ # }
1382
+ #
1383
+ # swap
1384
+ #
1385
+ # {
1386
+ # "code": 0,
1387
+ # "data": [
1388
+ # {
1389
+ # "instrument_id": "BTCUSDTPERP",
1390
+ # "trade_id": "1595190773677035521",
1391
+ # "direction": "4",
1392
+ # "volume": "4",
1393
+ # "price": "16188.3",
1394
+ # "trade_time": 1669158092314
1395
+ # },
1396
+ # ...
1397
+ # ]
1398
+ # }
1399
+ #
1400
+ data = self.safe_list(response, 'data', [])
1401
+ return self.parse_trades(data, market, since, limit)
1402
+
1403
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
1404
+ #
1405
+ # [
1406
+ # 1556712900,
1407
+ # 2205.899,
1408
+ # 0.029967,
1409
+ # 0.02997,
1410
+ # 0.029871,
1411
+ # 0.029927
1412
+ # ]
1413
+ #
1414
+ if market['swap']:
1415
+ return [
1416
+ self.safe_integer(ohlcv, 0),
1417
+ self.safe_number(ohlcv, 1), # open
1418
+ self.safe_number(ohlcv, 2), # high
1419
+ self.safe_number(ohlcv, 3), # low
1420
+ self.safe_number(ohlcv, 4), # close
1421
+ self.safe_number(ohlcv, 5), # volume
1422
+ ]
1423
+ else:
1424
+ return [
1425
+ self.safe_timestamp(ohlcv, 0),
1426
+ self.safe_number(ohlcv, 5), # open
1427
+ self.safe_number(ohlcv, 3), # high
1428
+ self.safe_number(ohlcv, 4), # low
1429
+ self.safe_number(ohlcv, 2), # close
1430
+ self.safe_number(ohlcv, 1), # volume
1431
+ ]
1432
+
1433
+ async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
1434
+ """
1435
+ fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1436
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#get-candles-data
1437
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#recentcandle
1438
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
1439
+ :param str timeframe: the length of time each candle represents
1440
+ :param int [since]: timestamp in ms of the earliest candle to fetch
1441
+ :param int [limit]: the maximum amount of candles to fetch
1442
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1443
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
1444
+ """
1445
+ await self.load_markets()
1446
+ market = self.market(symbol)
1447
+ request: dict = {}
1448
+ response = None
1449
+ if market['swap']:
1450
+ request['instrument_id'] = market['id']
1451
+ request['granularity'] = timeframe
1452
+ if limit is not None:
1453
+ request['limit'] = min(limit, 100)
1454
+ response = await self.publicSwapGetPublicCandles(self.extend(request, params))
1455
+ else:
1456
+ request['symbol'] = market['id']
1457
+ request['period'] = self.safe_string(self.timeframes, timeframe, timeframe)
1458
+ if since is not None:
1459
+ startTime = self.parse_to_int(since / 1000)
1460
+ request['start_time'] = startTime
1461
+ if limit is not None:
1462
+ duration = self.parse_timeframe(timeframe)
1463
+ request['end_time'] = self.sum(startTime, limit * duration)
1464
+ elif limit is not None:
1465
+ endTime = self.seconds()
1466
+ duration = self.parse_timeframe(timeframe)
1467
+ auxLimit = limit # in c# -limit is mutating the arg
1468
+ request['start_time'] = self.sum(endTime, -auxLimit * duration)
1469
+ response = await self.publicSpotGetKline(self.extend(request, params))
1470
+ #
1471
+ # spot
1472
+ #
1473
+ # {
1474
+ # "code":0,
1475
+ # "data":[
1476
+ # [1556712900,2205.899,0.029967,0.02997,0.029871,0.029927],
1477
+ # [1556713800,1912.9174,0.029992,0.030014,0.029955,0.02996],
1478
+ # [1556714700,1556.4795,0.029974,0.030019,0.029969,0.02999],
1479
+ # ]
1480
+ # }
1481
+ #
1482
+ # swap
1483
+ #
1484
+ # {
1485
+ # "code": 0,
1486
+ # "data": {
1487
+ # "instrument_id": "BTCUSDTPERP",
1488
+ # "granularity": "1m",
1489
+ # "candles": [
1490
+ # [1588089660000,"6900","6900","6900","6900","0","0"],
1491
+ # [1588089720000,"6900","6900","6900","6900","0","0"],
1492
+ # [1588089780000,"6900","6900","6900","6900","0","0"],
1493
+ # ]
1494
+ # }
1495
+ # }
1496
+ #
1497
+ candles = None
1498
+ if market['swap']:
1499
+ data = self.safe_value(response, 'data', {})
1500
+ candles = self.safe_value(data, 'candles', [])
1501
+ else:
1502
+ candles = self.safe_value(response, 'data', [])
1503
+ return self.parse_ohlcvs(candles, market, timeframe, since, limit)
1504
+
1505
+ async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1506
+ """
1507
+ create a trade order
1508
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#create-new-order
1509
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#orderplace
1510
+ :param str symbol: unified symbol of the market to create an order in
1511
+ :param str type: 'market' or 'limit'
1512
+ :param str side: 'buy' or 'sell'
1513
+ :param float amount: how much you want to trade in units of the base currency, spot market orders use the quote currency, swap requires the number of contracts
1514
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1515
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1516
+ :param str [params.timeInForce]: "GTC", "IOC", "FOK", or "PO"
1517
+ :param bool [params.postOnly]: True or False
1518
+ :param bool [params.reduceOnly]: True or False
1519
+ :param str [params.marginMode]: 'cross' or 'isolated', for spot margin trading
1520
+ :param float [params.cost]: *spot market buy only* the quote quantity that can be used alternative for the amount
1521
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1522
+ """
1523
+ await self.load_markets()
1524
+ market = self.market(symbol)
1525
+ marginResult = self.handle_margin_mode_and_params('createOrder', params)
1526
+ marginMode = marginResult[0]
1527
+ request = self.create_order_request(symbol, type, side, amount, price, params)
1528
+ response = None
1529
+ if market['swap']:
1530
+ response = await self.privateSwapPostTradeOrderPlace(request)
1531
+ else:
1532
+ if marginMode is not None:
1533
+ response = await self.privateSpotPostMarginOrderNew(request)
1534
+ else:
1535
+ response = await self.privateSpotPostSpotOrderNew(request)
1536
+ #
1537
+ # spot and margin
1538
+ #
1539
+ # {
1540
+ # "code": 0,
1541
+ # "order_id": "198361cecdc65f9c8c9bb2fa68faec40"
1542
+ # }
1543
+ #
1544
+ # swap
1545
+ #
1546
+ # {
1547
+ # "code": 0,
1548
+ # "data": "1590873693003714560"
1549
+ # }
1550
+ #
1551
+ order = self.parse_order(response, market)
1552
+ order['symbol'] = market['symbol']
1553
+ order['type'] = type
1554
+ order['side'] = side
1555
+ order['amount'] = amount
1556
+ order['price'] = price
1557
+ return order
1558
+
1559
+ async def create_orders(self, orders: List[OrderRequest], params={}):
1560
+ """
1561
+ create a list of trade orders(all orders should be of the same symbol)
1562
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#create-multiple-order
1563
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#batchorder
1564
+ :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
1565
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1566
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1567
+ """
1568
+ await self.load_markets()
1569
+ ordersRequests = []
1570
+ symbol = None
1571
+ marginMode = None
1572
+ for i in range(0, len(orders)):
1573
+ rawOrder = orders[i]
1574
+ marketId = self.safe_string(rawOrder, 'symbol')
1575
+ if symbol is None:
1576
+ symbol = marketId
1577
+ else:
1578
+ if symbol != marketId:
1579
+ raise BadRequest(self.id + ' createOrders() requires all orders to have the same symbol')
1580
+ type = self.safe_string(rawOrder, 'type')
1581
+ side = self.safe_string(rawOrder, 'side')
1582
+ amount = self.safe_value(rawOrder, 'amount')
1583
+ price = self.safe_value(rawOrder, 'price')
1584
+ orderParams = self.safe_value(rawOrder, 'params', {})
1585
+ marginResult = self.handle_margin_mode_and_params('createOrders', orderParams)
1586
+ currentMarginMode = marginResult[0]
1587
+ if currentMarginMode is not None:
1588
+ if marginMode is None:
1589
+ marginMode = currentMarginMode
1590
+ else:
1591
+ if marginMode != currentMarginMode:
1592
+ raise BadRequest(self.id + ' createOrders() requires all orders to have the same margin mode(isolated or cross)')
1593
+ orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams)
1594
+ ordersRequests.append(orderRequest)
1595
+ market = self.market(symbol)
1596
+ request: dict = {}
1597
+ response = None
1598
+ if market['swap']:
1599
+ response = await self.privateSwapPostTradeBatchOrder(ordersRequests)
1600
+ else:
1601
+ request['market'] = 'margin' if (marginMode is not None) else 'spot'
1602
+ request['symbol'] = market['id']
1603
+ request['list'] = self.json(ordersRequests)
1604
+ response = await self.privateSpotPostMarketOrderBatchNew(request)
1605
+ #
1606
+ # spot
1607
+ #
1608
+ # {
1609
+ # "code": 0,
1610
+ # "order_ids": [
1611
+ # "064290fbe2d26e7b28d7e6c0a5cf70a5",
1612
+ # "24c8f9b73d81e4d9d8d7e3280281c258"
1613
+ # ]
1614
+ # }
1615
+ #
1616
+ # swap
1617
+ #
1618
+ # {
1619
+ # "code": 0,
1620
+ # "data": [
1621
+ # "1720297963537829888",
1622
+ # "1720297963537829889"
1623
+ # ]
1624
+ # }
1625
+ #
1626
+ data = []
1627
+ if market['swap']:
1628
+ data = self.safe_value(response, 'data', [])
1629
+ else:
1630
+ data = self.safe_value(response, 'order_ids', [])
1631
+ result = []
1632
+ for i in range(0, len(orders)):
1633
+ rawOrder = orders[i]
1634
+ individualOrder: dict = {}
1635
+ individualOrder['order_id'] = data[i]
1636
+ individualOrder['instrument_id'] = market['id']
1637
+ individualOrder['amount'] = self.safe_number(rawOrder, 'amount')
1638
+ individualOrder['price'] = self.safe_number(rawOrder, 'price')
1639
+ result.append(individualOrder)
1640
+ return self.parse_orders(result, market)
1641
+
1642
+ def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1643
+ """
1644
+ * @ignore
1645
+ helper function to build request
1646
+ :param str symbol: unified symbol of the market to create an order in
1647
+ :param str type: 'market' or 'limit'
1648
+ :param str side: 'buy' or 'sell'
1649
+ :param float amount: how much you want to trade in units of the base currency, spot market orders use the quote currency, swap requires the number of contracts
1650
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1651
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1652
+ :returns dict: request to be sent to the exchange
1653
+ """
1654
+ market = self.market(symbol)
1655
+ marketType = None
1656
+ marginMode = None
1657
+ marketType, params = self.handle_market_type_and_params('createOrderRequest', market, params)
1658
+ marginMode, params = self.handle_margin_mode_and_params('createOrderRequest', params)
1659
+ if marginMode is not None:
1660
+ marketType = 'margin'
1661
+ request: dict = {}
1662
+ swap = (marketType == 'swap')
1663
+ isMarketOrder = (type == 'market')
1664
+ isLimitOrder = (type == 'limit')
1665
+ marketIdRequest = 'instrument_id' if swap else 'symbol'
1666
+ request[marketIdRequest] = market['id']
1667
+ postOnly = self.is_post_only(isMarketOrder, False, params)
1668
+ postOnlyParsed = None
1669
+ if swap:
1670
+ reduceOnly = self.safe_bool(params, 'reduceOnly', False)
1671
+ timeInForce = self.safe_string(params, 'timeInForce')
1672
+ orderType = None
1673
+ if side == 'buy':
1674
+ requestType = 4 if (reduceOnly) else 1
1675
+ request['type'] = requestType
1676
+ else:
1677
+ requestType = 3 if (reduceOnly) else 2
1678
+ request['type'] = requestType
1679
+ if isLimitOrder:
1680
+ orderType = 0
1681
+ if timeInForce == 'FOK':
1682
+ orderType = 15 if isMarketOrder else 9
1683
+ elif timeInForce == 'IOC':
1684
+ orderType = 13 if isMarketOrder else 4
1685
+ elif (timeInForce == 'GTC') or (isMarketOrder):
1686
+ orderType = 14
1687
+ elif timeInForce == 'PO':
1688
+ postOnly = True
1689
+ if price is not None:
1690
+ request['price'] = self.price_to_precision(symbol, price)
1691
+ request['order_type'] = orderType
1692
+ request['size'] = amount # swap orders require the amount to be the number of contracts
1693
+ params = self.omit(params, ['reduceOnly', 'timeInForce'])
1694
+ else:
1695
+ postOnlyParsed = 1 if (postOnly is True) else 2
1696
+ request['market'] = marketType
1697
+ suffix = ''
1698
+ if type == 'market':
1699
+ suffix = '_market'
1700
+ else:
1701
+ request['price'] = self.price_to_precision(symbol, price)
1702
+ request['type'] = side + suffix
1703
+ # limit orders require the amount in the base currency, market orders require the amount in the quote currency
1704
+ quantity = None
1705
+ createMarketBuyOrderRequiresPrice = True
1706
+ createMarketBuyOrderRequiresPrice, params = self.handle_option_and_params(params, 'createOrderRequest', 'createMarketBuyOrderRequiresPrice', True)
1707
+ if isMarketOrder and (side == 'buy'):
1708
+ cost = self.safe_number(params, 'cost')
1709
+ params = self.omit(params, 'cost')
1710
+ if cost is not None:
1711
+ quantity = self.cost_to_precision(symbol, cost)
1712
+ elif createMarketBuyOrderRequiresPrice:
1713
+ if price is None:
1714
+ raise InvalidOrder(self.id + ' createOrder() requires a price argument for market buy orders on spot markets to calculate the total amount to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to False and pass the cost to spend in the amount argument')
1715
+ else:
1716
+ amountString = self.number_to_string(amount)
1717
+ priceString = self.number_to_string(price)
1718
+ costRequest = self.parse_number(Precise.string_mul(amountString, priceString))
1719
+ quantity = self.cost_to_precision(symbol, costRequest)
1720
+ else:
1721
+ quantity = self.cost_to_precision(symbol, amount)
1722
+ else:
1723
+ quantity = self.amount_to_precision(symbol, amount)
1724
+ request['amount'] = quantity
1725
+ if postOnly:
1726
+ if postOnlyParsed:
1727
+ request['post_only'] = postOnlyParsed
1728
+ else:
1729
+ request['post_only'] = postOnly
1730
+ params = self.omit(params, ['postOnly'])
1731
+ return self.extend(request, params)
1732
+
1733
+ async def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
1734
+ """
1735
+ create a market buy order by providing the symbol and cost
1736
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#create-new-order
1737
+ :param str symbol: unified symbol of the market to create an order in
1738
+ :param float cost: how much you want to trade in units of the quote currency
1739
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1740
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1741
+ """
1742
+ await self.load_markets()
1743
+ market = self.market(symbol)
1744
+ if not market['spot']:
1745
+ raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports spot orders only')
1746
+ params['createMarketBuyOrderRequiresPrice'] = False
1747
+ return await self.create_order(symbol, 'market', 'buy', cost, None, params)
1748
+
1749
+ async def cancel_order(self, id: str, symbol: Str = None, params={}):
1750
+ """
1751
+ cancels an open order
1752
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#cancel-order
1753
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#cancelorder
1754
+ :param str id: order id
1755
+ :param str symbol: not used by digifinex cancelOrder()
1756
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1757
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1758
+ """
1759
+ await self.load_markets()
1760
+ market = None
1761
+ if symbol is not None:
1762
+ market = self.market(symbol)
1763
+ id = str(id)
1764
+ marketType = None
1765
+ marketType, params = self.handle_market_type_and_params('cancelOrder', market, params)
1766
+ request: dict = {
1767
+ 'order_id': id,
1768
+ }
1769
+ if marketType == 'swap':
1770
+ if symbol is None:
1771
+ raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
1772
+ request['instrument_id'] = market['id']
1773
+ else:
1774
+ request['market'] = marketType
1775
+ marginMode, query = self.handle_margin_mode_and_params('cancelOrder', params)
1776
+ response = None
1777
+ if marginMode is not None or marketType == 'margin':
1778
+ marketType = 'margin'
1779
+ response = await self.privateSpotPostMarginOrderCancel(self.extend(request, query))
1780
+ elif marketType == 'spot':
1781
+ response = await self.privateSpotPostSpotOrderCancel(self.extend(request, query))
1782
+ elif marketType == 'swap':
1783
+ response = await self.privateSwapPostTradeCancelOrder(self.extend(request, query))
1784
+ else:
1785
+ raise NotSupported(self.id + ' cancelOrder() not support self market type')
1786
+ #
1787
+ # spot and margin
1788
+ #
1789
+ # {
1790
+ # "code": 0,
1791
+ # "success": [
1792
+ # "198361cecdc65f9c8c9bb2fa68faec40",
1793
+ # "3fb0d98e51c18954f10d439a9cf57de0"
1794
+ # ],
1795
+ # "error": [
1796
+ # "78a7104e3c65cc0c5a212a53e76d0205"
1797
+ # ]
1798
+ # }
1799
+ #
1800
+ # swap
1801
+ #
1802
+ # {
1803
+ # "code": 0,
1804
+ # "data": "1590923061186531328"
1805
+ # }
1806
+ #
1807
+ if (marketType == 'spot') or (marketType == 'margin'):
1808
+ canceledOrders = self.safe_value(response, 'success', [])
1809
+ numCanceledOrders = len(canceledOrders)
1810
+ if numCanceledOrders != 1:
1811
+ raise OrderNotFound(self.id + ' cancelOrder() ' + id + ' not found')
1812
+ return response
1813
+
1814
+ async def cancel_orders(self, ids, symbol: Str = None, params={}):
1815
+ """
1816
+ cancel multiple orders
1817
+ :param str[] ids: order ids
1818
+ :param str symbol: not used by digifinex cancelOrders()
1819
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1820
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1821
+ """
1822
+ await self.load_markets()
1823
+ defaultType = self.safe_string(self.options, 'defaultType', 'spot')
1824
+ orderType = self.safe_string(params, 'type', defaultType)
1825
+ params = self.omit(params, 'type')
1826
+ request: dict = {
1827
+ 'market': orderType,
1828
+ 'order_id': ','.join(ids),
1829
+ }
1830
+ response = await self.privateSpotPostSpotOrderCancel(self.extend(request, params))
1831
+ #
1832
+ # {
1833
+ # "code": 0,
1834
+ # "success": [
1835
+ # "198361cecdc65f9c8c9bb2fa68faec40",
1836
+ # "3fb0d98e51c18954f10d439a9cf57de0"
1837
+ # ],
1838
+ # "error": [
1839
+ # "78a7104e3c65cc0c5a212a53e76d0205"
1840
+ # ]
1841
+ # }
1842
+ #
1843
+ canceledOrders = self.safe_value(response, 'success', [])
1844
+ numCanceledOrders = len(canceledOrders)
1845
+ if numCanceledOrders < 1:
1846
+ raise OrderNotFound(self.id + ' cancelOrders() error')
1847
+ return response
1848
+
1849
+ def parse_order_status(self, status: Str):
1850
+ statuses: dict = {
1851
+ '0': 'open',
1852
+ '1': 'open', # partially filled
1853
+ '2': 'closed',
1854
+ '3': 'canceled',
1855
+ '4': 'canceled', # partially filled and canceled
1856
+ }
1857
+ return self.safe_string(statuses, status, status)
1858
+
1859
+ def parse_order(self, order: dict, market: Market = None) -> Order:
1860
+ #
1861
+ # spot: createOrder
1862
+ #
1863
+ # {
1864
+ # "code": 0,
1865
+ # "order_id": "198361cecdc65f9c8c9bb2fa68faec40"
1866
+ # }
1867
+ #
1868
+ # swap: createOrder
1869
+ #
1870
+ # {
1871
+ # "code": 0,
1872
+ # "data": "1590873693003714560"
1873
+ # }
1874
+ #
1875
+ # spot and swap: createOrders
1876
+ #
1877
+ # {
1878
+ # "order_id": "d64d92a5e0a120f792f385485bc3d95b",
1879
+ # "instrument_id": "BTC_USDT",
1880
+ # "amount": 0.0001,
1881
+ # "price": 27000
1882
+ # }
1883
+ #
1884
+ # spot: fetchOrder, fetchOpenOrders, fetchOrders
1885
+ #
1886
+ # {
1887
+ # "symbol": "BTC_USDT",
1888
+ # "order_id": "dd3164b333a4afa9d5730bb87f6db8b3",
1889
+ # "created_date": 1562303547,
1890
+ # "finished_date": 0,
1891
+ # "price": 0.1,
1892
+ # "amount": 1,
1893
+ # "cash_amount": 1,
1894
+ # "executed_amount": 0,
1895
+ # "avg_price": 0,
1896
+ # "status": 1,
1897
+ # "type": "buy",
1898
+ # "kind": "margin"
1899
+ # }
1900
+ #
1901
+ # swap: fetchOrder, fetchOpenOrders, fetchOrders
1902
+ #
1903
+ # {
1904
+ # "order_id": "1590898207657824256",
1905
+ # "instrument_id": "BTCUSDTPERP",
1906
+ # "margin_mode": "crossed",
1907
+ # "contract_val": "0.001",
1908
+ # "type": 1,
1909
+ # "order_type": 0,
1910
+ # "price": "14000",
1911
+ # "size": "6",
1912
+ # "filled_qty": "0",
1913
+ # "price_avg": "0",
1914
+ # "fee": "0",
1915
+ # "state": 0,
1916
+ # "leverage": "20",
1917
+ # "turnover": "0",
1918
+ # "has_stop": 0,
1919
+ # "insert_time": 1668134664828,
1920
+ # "time_stamp": 1668134664828
1921
+ # }
1922
+ #
1923
+ timestamp = None
1924
+ lastTradeTimestamp = None
1925
+ timeInForce = None
1926
+ type = None
1927
+ side = self.safe_string(order, 'type')
1928
+ marketId = self.safe_string_2(order, 'symbol', 'instrument_id')
1929
+ symbol = self.safe_symbol(marketId, market)
1930
+ market = self.market(symbol)
1931
+ if market['type'] == 'swap':
1932
+ orderType = self.safe_integer(order, 'order_type')
1933
+ if orderType is not None:
1934
+ if (orderType == 9) or (orderType == 10) or (orderType == 11) or (orderType == 12) or (orderType == 15):
1935
+ timeInForce = 'FOK'
1936
+ elif (orderType == 1) or (orderType == 2) or (orderType == 3) or (orderType == 4) or (orderType == 13):
1937
+ timeInForce = 'IOC'
1938
+ elif (orderType == 6) or (orderType == 7) or (orderType == 8) or (orderType == 14):
1939
+ timeInForce = 'GTC'
1940
+ if (orderType == 0) or (orderType == 1) or (orderType == 4) or (orderType == 5) or (orderType == 9) or (orderType == 10):
1941
+ type = 'limit'
1942
+ else:
1943
+ type = 'market'
1944
+ if side == '1':
1945
+ side = 'open long'
1946
+ elif side == '2':
1947
+ side = 'open short'
1948
+ elif side == '3':
1949
+ side = 'close long'
1950
+ elif side == '4':
1951
+ side = 'close short'
1952
+ timestamp = self.safe_integer(order, 'insert_time')
1953
+ lastTradeTimestamp = self.safe_integer(order, 'time_stamp')
1954
+ else:
1955
+ timestamp = self.safe_timestamp(order, 'created_date')
1956
+ lastTradeTimestamp = self.safe_timestamp(order, 'finished_date')
1957
+ if side is not None:
1958
+ parts = side.split('_')
1959
+ numParts = len(parts)
1960
+ if numParts > 1:
1961
+ side = parts[0]
1962
+ type = parts[1]
1963
+ else:
1964
+ type = 'limit'
1965
+ return self.safe_order({
1966
+ 'info': order,
1967
+ 'id': self.safe_string_2(order, 'order_id', 'data'),
1968
+ 'clientOrderId': None,
1969
+ 'timestamp': timestamp,
1970
+ 'datetime': self.iso8601(timestamp),
1971
+ 'lastTradeTimestamp': lastTradeTimestamp,
1972
+ 'symbol': symbol,
1973
+ 'type': type,
1974
+ 'timeInForce': timeInForce,
1975
+ 'postOnly': None,
1976
+ 'side': side,
1977
+ 'price': self.safe_number(order, 'price'),
1978
+ 'stopPrice': None,
1979
+ 'triggerPrice': None,
1980
+ 'amount': self.safe_number_2(order, 'amount', 'size'),
1981
+ 'filled': self.safe_number_2(order, 'executed_amount', 'filled_qty'),
1982
+ 'remaining': None,
1983
+ 'cost': None,
1984
+ 'average': self.safe_number_2(order, 'avg_price', 'price_avg'),
1985
+ 'status': self.parse_order_status(self.safe_string_2(order, 'status', 'state')),
1986
+ 'fee': {
1987
+ 'cost': self.safe_number(order, 'fee'),
1988
+ },
1989
+ 'trades': None,
1990
+ }, market)
1991
+
1992
+ async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1993
+ """
1994
+ fetch all unfilled currently open orders
1995
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#current-active-orders
1996
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#openorder
1997
+ :param str symbol: unified market symbol
1998
+ :param int [since]: the earliest time in ms to fetch open orders for
1999
+ :param int [limit]: the maximum number of open orders structures to retrieve
2000
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2001
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2002
+ """
2003
+ await self.load_markets()
2004
+ market = None
2005
+ if symbol is not None:
2006
+ market = self.market(symbol)
2007
+ marketType = None
2008
+ marketType, params = self.handle_market_type_and_params('fetchOpenOrders', market, params)
2009
+ marginMode, query = self.handle_margin_mode_and_params('fetchOpenOrders', params)
2010
+ request: dict = {}
2011
+ swap = (marketType == 'swap')
2012
+ if swap:
2013
+ if since is not None:
2014
+ request['start_timestamp'] = since
2015
+ if limit is not None:
2016
+ request['limit'] = limit
2017
+ else:
2018
+ request['market'] = marketType
2019
+ if market is not None:
2020
+ marketIdRequest = 'instrument_id' if swap else 'symbol'
2021
+ request[marketIdRequest] = market['id']
2022
+ response = None
2023
+ if marginMode is not None or marketType == 'margin':
2024
+ marketType = 'margin'
2025
+ response = await self.privateSpotGetMarginOrderCurrent(self.extend(request, query))
2026
+ elif marketType == 'spot':
2027
+ response = await self.privateSpotGetSpotOrderCurrent(self.extend(request, query))
2028
+ elif marketType == 'swap':
2029
+ response = await self.privateSwapGetTradeOpenOrders(self.extend(request, query))
2030
+ else:
2031
+ raise NotSupported(self.id + ' fetchOpenOrders() not support self market type')
2032
+ #
2033
+ # spot and margin
2034
+ #
2035
+ # {
2036
+ # "code": 0,
2037
+ # "data": [
2038
+ # {
2039
+ # "symbol": "BTC_USDT",
2040
+ # "order_id": "dd3164b333a4afa9d5730bb87f6db8b3",
2041
+ # "created_date": 1562303547,
2042
+ # "finished_date": 0,
2043
+ # "price": 0.1,
2044
+ # "amount": 1,
2045
+ # "cash_amount": 1,
2046
+ # "executed_amount": 0,
2047
+ # "avg_price": 0,
2048
+ # "status": 1,
2049
+ # "type": "buy",
2050
+ # "kind": "margin"
2051
+ # }
2052
+ # ]
2053
+ # }
2054
+ #
2055
+ # swap
2056
+ #
2057
+ # {
2058
+ # "code": 0,
2059
+ # "data": [
2060
+ # {
2061
+ # "order_id": "1590898207657824256",
2062
+ # "instrument_id": "BTCUSDTPERP",
2063
+ # "margin_mode": "crossed",
2064
+ # "contract_val": "0.001",
2065
+ # "type": 1,
2066
+ # "order_type": 0,
2067
+ # "price": "14000",
2068
+ # "size": "6",
2069
+ # "filled_qty": "0",
2070
+ # "price_avg": "0",
2071
+ # "fee": "0",
2072
+ # "state": 0,
2073
+ # "leverage": "20",
2074
+ # "turnover": "0",
2075
+ # "has_stop": 0,
2076
+ # "insert_time": 1668134664828,
2077
+ # "time_stamp": 1668134664828
2078
+ # },
2079
+ # ...
2080
+ # ]
2081
+ # }
2082
+ #
2083
+ data = self.safe_list(response, 'data', [])
2084
+ return self.parse_orders(data, market, since, limit)
2085
+
2086
+ async def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2087
+ """
2088
+ fetches information on multiple orders made by the user
2089
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#get-all-orders-including-history-orders
2090
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#historyorder
2091
+ :param str symbol: unified market symbol of the market orders were made in
2092
+ :param int [since]: the earliest time in ms to fetch orders for
2093
+ :param int [limit]: the maximum number of order structures to retrieve
2094
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2095
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2096
+ """
2097
+ await self.load_markets()
2098
+ market = None
2099
+ if symbol is not None:
2100
+ market = self.market(symbol)
2101
+ marketType = None
2102
+ marketType, params = self.handle_market_type_and_params('fetchOrders', market, params)
2103
+ marginMode, query = self.handle_margin_mode_and_params('fetchOrders', params)
2104
+ request: dict = {}
2105
+ if marketType == 'swap':
2106
+ if since is not None:
2107
+ request['start_timestamp'] = since
2108
+ else:
2109
+ request['market'] = marketType
2110
+ if since is not None:
2111
+ request['start_time'] = self.parse_to_int(since / 1000) # default 3 days from now, max 30 days
2112
+ if market is not None:
2113
+ marketIdRequest = 'instrument_id' if (marketType == 'swap') else 'symbol'
2114
+ request[marketIdRequest] = market['id']
2115
+ if limit is not None:
2116
+ request['limit'] = limit
2117
+ response = None
2118
+ if marginMode is not None or marketType == 'margin':
2119
+ marketType = 'margin'
2120
+ response = await self.privateSpotGetMarginOrderHistory(self.extend(request, query))
2121
+ elif marketType == 'spot':
2122
+ response = await self.privateSpotGetSpotOrderHistory(self.extend(request, query))
2123
+ elif marketType == 'swap':
2124
+ response = await self.privateSwapGetTradeHistoryOrders(self.extend(request, query))
2125
+ else:
2126
+ raise NotSupported(self.id + ' fetchOrders() not support self market type')
2127
+ #
2128
+ # spot and margin
2129
+ #
2130
+ # {
2131
+ # "code": 0,
2132
+ # "data": [
2133
+ # {
2134
+ # "symbol": "BTC_USDT",
2135
+ # "order_id": "dd3164b333a4afa9d5730bb87f6db8b3",
2136
+ # "created_date": 1562303547,
2137
+ # "finished_date": 0,
2138
+ # "price": 0.1,
2139
+ # "amount": 1,
2140
+ # "cash_amount": 1,
2141
+ # "executed_amount": 0,
2142
+ # "avg_price": 0,
2143
+ # "status": 1,
2144
+ # "type": "buy",
2145
+ # "kind": "margin"
2146
+ # }
2147
+ # ]
2148
+ # }
2149
+ #
2150
+ # swap
2151
+ #
2152
+ # {
2153
+ # "code": 0,
2154
+ # "data": [
2155
+ # {
2156
+ # "order_id": "1590136768156405760",
2157
+ # "instrument_id": "BTCUSDTPERP",
2158
+ # "margin_mode": "crossed",
2159
+ # "contract_val": "0.001",
2160
+ # "type": 1,
2161
+ # "order_type": 8,
2162
+ # "price": "18660.2",
2163
+ # "size": "1",
2164
+ # "filled_qty": "1",
2165
+ # "price_avg": "18514.5",
2166
+ # "fee": "0.00925725",
2167
+ # "state": 2,
2168
+ # "leverage": "20",
2169
+ # "turnover": "18.5145",
2170
+ # "has_stop": 0,
2171
+ # "insert_time": 1667953123526,
2172
+ # "time_stamp": 1667953123596
2173
+ # },
2174
+ # ...
2175
+ # ]
2176
+ # }
2177
+ #
2178
+ data = self.safe_list(response, 'data', [])
2179
+ return self.parse_orders(data, market, since, limit)
2180
+
2181
+ async def fetch_order(self, id: str, symbol: Str = None, params={}):
2182
+ """
2183
+ fetches information on an order made by the user
2184
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#get-order-status
2185
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#orderinfo
2186
+ :param str id: order id
2187
+ :param str symbol: unified symbol of the market the order was made in
2188
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2189
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2190
+ """
2191
+ await self.load_markets()
2192
+ market = None
2193
+ if symbol is not None:
2194
+ market = self.market(symbol)
2195
+ marketType = None
2196
+ marketType, params = self.handle_market_type_and_params('fetchOrder', market, params)
2197
+ marginMode, query = self.handle_margin_mode_and_params('fetchOrder', params)
2198
+ request: dict = {
2199
+ 'order_id': id,
2200
+ }
2201
+ if marketType == 'swap':
2202
+ if market is not None:
2203
+ request['instrument_id'] = market['id']
2204
+ else:
2205
+ request['market'] = marketType
2206
+ response = None
2207
+ if (marginMode is not None) or (marketType == 'margin'):
2208
+ marketType = 'margin'
2209
+ response = await self.privateSpotGetMarginOrder(self.extend(request, query))
2210
+ elif marketType == 'spot':
2211
+ response = await self.privateSpotGetSpotOrder(self.extend(request, query))
2212
+ elif marketType == 'swap':
2213
+ response = await self.privateSwapGetTradeOrderInfo(self.extend(request, query))
2214
+ else:
2215
+ raise NotSupported(self.id + ' fetchOrder() not support self market type')
2216
+ #
2217
+ # spot and margin
2218
+ #
2219
+ # {
2220
+ # "code": 0,
2221
+ # "data": [
2222
+ # {
2223
+ # "symbol": "BTC_USDT",
2224
+ # "order_id": "dd3164b333a4afa9d5730bb87f6db8b3",
2225
+ # "created_date": 1562303547,
2226
+ # "finished_date": 0,
2227
+ # "price": 0.1,
2228
+ # "amount": 1,
2229
+ # "cash_amount": 1,
2230
+ # "executed_amount": 0,
2231
+ # "avg_price": 0,
2232
+ # "status": 1,
2233
+ # "type": "buy",
2234
+ # "kind": "margin"
2235
+ # }
2236
+ # ]
2237
+ # }
2238
+ #
2239
+ # swap
2240
+ #
2241
+ # {
2242
+ # "code": 0,
2243
+ # "data": {
2244
+ # "order_id": "1590923061186531328",
2245
+ # "instrument_id": "ETHUSDTPERP",
2246
+ # "margin_mode": "crossed",
2247
+ # "contract_val": "0.01",
2248
+ # "type": 1,
2249
+ # "order_type": 0,
2250
+ # "price": "900",
2251
+ # "size": "6",
2252
+ # "filled_qty": "0",
2253
+ # "price_avg": "0",
2254
+ # "fee": "0",
2255
+ # "state": 0,
2256
+ # "leverage": "20",
2257
+ # "turnover": "0",
2258
+ # "has_stop": 0,
2259
+ # "insert_time": 1668140590372,
2260
+ # "time_stamp": 1668140590372
2261
+ # }
2262
+ # }
2263
+ #
2264
+ data = self.safe_value(response, 'data')
2265
+ order = data if (marketType == 'swap') else self.safe_value(data, 0)
2266
+ if order is None:
2267
+ raise OrderNotFound(self.id + ' fetchOrder() order ' + str(id) + ' not found')
2268
+ return self.parse_order(order, market)
2269
+
2270
+ async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2271
+ """
2272
+ fetch all trades made by the user
2273
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#customer-39-s-trades
2274
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#historytrade
2275
+ :param str symbol: unified market symbol
2276
+ :param int [since]: the earliest time in ms to fetch trades for
2277
+ :param int [limit]: the maximum number of trades structures to retrieve
2278
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2279
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
2280
+ """
2281
+ await self.load_markets()
2282
+ market = None
2283
+ request: dict = {}
2284
+ if symbol is not None:
2285
+ market = self.market(symbol)
2286
+ marketType = None
2287
+ marketType, params = self.handle_market_type_and_params('fetchMyTrades', market, params)
2288
+ marginMode, query = self.handle_margin_mode_and_params('fetchMyTrades', params)
2289
+ if marketType == 'swap':
2290
+ if since is not None:
2291
+ request['start_timestamp'] = since
2292
+ else:
2293
+ request['market'] = marketType
2294
+ if since is not None:
2295
+ request['start_time'] = self.parse_to_int(since / 1000) # default 3 days from now, max 30 days
2296
+ marketIdRequest = 'instrument_id' if (marketType == 'swap') else 'symbol'
2297
+ if symbol is not None:
2298
+ request[marketIdRequest] = market['id']
2299
+ if limit is not None:
2300
+ request['limit'] = limit
2301
+ response = None
2302
+ if marginMode is not None or marketType == 'margin':
2303
+ marketType = 'margin'
2304
+ response = await self.privateSpotGetMarginMytrades(self.extend(request, query))
2305
+ elif marketType == 'spot':
2306
+ response = await self.privateSpotGetSpotMytrades(self.extend(request, query))
2307
+ elif marketType == 'swap':
2308
+ response = await self.privateSwapGetTradeHistoryTrades(self.extend(request, query))
2309
+ else:
2310
+ raise NotSupported(self.id + ' fetchMyTrades() not support self market type')
2311
+ #
2312
+ # spot and margin
2313
+ #
2314
+ # {
2315
+ # "list":[
2316
+ # {
2317
+ # "timestamp":1639506068,
2318
+ # "is_maker":false,
2319
+ # "id":"8975951332",
2320
+ # "amount":31.83,
2321
+ # "side":"sell_market",
2322
+ # "symbol":"DOGE_USDT",
2323
+ # "fee_currency":"USDT",
2324
+ # "fee":0.01163774826
2325
+ # ,"order_id":"32b169792f4a7a19e5907dc29fc123d4",
2326
+ # "price":0.182811
2327
+ # }
2328
+ # ],
2329
+ # "code": 0
2330
+ # }
2331
+ #
2332
+ # swap
2333
+ #
2334
+ # {
2335
+ # "code": 0,
2336
+ # "data": [
2337
+ # {
2338
+ # "trade_id": "1590136768424841218",
2339
+ # "instrument_id": "BTCUSDTPERP",
2340
+ # "order_id": "1590136768156405760",
2341
+ # "type": 1,
2342
+ # "order_type": 8,
2343
+ # "price": "18514.5",
2344
+ # "size": "1",
2345
+ # "fee": "0.00925725",
2346
+ # "close_profit": "0",
2347
+ # "leverage": "20",
2348
+ # "trade_type": 0,
2349
+ # "match_role": 1,
2350
+ # "trade_time": 1667953123562
2351
+ # },
2352
+ # ...
2353
+ # ]
2354
+ # }
2355
+ #
2356
+ responseRequest = 'data' if (marketType == 'swap') else 'list'
2357
+ data = self.safe_list(response, responseRequest, [])
2358
+ return self.parse_trades(data, market, since, limit)
2359
+
2360
+ def parse_ledger_entry_type(self, type):
2361
+ types: dict = {}
2362
+ return self.safe_string(types, type, type)
2363
+
2364
+ def parse_ledger_entry(self, item: dict, currency: Currency = None):
2365
+ #
2366
+ # spot and margin
2367
+ #
2368
+ # {
2369
+ # "currency_mark": "BTC",
2370
+ # "type": 100234,
2371
+ # "num": -10,
2372
+ # "balance": 0.1,
2373
+ # "time": 1546272000
2374
+ # }
2375
+ #
2376
+ # swap
2377
+ #
2378
+ # {
2379
+ # "currency": "USDT",
2380
+ # "finance_type": 17,
2381
+ # "change": "-3.01",
2382
+ # "timestamp": 1650809432000
2383
+ # }
2384
+ #
2385
+ type = self.parse_ledger_entry_type(self.safe_string_2(item, 'type', 'finance_type'))
2386
+ code = self.safe_currency_code(self.safe_string_2(item, 'currency_mark', 'currency'), currency)
2387
+ amount = self.safe_number_2(item, 'num', 'change')
2388
+ after = self.safe_number(item, 'balance')
2389
+ timestamp = self.safe_timestamp(item, 'time')
2390
+ if timestamp is None:
2391
+ timestamp = self.safe_integer(item, 'timestamp')
2392
+ return {
2393
+ 'info': item,
2394
+ 'id': None,
2395
+ 'direction': None,
2396
+ 'account': None,
2397
+ 'referenceId': None,
2398
+ 'referenceAccount': None,
2399
+ 'type': type,
2400
+ 'currency': code,
2401
+ 'amount': amount,
2402
+ 'before': None,
2403
+ 'after': after,
2404
+ 'status': None,
2405
+ 'timestamp': timestamp,
2406
+ 'datetime': self.iso8601(timestamp),
2407
+ 'fee': None,
2408
+ }
2409
+
2410
+ async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
2411
+ """
2412
+ fetch the history of changes, actions done by the user or operations that altered balance of the user
2413
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#spot-margin-otc-financial-logs
2414
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#bills
2415
+ :param str code: unified currency code, default is None
2416
+ :param int [since]: timestamp in ms of the earliest ledger entry, default is None
2417
+ :param int [limit]: max number of ledger entrys to return, default is None
2418
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2419
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
2420
+ """
2421
+ await self.load_markets()
2422
+ request: dict = {}
2423
+ marketType = None
2424
+ marketType, params = self.handle_market_type_and_params('fetchLedger', None, params)
2425
+ marginMode, query = self.handle_margin_mode_and_params('fetchLedger', params)
2426
+ if marketType == 'swap':
2427
+ if since is not None:
2428
+ request['start_timestamp'] = since
2429
+ else:
2430
+ request['market'] = marketType
2431
+ if since is not None:
2432
+ request['start_time'] = self.parse_to_int(since / 1000) # default 3 days from now, max 30 days
2433
+ currencyIdRequest = 'currency' if (marketType == 'swap') else 'currency_mark'
2434
+ currency = None
2435
+ if code is not None:
2436
+ currency = self.currency(code)
2437
+ request[currencyIdRequest] = currency['id']
2438
+ if limit is not None:
2439
+ request['limit'] = limit
2440
+ response = None
2441
+ if marginMode is not None or marketType == 'margin':
2442
+ marketType = 'margin'
2443
+ response = await self.privateSpotGetMarginFinancelog(self.extend(request, query))
2444
+ elif marketType == 'spot':
2445
+ response = await self.privateSpotGetSpotFinancelog(self.extend(request, query))
2446
+ elif marketType == 'swap':
2447
+ response = await self.privateSwapGetAccountFinanceRecord(self.extend(request, query))
2448
+ else:
2449
+ raise NotSupported(self.id + ' fetchLedger() not support self market type')
2450
+ #
2451
+ # spot and margin
2452
+ #
2453
+ # {
2454
+ # "code": 0,
2455
+ # "data": {
2456
+ # "total": 521,
2457
+ # "finance": [
2458
+ # {
2459
+ # "currency_mark": "BTC",
2460
+ # "type": 100234,
2461
+ # "num": 28457,
2462
+ # "balance": 0.1,
2463
+ # "time": 1546272000
2464
+ # }
2465
+ # ]
2466
+ # }
2467
+ # }
2468
+ #
2469
+ # swap
2470
+ #
2471
+ # {
2472
+ # "code": 0,
2473
+ # "data": [
2474
+ # {
2475
+ # "currency": "USDT",
2476
+ # "finance_type": 17,
2477
+ # "change": "3.01",
2478
+ # "timestamp": 1650809432000
2479
+ # },
2480
+ # ]
2481
+ # }
2482
+ #
2483
+ ledger = None
2484
+ if marketType == 'swap':
2485
+ ledger = self.safe_value(response, 'data', [])
2486
+ else:
2487
+ data = self.safe_value(response, 'data', {})
2488
+ ledger = self.safe_value(data, 'finance', [])
2489
+ return self.parse_ledger(ledger, currency, since, limit)
2490
+
2491
+ def parse_deposit_address(self, depositAddress, currency: Currency = None):
2492
+ #
2493
+ # {
2494
+ # "addressTag":"",
2495
+ # "address":"0xf1104d9f8624f89775a3e9d480fc0e75a8ef4373",
2496
+ # "currency":"USDT",
2497
+ # "chain":"ERC20"
2498
+ # }
2499
+ #
2500
+ address = self.safe_string(depositAddress, 'address')
2501
+ tag = self.safe_string(depositAddress, 'addressTag')
2502
+ currencyId = self.safe_string_upper(depositAddress, 'currency')
2503
+ code = self.safe_currency_code(currencyId)
2504
+ return {
2505
+ 'info': depositAddress,
2506
+ 'currency': code,
2507
+ 'address': address,
2508
+ 'tag': tag,
2509
+ 'network': None,
2510
+ }
2511
+
2512
+ async def fetch_deposit_address(self, code: str, params={}):
2513
+ """
2514
+ fetch the deposit address for a currency associated with self account
2515
+ :param str code: unified currency code
2516
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2517
+ :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
2518
+ """
2519
+ await self.load_markets()
2520
+ currency = self.currency(code)
2521
+ request: dict = {
2522
+ 'currency': currency['id'],
2523
+ }
2524
+ response = await self.privateSpotGetDepositAddress(self.extend(request, params))
2525
+ #
2526
+ # {
2527
+ # "data":[
2528
+ # {
2529
+ # "addressTag":"",
2530
+ # "address":"0xf1104d9f8624f89775a3e9d480fc0e75a8ef4373",
2531
+ # "currency":"USDT",
2532
+ # "chain":"ERC20"
2533
+ # }
2534
+ # ],
2535
+ # "code":200
2536
+ # }
2537
+ #
2538
+ data = self.safe_value(response, 'data', [])
2539
+ addresses = self.parse_deposit_addresses(data, [currency['code']])
2540
+ address = self.safe_value(addresses, code)
2541
+ if address is None:
2542
+ raise InvalidAddress(self.id + ' fetchDepositAddress() did not return an address for ' + code + ' - create the deposit address in the user settings on the exchange website first.')
2543
+ return address
2544
+
2545
+ async def fetch_transactions_by_type(self, type, code: Str = None, since: Int = None, limit: Int = None, params={}):
2546
+ await self.load_markets()
2547
+ currency = None
2548
+ request: dict = {
2549
+ # 'currency': currency['id'],
2550
+ # 'from': 'fromId', # When direct is' prev ', from is 1, returning from old to new ascending, when direct is' next ', from is the ID of the most recent record, returned from the old descending order
2551
+ # 'size': 100, # default 100, max 500
2552
+ # 'direct': 'prev', # "prev" ascending, "next" descending
2553
+ }
2554
+ if code is not None:
2555
+ currency = self.currency(code)
2556
+ request['currency'] = currency['id']
2557
+ if limit is not None:
2558
+ request['size'] = min(500, limit)
2559
+ response = None
2560
+ if type == 'deposit':
2561
+ response = await self.privateSpotGetDepositHistory(self.extend(request, params))
2562
+ else:
2563
+ response = await self.privateSpotGetWithdrawHistory(self.extend(request, params))
2564
+ #
2565
+ # {
2566
+ # "code": 200,
2567
+ # "data": [
2568
+ # {
2569
+ # "id": 1171,
2570
+ # "currency": "xrp",
2571
+ # "hash": "ed03094b84eafbe4bc16e7ef766ee959885ee5bcb265872baaa9c64e1cf86c2b",
2572
+ # "chain": "",
2573
+ # "amount": 7.457467,
2574
+ # "address": "rae93V8d2mdoUQHwBDBdM4NHCMehRJAsbm",
2575
+ # "memo": "100040",
2576
+ # "fee": 0,
2577
+ # "state": "safe",
2578
+ # "created_date": "2020-04-20 11:23:00",
2579
+ # "finished_date": "2020-04-20 13:23:00"
2580
+ # },
2581
+ # ]
2582
+ # }
2583
+ #
2584
+ data = self.safe_list(response, 'data', [])
2585
+ return self.parse_transactions(data, currency, since, limit, {'type': type})
2586
+
2587
+ async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2588
+ """
2589
+ fetch all deposits made to an account
2590
+ :param str code: unified currency code
2591
+ :param int [since]: the earliest time in ms to fetch deposits for
2592
+ :param int [limit]: the maximum number of deposits structures to retrieve
2593
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2594
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2595
+ """
2596
+ return await self.fetch_transactions_by_type('deposit', code, since, limit, params)
2597
+
2598
+ async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2599
+ """
2600
+ fetch all withdrawals made from an account
2601
+ :param str code: unified currency code
2602
+ :param int [since]: the earliest time in ms to fetch withdrawals for
2603
+ :param int [limit]: the maximum number of withdrawals structures to retrieve
2604
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2605
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2606
+ """
2607
+ return await self.fetch_transactions_by_type('withdrawal', code, since, limit, params)
2608
+
2609
+ def parse_transaction_status(self, status: Str):
2610
+ # deposit state includes: 1(in deposit), 2(to be confirmed), 3(successfully deposited), 4(stopped)
2611
+ # withdrawal state includes: 1(application in progress), 2(to be confirmed), 3(completed), 4(rejected)
2612
+ statuses: dict = {
2613
+ '1': 'pending', # in Progress
2614
+ '2': 'pending', # to be confirmed
2615
+ '3': 'ok', # Completed
2616
+ '4': 'failed', # Rejected
2617
+ }
2618
+ return self.safe_string(statuses, status, status)
2619
+
2620
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
2621
+ #
2622
+ # withdraw
2623
+ #
2624
+ # {
2625
+ # "code": 200,
2626
+ # "withdraw_id": 700
2627
+ # }
2628
+ #
2629
+ # fetchDeposits, fetchWithdrawals
2630
+ #
2631
+ # {
2632
+ # "id": 1171,
2633
+ # "currency": "xrp",
2634
+ # "hash": "ed03094b84eafbe4bc16e7ef766ee959885ee5bcb265872baaa9c64e1cf86c2b",
2635
+ # "chain": "",
2636
+ # "amount": 7.457467,
2637
+ # "address": "rae93V8d2mdoUQHwBDBdM4NHCMehRJAsbm",
2638
+ # "memo": "100040",
2639
+ # "fee": 0,
2640
+ # "state": "safe",
2641
+ # "created_date": "2020-04-20 11:23:00",
2642
+ # "finished_date": "2020-04-20 13:23:00"
2643
+ # }
2644
+ #
2645
+ id = self.safe_string_2(transaction, 'id', 'withdraw_id')
2646
+ address = self.safe_string(transaction, 'address')
2647
+ tag = self.safe_string(transaction, 'memo')
2648
+ txid = self.safe_string(transaction, 'hash')
2649
+ currencyId = self.safe_string_upper(transaction, 'currency')
2650
+ code = self.safe_currency_code(currencyId, currency)
2651
+ timestamp = self.parse8601(self.safe_string(transaction, 'created_date'))
2652
+ updated = self.parse8601(self.safe_string(transaction, 'finished_date'))
2653
+ status = self.parse_transaction_status(self.safe_string(transaction, 'state'))
2654
+ amount = self.safe_number(transaction, 'amount')
2655
+ feeCost = self.safe_number(transaction, 'fee')
2656
+ fee = None
2657
+ if feeCost is not None:
2658
+ fee = {'currency': code, 'cost': feeCost}
2659
+ network = self.safe_string(transaction, 'chain')
2660
+ return {
2661
+ 'info': transaction,
2662
+ 'id': id,
2663
+ 'txid': txid,
2664
+ 'timestamp': timestamp,
2665
+ 'datetime': self.iso8601(timestamp),
2666
+ 'network': network,
2667
+ 'address': address,
2668
+ 'addressTo': address,
2669
+ 'addressFrom': None,
2670
+ 'tag': tag,
2671
+ 'tagTo': tag,
2672
+ 'tagFrom': None,
2673
+ 'type': None,
2674
+ 'amount': amount,
2675
+ 'currency': code,
2676
+ 'status': status,
2677
+ 'updated': updated,
2678
+ 'internal': None,
2679
+ 'comment': None,
2680
+ 'fee': fee,
2681
+ }
2682
+
2683
+ def parse_transfer_status(self, status: Str) -> Str:
2684
+ statuses: dict = {
2685
+ '0': 'ok',
2686
+ }
2687
+ return self.safe_string(statuses, status, status)
2688
+
2689
+ def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
2690
+ #
2691
+ # transfer
2692
+ #
2693
+ # {
2694
+ # "code": 0
2695
+ # }
2696
+ #
2697
+ # fetchTransfers
2698
+ #
2699
+ # {
2700
+ # "transfer_id": 130524,
2701
+ # "type": 1,
2702
+ # "currency": "USDT",
2703
+ # "amount": "24",
2704
+ # "timestamp": 1666505659000
2705
+ # }
2706
+ #
2707
+ fromAccount = None
2708
+ toAccount = None
2709
+ type = self.safe_integer(transfer, 'type')
2710
+ if type == 1:
2711
+ fromAccount = 'spot'
2712
+ toAccount = 'swap'
2713
+ elif type == 2:
2714
+ fromAccount = 'swap'
2715
+ toAccount = 'spot'
2716
+ timestamp = self.safe_integer(transfer, 'timestamp')
2717
+ return {
2718
+ 'info': transfer,
2719
+ 'id': self.safe_string(transfer, 'transfer_id'),
2720
+ 'timestamp': timestamp,
2721
+ 'datetime': self.iso8601(timestamp),
2722
+ 'currency': self.safe_currency_code(self.safe_string(transfer, 'currency'), currency),
2723
+ 'amount': self.safe_number(transfer, 'amount'),
2724
+ 'fromAccount': fromAccount,
2725
+ 'toAccount': toAccount,
2726
+ 'status': self.parse_transfer_status(self.safe_string(transfer, 'code')),
2727
+ }
2728
+
2729
+ async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
2730
+ """
2731
+ transfer currency internally between wallets on the same account
2732
+ :param str code: unified currency code
2733
+ :param float amount: amount to transfer
2734
+ :param str fromAccount: account to transfer from
2735
+ :param str toAccount: account to transfer to
2736
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2737
+ :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
2738
+ """
2739
+ await self.load_markets()
2740
+ currency = self.currency(code)
2741
+ accountsByType = self.safe_value(self.options, 'accountsByType', {})
2742
+ fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
2743
+ toId = self.safe_string(accountsByType, toAccount, toAccount)
2744
+ request: dict = {
2745
+ 'currency_mark': currency['id'],
2746
+ 'num': self.currency_to_precision(code, amount),
2747
+ 'from': fromId, # 1 = SPOT, 2 = MARGIN, 3 = OTC
2748
+ 'to': toId, # 1 = SPOT, 2 = MARGIN, 3 = OTC
2749
+ }
2750
+ response = await self.privateSpotPostTransfer(self.extend(request, params))
2751
+ #
2752
+ # {
2753
+ # "code": 0
2754
+ # }
2755
+ #
2756
+ return self.parse_transfer(response, currency)
2757
+
2758
+ async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
2759
+ """
2760
+ make a withdrawal
2761
+ :param str code: unified currency code
2762
+ :param float amount: the amount to withdraw
2763
+ :param str address: the address to withdraw to
2764
+ :param str tag:
2765
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2766
+ :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
2767
+ """
2768
+ tag, params = self.handle_withdraw_tag_and_params(tag, params)
2769
+ self.check_address(address)
2770
+ await self.load_markets()
2771
+ currency = self.currency(code)
2772
+ request: dict = {
2773
+ # 'chain': 'ERC20', 'OMNI', 'TRC20', # required for USDT
2774
+ 'address': address,
2775
+ 'amount': self.currency_to_precision(code, amount),
2776
+ 'currency': currency['id'],
2777
+ }
2778
+ if tag is not None:
2779
+ request['memo'] = tag
2780
+ response = await self.privateSpotPostWithdrawNew(self.extend(request, params))
2781
+ #
2782
+ # {
2783
+ # "code": 200,
2784
+ # "withdraw_id": 700
2785
+ # }
2786
+ #
2787
+ return self.parse_transaction(response, currency)
2788
+
2789
+ async def fetch_borrow_interest(self, code: Str = None, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2790
+ await self.load_markets()
2791
+ request: dict = {}
2792
+ market = None
2793
+ if symbol is not None:
2794
+ market = self.market(symbol)
2795
+ request['symbol'] = market['id']
2796
+ response = await self.privateSpotGetMarginPositions(self.extend(request, params))
2797
+ #
2798
+ # {
2799
+ # "margin": "45.71246418952618",
2800
+ # "code": 0,
2801
+ # "margin_rate": "7.141978570340037",
2802
+ # "positions": [
2803
+ # {
2804
+ # "amount": 0.0006103,
2805
+ # "side": "go_long",
2806
+ # "entry_price": 31428.72,
2807
+ # "liquidation_rate": 0.3,
2808
+ # "liquidation_price": 10225.335481159,
2809
+ # "unrealized_roe": -0.0076885829266987,
2810
+ # "symbol": "BTC_USDT",
2811
+ # "unrealized_pnl": -0.049158102631999,
2812
+ # "leverage_ratio": 3
2813
+ # }
2814
+ # ],
2815
+ # "unrealized_pnl": "-0.049158102631998504"
2816
+ # }
2817
+ #
2818
+ rows = self.safe_value(response, 'positions')
2819
+ interest = self.parse_borrow_interests(rows, market)
2820
+ return self.filter_by_currency_since_limit(interest, code, since, limit)
2821
+
2822
+ def parse_borrow_interest(self, info: dict, market: Market = None):
2823
+ #
2824
+ # {
2825
+ # "amount": 0.0006103,
2826
+ # "side": "go_long",
2827
+ # "entry_price": 31428.72,
2828
+ # "liquidation_rate": 0.3,
2829
+ # "liquidation_price": 10225.335481159,
2830
+ # "unrealized_roe": -0.0076885829266987,
2831
+ # "symbol": "BTC_USDT",
2832
+ # "unrealized_pnl": -0.049158102631999,
2833
+ # "leverage_ratio": 3
2834
+ # }
2835
+ #
2836
+ marketId = self.safe_string(info, 'symbol')
2837
+ amountString = self.safe_string(info, 'amount')
2838
+ leverageString = self.safe_string(info, 'leverage_ratio')
2839
+ amountInvested = Precise.string_div(amountString, leverageString)
2840
+ amountBorrowed = Precise.string_sub(amountString, amountInvested)
2841
+ currency = None if (market is None) else market['base']
2842
+ symbol = self.safe_symbol(marketId, market)
2843
+ return {
2844
+ 'account': symbol,
2845
+ 'symbol': symbol,
2846
+ 'currency': currency,
2847
+ 'interest': None,
2848
+ 'interestRate': 0.001, # all interest rates on digifinex are 0.1%
2849
+ 'amountBorrowed': self.parse_number(amountBorrowed),
2850
+ 'timestamp': None,
2851
+ 'datetime': None,
2852
+ 'info': info,
2853
+ }
2854
+
2855
+ async def fetch_cross_borrow_rate(self, code: str, params={}) -> CrossBorrowRate:
2856
+ """
2857
+ fetch the rate of interest to borrow a currency for margin trading
2858
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#margin-assets
2859
+ :param str code: unified currency code
2860
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2861
+ :returns dict: a `borrow rate structure <https://github.com/ccxt/ccxt/wiki/Manual#borrow-rate-structure>`
2862
+ """
2863
+ await self.load_markets()
2864
+ request: dict = {}
2865
+ response = await self.privateSpotGetMarginAssets(self.extend(request, params))
2866
+ #
2867
+ # {
2868
+ # "list": [
2869
+ # {
2870
+ # "valuation_rate": 1,
2871
+ # "total": 1.92012186174,
2872
+ # "free": 1.92012186174,
2873
+ # "currency": "USDT"
2874
+ # },
2875
+ # ],
2876
+ # "total": 45.133305540922,
2877
+ # "code": 0,
2878
+ # "unrealized_pnl": 0,
2879
+ # "free": 45.133305540922,
2880
+ # "equity": 45.133305540922
2881
+ # }
2882
+ #
2883
+ data = self.safe_value(response, 'list', [])
2884
+ result = []
2885
+ for i in range(0, len(data)):
2886
+ entry = data[i]
2887
+ if self.safe_string(entry, 'currency') == code:
2888
+ result = entry
2889
+ currency = self.currency(code)
2890
+ return self.parse_borrow_rate(result, currency)
2891
+
2892
+ async def fetch_cross_borrow_rates(self, params={}) -> CrossBorrowRates:
2893
+ """
2894
+ fetch the borrow interest rates of all currencies
2895
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#margin-assets
2896
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2897
+ :returns dict: a list of `borrow rate structures <https://docs.ccxt.com/#/?id=borrow-rate-structure>`
2898
+ """
2899
+ await self.load_markets()
2900
+ response = await self.privateSpotGetMarginAssets(params)
2901
+ #
2902
+ # {
2903
+ # "list": [
2904
+ # {
2905
+ # "valuation_rate": 1,
2906
+ # "total": 1.92012186174,
2907
+ # "free": 1.92012186174,
2908
+ # "currency": "USDT"
2909
+ # },
2910
+ # ],
2911
+ # "total": 45.133305540922,
2912
+ # "code": 0,
2913
+ # "unrealized_pnl": 0,
2914
+ # "free": 45.133305540922,
2915
+ # "equity": 45.133305540922
2916
+ # }
2917
+ #
2918
+ result = self.safe_value(response, 'list', [])
2919
+ return self.parse_borrow_rates(result, 'currency')
2920
+
2921
+ def parse_borrow_rate(self, info, currency: Currency = None):
2922
+ #
2923
+ # {
2924
+ # "valuation_rate": 1,
2925
+ # "total": 1.92012186174,
2926
+ # "free": 1.92012186174,
2927
+ # "currency": "USDT"
2928
+ # }
2929
+ #
2930
+ timestamp = self.milliseconds()
2931
+ currencyId = self.safe_string(info, 'currency')
2932
+ return {
2933
+ 'currency': self.safe_currency_code(currencyId, currency),
2934
+ 'rate': 0.001, # all interest rates on digifinex are 0.1%
2935
+ 'period': 86400000,
2936
+ 'timestamp': timestamp,
2937
+ 'datetime': self.iso8601(timestamp),
2938
+ 'info': info,
2939
+ }
2940
+
2941
+ def parse_borrow_rates(self, info, codeKey):
2942
+ #
2943
+ # {
2944
+ # "valuation_rate": 1,
2945
+ # "total": 1.92012186174,
2946
+ # "free": 1.92012186174,
2947
+ # "currency": "USDT"
2948
+ # },
2949
+ #
2950
+ result: dict = {}
2951
+ for i in range(0, len(info)):
2952
+ item = info[i]
2953
+ currency = self.safe_string(item, codeKey)
2954
+ code = self.safe_currency_code(currency)
2955
+ borrowRate = self.parse_borrow_rate(item)
2956
+ result[code] = borrowRate
2957
+ return result
2958
+
2959
+ async def fetch_funding_rate(self, symbol: str, params={}):
2960
+ """
2961
+ fetch the current funding rate
2962
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#currentfundingrate
2963
+ :param str symbol: unified market symbol
2964
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2965
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
2966
+ """
2967
+ await self.load_markets()
2968
+ market = self.market(symbol)
2969
+ if not market['swap']:
2970
+ raise BadSymbol(self.id + ' fetchFundingRate() supports swap contracts only')
2971
+ request: dict = {
2972
+ 'instrument_id': market['id'],
2973
+ }
2974
+ response = await self.publicSwapGetPublicFundingRate(self.extend(request, params))
2975
+ #
2976
+ # {
2977
+ # "code": 0,
2978
+ # "data": {
2979
+ # "instrument_id": "BTCUSDTPERP",
2980
+ # "funding_rate": "-0.00012",
2981
+ # "funding_time": 1662710400000,
2982
+ # "next_funding_rate": "0.0001049907085171607",
2983
+ # "next_funding_time": 1662739200000
2984
+ # }
2985
+ # }
2986
+ #
2987
+ data = self.safe_value(response, 'data', {})
2988
+ return self.parse_funding_rate(data, market)
2989
+
2990
+ def parse_funding_rate(self, contract, market: Market = None):
2991
+ #
2992
+ # {
2993
+ # "instrument_id": "BTCUSDTPERP",
2994
+ # "funding_rate": "-0.00012",
2995
+ # "funding_time": 1662710400000,
2996
+ # "next_funding_rate": "0.0001049907085171607",
2997
+ # "next_funding_time": 1662739200000
2998
+ # }
2999
+ #
3000
+ marketId = self.safe_string(contract, 'instrument_id')
3001
+ timestamp = self.safe_integer(contract, 'funding_time')
3002
+ nextTimestamp = self.safe_integer(contract, 'next_funding_time')
3003
+ return {
3004
+ 'info': contract,
3005
+ 'symbol': self.safe_symbol(marketId, market),
3006
+ 'markPrice': None,
3007
+ 'indexPrice': None,
3008
+ 'interestRate': None,
3009
+ 'estimatedSettlePrice': None,
3010
+ 'timestamp': None,
3011
+ 'datetime': None,
3012
+ 'fundingRate': self.safe_number(contract, 'funding_rate'),
3013
+ 'fundingTimestamp': timestamp,
3014
+ 'fundingDatetime': self.iso8601(timestamp),
3015
+ 'nextFundingRate': self.safe_string(contract, 'next_funding_rate'),
3016
+ 'nextFundingTimestamp': nextTimestamp,
3017
+ 'nextFundingDatetime': self.iso8601(nextTimestamp),
3018
+ 'previousFundingRate': None,
3019
+ 'previousFundingTimestamp': None,
3020
+ 'previousFundingDatetime': None,
3021
+ }
3022
+
3023
+ async def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
3024
+ """
3025
+ fetches historical funding rate prices
3026
+ :param str symbol: unified symbol of the market to fetch the funding rate history for
3027
+ :param int [since]: timestamp in ms of the earliest funding rate to fetch
3028
+ :param int [limit]: the maximum amount of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>` to fetch
3029
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3030
+ :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>`
3031
+ """
3032
+ if symbol is None:
3033
+ raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
3034
+ await self.load_markets()
3035
+ market = self.market(symbol)
3036
+ if not market['swap']:
3037
+ raise BadSymbol(self.id + ' fetchFundingRateHistory() supports swap contracts only')
3038
+ request: dict = {
3039
+ 'instrument_id': market['id'],
3040
+ }
3041
+ if since is not None:
3042
+ request['start_timestamp'] = since
3043
+ if limit is not None:
3044
+ request['limit'] = limit
3045
+ response = await self.publicSwapGetPublicFundingRateHistory(self.extend(request, params))
3046
+ #
3047
+ # {
3048
+ # "code": 0,
3049
+ # "data": {
3050
+ # "instrument_id": "BTCUSDTPERP",
3051
+ # "funding_rates": [
3052
+ # {
3053
+ # "rate": "-0.00375",
3054
+ # "time": 1607673600000
3055
+ # },
3056
+ # ...
3057
+ # ]
3058
+ # }
3059
+ # }
3060
+ #
3061
+ data = self.safe_value(response, 'data', {})
3062
+ result = self.safe_value(data, 'funding_rates', [])
3063
+ rates = []
3064
+ for i in range(0, len(result)):
3065
+ entry = result[i]
3066
+ marketId = self.safe_string(data, 'instrument_id')
3067
+ symbolInner = self.safe_symbol(marketId)
3068
+ timestamp = self.safe_integer(entry, 'time')
3069
+ rates.append({
3070
+ 'info': entry,
3071
+ 'symbol': symbolInner,
3072
+ 'fundingRate': self.safe_number(entry, 'rate'),
3073
+ 'timestamp': timestamp,
3074
+ 'datetime': self.iso8601(timestamp),
3075
+ })
3076
+ sorted = self.sort_by(rates, 'timestamp')
3077
+ return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)
3078
+
3079
+ async def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
3080
+ """
3081
+ fetch the trading fees for a market
3082
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#tradingfee
3083
+ :param str symbol: unified market symbol
3084
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3085
+ :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
3086
+ """
3087
+ await self.load_markets()
3088
+ market = self.market(symbol)
3089
+ if not market['swap']:
3090
+ raise BadRequest(self.id + ' fetchTradingFee() supports swap markets only')
3091
+ request: dict = {
3092
+ 'instrument_id': market['id'],
3093
+ }
3094
+ response = await self.privateSwapGetAccountTradingFeeRate(self.extend(request, params))
3095
+ #
3096
+ # {
3097
+ # "code": 0,
3098
+ # "data": {
3099
+ # "instrument_id": "BTCUSDTPERP",
3100
+ # "taker_fee_rate": "0.0005",
3101
+ # "maker_fee_rate": "0.0003"
3102
+ # }
3103
+ # }
3104
+ #
3105
+ data = self.safe_value(response, 'data', {})
3106
+ return self.parse_trading_fee(data, market)
3107
+
3108
+ def parse_trading_fee(self, fee: dict, market: Market = None) -> TradingFeeInterface:
3109
+ #
3110
+ # {
3111
+ # "instrument_id": "BTCUSDTPERP",
3112
+ # "taker_fee_rate": "0.0005",
3113
+ # "maker_fee_rate": "0.0003"
3114
+ # }
3115
+ #
3116
+ marketId = self.safe_string(fee, 'instrument_id')
3117
+ symbol = self.safe_symbol(marketId, market)
3118
+ return {
3119
+ 'info': fee,
3120
+ 'symbol': symbol,
3121
+ 'maker': self.safe_number(fee, 'maker_fee_rate'),
3122
+ 'taker': self.safe_number(fee, 'taker_fee_rate'),
3123
+ 'percentage': None,
3124
+ 'tierBased': None,
3125
+ }
3126
+
3127
+ async def fetch_positions(self, symbols: Strings = None, params={}):
3128
+ """
3129
+ fetch all open positions
3130
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#margin-positions
3131
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#positions
3132
+ :param str[]|None symbols: list of unified market symbols
3133
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3134
+ :returns dict[]: a list of `position structures <https://docs.ccxt.com/#/?id=position-structure>`
3135
+ """
3136
+ await self.load_markets()
3137
+ symbols = self.market_symbols(symbols)
3138
+ request: dict = {}
3139
+ market = None
3140
+ marketType = None
3141
+ if symbols is not None:
3142
+ symbol = None
3143
+ if isinstance(symbols, list):
3144
+ symbolsLength = len(symbols)
3145
+ if symbolsLength > 1:
3146
+ raise BadRequest(self.id + ' fetchPositions() symbols argument cannot contain more than 1 symbol')
3147
+ symbol = symbols[0]
3148
+ else:
3149
+ symbol = symbols
3150
+ market = self.market(symbol)
3151
+ marketType, params = self.handle_market_type_and_params('fetchPositions', market, params)
3152
+ marginMode, query = self.handle_margin_mode_and_params('fetchPositions', params)
3153
+ if marginMode is not None:
3154
+ marketType = 'margin'
3155
+ if market is not None:
3156
+ marketIdRequest = 'instrument_id' if (marketType == 'swap') else 'symbol'
3157
+ request[marketIdRequest] = market['id']
3158
+ response = None
3159
+ if marketType == 'spot' or marketType == 'margin':
3160
+ response = await self.privateSpotGetMarginPositions(self.extend(request, query))
3161
+ elif marketType == 'swap':
3162
+ response = await self.privateSwapGetAccountPositions(self.extend(request, query))
3163
+ else:
3164
+ raise NotSupported(self.id + ' fetchPositions() not support self market type')
3165
+ #
3166
+ # swap
3167
+ #
3168
+ # {
3169
+ # "code": 0,
3170
+ # "data": [
3171
+ # {
3172
+ # "instrument_id": "BTCUSDTPERP",
3173
+ # "margin_mode": "crossed",
3174
+ # "avail_position": "1",
3175
+ # "avg_cost": "18369.3",
3176
+ # "last": "18404.7",
3177
+ # "leverage": "20",
3178
+ # "liquidation_price": "451.12820512820264",
3179
+ # "maint_margin_ratio": "0.005",
3180
+ # "margin": "0.918465",
3181
+ # "position": "1",
3182
+ # "realized_pnl": "0",
3183
+ # "unrealized_pnl": "0.03410000000000224",
3184
+ # "unrealized_pnl_rate": "0.03712716325608732",
3185
+ # "side": "long",
3186
+ # "open_outstanding": "0",
3187
+ # "risk_score": "0.495049504950495",
3188
+ # "margin_ratio": "0.4029464788983229",
3189
+ # "timestamp": 1667960497145
3190
+ # },
3191
+ # ...
3192
+ # ]
3193
+ # }
3194
+ #
3195
+ # margin
3196
+ #
3197
+ # {
3198
+ # "margin": "77.71534772983289",
3199
+ # "code": 0,
3200
+ # "margin_rate": "10.284503769497306",
3201
+ # "positions": [
3202
+ # {
3203
+ # "amount": 0.0010605,
3204
+ # "side": "go_long",
3205
+ # "entry_price": 18321.39,
3206
+ # "liquidation_rate": 0.3,
3207
+ # "liquidation_price": -52754.371758471,
3208
+ # "unrealized_roe": -0.002784390267332,
3209
+ # "symbol": "BTC_USDT",
3210
+ # "unrealized_pnl": -0.010820048189999,
3211
+ # "leverage_ratio": 5
3212
+ # },
3213
+ # ...
3214
+ # ],
3215
+ # "unrealized_pnl": "-0.10681600018999979"
3216
+ # }
3217
+ #
3218
+ positionRequest = 'data' if (marketType == 'swap') else 'positions'
3219
+ positions = self.safe_value(response, positionRequest, [])
3220
+ result = []
3221
+ for i in range(0, len(positions)):
3222
+ result.append(self.parse_position(positions[i], market))
3223
+ return self.filter_by_array_positions(result, 'symbol', symbols, False)
3224
+
3225
+ async def fetch_position(self, symbol: str, params={}):
3226
+ """
3227
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#margin-positions
3228
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#positions
3229
+ fetch data on a single open contract trade position
3230
+ :param str symbol: unified market symbol of the market the position is held in
3231
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3232
+ :returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
3233
+ """
3234
+ await self.load_markets()
3235
+ market = self.market(symbol)
3236
+ request: dict = {}
3237
+ marketType = None
3238
+ marketType, params = self.handle_market_type_and_params('fetchPosition', market, params)
3239
+ marginMode, query = self.handle_margin_mode_and_params('fetchPosition', params)
3240
+ if marginMode is not None:
3241
+ marketType = 'margin'
3242
+ marketIdRequest = 'instrument_id' if (marketType == 'swap') else 'symbol'
3243
+ request[marketIdRequest] = market['id']
3244
+ response = None
3245
+ if marketType == 'spot' or marketType == 'margin':
3246
+ response = await self.privateSpotGetMarginPositions(self.extend(request, query))
3247
+ elif marketType == 'swap':
3248
+ response = await self.privateSwapGetAccountPositions(self.extend(request, query))
3249
+ else:
3250
+ raise NotSupported(self.id + ' fetchPosition() not support self market type')
3251
+ #
3252
+ # swap
3253
+ #
3254
+ # {
3255
+ # "code": 0,
3256
+ # "data": [
3257
+ # {
3258
+ # "instrument_id": "BTCUSDTPERP",
3259
+ # "margin_mode": "crossed",
3260
+ # "avail_position": "1",
3261
+ # "avg_cost": "18369.3",
3262
+ # "last": "18388.9",
3263
+ # "leverage": "20",
3264
+ # "liquidation_price": "383.38712921065553",
3265
+ # "maint_margin_ratio": "0.005",
3266
+ # "margin": "0.918465",
3267
+ # "position": "1",
3268
+ # "realized_pnl": "0",
3269
+ # "unrealized_pnl": "0.021100000000004115",
3270
+ # "unrealized_pnl_rate": "0.02297311274790451",
3271
+ # "side": "long",
3272
+ # "open_outstanding": "0",
3273
+ # "risk_score": "0.4901960784313725",
3274
+ # "margin_ratio": "0.40486964045976204",
3275
+ # "timestamp": 1667960241758
3276
+ # }
3277
+ # ]
3278
+ # }
3279
+ #
3280
+ # margin
3281
+ #
3282
+ # {
3283
+ # "margin": "77.71534772983289",
3284
+ # "code": 0,
3285
+ # "margin_rate": "10.284503769497306",
3286
+ # "positions": [
3287
+ # {
3288
+ # "amount": 0.0010605,
3289
+ # "side": "go_long",
3290
+ # "entry_price": 18321.39,
3291
+ # "liquidation_rate": 0.3,
3292
+ # "liquidation_price": -52754.371758471,
3293
+ # "unrealized_roe": -0.002784390267332,
3294
+ # "symbol": "BTC_USDT",
3295
+ # "unrealized_pnl": -0.010820048189999,
3296
+ # "leverage_ratio": 5
3297
+ # }
3298
+ # ],
3299
+ # "unrealized_pnl": "-0.10681600018999979"
3300
+ # }
3301
+ #
3302
+ dataRequest = 'data' if (marketType == 'swap') else 'positions'
3303
+ data = self.safe_value(response, dataRequest, [])
3304
+ position = self.parse_position(data[0], market)
3305
+ if marketType == 'swap':
3306
+ return position
3307
+ else:
3308
+ position['collateral'] = self.safe_number(response, 'margin')
3309
+ position['marginRatio'] = self.safe_number(response, 'margin_rate')
3310
+ return position
3311
+
3312
+ def parse_position(self, position: dict, market: Market = None):
3313
+ #
3314
+ # swap
3315
+ #
3316
+ # {
3317
+ # "instrument_id": "BTCUSDTPERP",
3318
+ # "margin_mode": "crossed",
3319
+ # "avail_position": "1",
3320
+ # "avg_cost": "18369.3",
3321
+ # "last": "18388.9",
3322
+ # "leverage": "20",
3323
+ # "liquidation_price": "383.38712921065553",
3324
+ # "maint_margin_ratio": "0.005",
3325
+ # "margin": "0.918465",
3326
+ # "position": "1",
3327
+ # "realized_pnl": "0",
3328
+ # "unrealized_pnl": "0.021100000000004115",
3329
+ # "unrealized_pnl_rate": "0.02297311274790451",
3330
+ # "side": "long",
3331
+ # "open_outstanding": "0",
3332
+ # "risk_score": "0.4901960784313725",
3333
+ # "margin_ratio": "0.40486964045976204",
3334
+ # "timestamp": 1667960241758
3335
+ # }
3336
+ #
3337
+ # margin
3338
+ #
3339
+ # {
3340
+ # "amount": 0.0010605,
3341
+ # "side": "go_long",
3342
+ # "entry_price": 18321.39,
3343
+ # "liquidation_rate": 0.3,
3344
+ # "liquidation_price": -52754.371758471,
3345
+ # "unrealized_roe": -0.002784390267332,
3346
+ # "symbol": "BTC_USDT",
3347
+ # "unrealized_pnl": -0.010820048189999,
3348
+ # "leverage_ratio": 5
3349
+ # }
3350
+ #
3351
+ marketId = self.safe_string_2(position, 'instrument_id', 'symbol')
3352
+ market = self.safe_market(marketId, market)
3353
+ symbol = market['symbol']
3354
+ marginMode = self.safe_string(position, 'margin_mode')
3355
+ if marginMode is not None:
3356
+ marginMode = 'cross' if (marginMode == 'crossed') else 'isolated'
3357
+ else:
3358
+ marginMode = 'crossed'
3359
+ timestamp = self.safe_integer(position, 'timestamp')
3360
+ side = self.safe_string(position, 'side')
3361
+ if side == 'go_long':
3362
+ side = 'long'
3363
+ elif side == 'go_short':
3364
+ side = 'short'
3365
+ return self.safe_position({
3366
+ 'info': position,
3367
+ 'id': None,
3368
+ 'symbol': symbol,
3369
+ 'notional': self.safe_number(position, 'amount'),
3370
+ 'marginMode': marginMode,
3371
+ 'liquidationPrice': self.safe_number(position, 'liquidation_price'),
3372
+ 'entryPrice': self.safe_number_2(position, 'avg_cost', 'entry_price'),
3373
+ 'unrealizedPnl': self.safe_number(position, 'unrealized_pnl'),
3374
+ 'contracts': self.safe_number(position, 'avail_position'),
3375
+ 'contractSize': self.safe_number(market, 'contractSize'),
3376
+ 'markPrice': self.safe_number(position, 'last'),
3377
+ 'side': side,
3378
+ 'hedged': None,
3379
+ 'timestamp': timestamp,
3380
+ 'datetime': self.iso8601(timestamp),
3381
+ 'maintenanceMargin': self.safe_number(position, 'margin'),
3382
+ 'maintenanceMarginPercentage': self.safe_number(position, 'maint_margin_ratio'),
3383
+ 'collateral': None,
3384
+ 'initialMargin': None,
3385
+ 'initialMarginPercentage': None,
3386
+ 'leverage': self.safe_number_2(position, 'leverage', 'leverage_ratio'),
3387
+ 'marginRatio': self.safe_number(position, 'margin_ratio'),
3388
+ 'percentage': None,
3389
+ 'stopLossPrice': None,
3390
+ 'takeProfitPrice': None,
3391
+ })
3392
+
3393
+ async def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
3394
+ """
3395
+ set the level of leverage for a market
3396
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#setleverage
3397
+ :param float leverage: the rate of leverage
3398
+ :param str symbol: unified market symbol
3399
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3400
+ :param str [params.marginMode]: either 'cross' or 'isolated', default is cross
3401
+ :param str [params.side]: either 'long' or 'short', required for isolated markets only
3402
+ :returns dict: response from the exchange
3403
+ """
3404
+ if symbol is None:
3405
+ raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
3406
+ await self.load_markets()
3407
+ market = self.market(symbol)
3408
+ if market['type'] != 'swap':
3409
+ raise BadSymbol(self.id + ' setLeverage() supports swap contracts only')
3410
+ if (leverage < 1) or (leverage > 100):
3411
+ raise BadRequest(self.id + ' leverage should be between 1 and 100')
3412
+ request: dict = {
3413
+ 'instrument_id': market['id'],
3414
+ 'leverage': leverage,
3415
+ }
3416
+ defaultMarginMode = self.safe_string_2(self.options, 'marginMode', 'defaultMarginMode')
3417
+ marginMode = self.safe_string_lower_2(params, 'marginMode', 'defaultMarginMode', defaultMarginMode)
3418
+ if marginMode is not None:
3419
+ marginMode = 'crossed' if (marginMode == 'cross') else 'isolated'
3420
+ request['margin_mode'] = marginMode
3421
+ params = self.omit(params, ['marginMode', 'defaultMarginMode'])
3422
+ if marginMode == 'isolated':
3423
+ side = self.safe_string(params, 'side')
3424
+ if side is not None:
3425
+ request['side'] = side
3426
+ params = self.omit(params, 'side')
3427
+ else:
3428
+ self.check_required_argument('setLeverage', side, 'side', ['long', 'short'])
3429
+ return await self.privateSwapPostAccountLeverage(self.extend(request, params))
3430
+ #
3431
+ # {
3432
+ # "code": 0,
3433
+ # "data": {
3434
+ # "instrument_id": "BTCUSDTPERP",
3435
+ # "leverage": 30,
3436
+ # "margin_mode": "crossed",
3437
+ # "side": "both"
3438
+ # }
3439
+ # }
3440
+ #
3441
+
3442
+ async def fetch_transfers(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> TransferEntries:
3443
+ """
3444
+ fetch the transfer history, only transfers between spot and swap accounts are supported
3445
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#transferrecord
3446
+ :param str code: unified currency code of the currency transferred
3447
+ :param int [since]: the earliest time in ms to fetch transfers for
3448
+ :param int [limit]: the maximum number of transfers to retrieve
3449
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3450
+ :returns dict[]: a list of `transfer structures <https://docs.ccxt.com/#/?id=transfer-structure>`
3451
+ """
3452
+ await self.load_markets()
3453
+ currency = None
3454
+ request: dict = {}
3455
+ if code is not None:
3456
+ currency = self.safe_currency_code(code)
3457
+ request['currency'] = currency['id']
3458
+ if since is not None:
3459
+ request['start_timestamp'] = since
3460
+ if limit is not None:
3461
+ request['limit'] = limit # default 20 max 100
3462
+ response = await self.privateSwapGetAccountTransferRecord(self.extend(request, params))
3463
+ #
3464
+ # {
3465
+ # "code": 0,
3466
+ # "data": [
3467
+ # {
3468
+ # "transfer_id": 130524,
3469
+ # "type": 1,
3470
+ # "currency": "USDT",
3471
+ # "amount": "24",
3472
+ # "timestamp": 1666505659000
3473
+ # },
3474
+ # ...
3475
+ # ]
3476
+ # }
3477
+ #
3478
+ transfers = self.safe_list(response, 'data', [])
3479
+ return self.parse_transfers(transfers, currency, since, limit)
3480
+
3481
+ async def fetch_leverage_tiers(self, symbols: Strings = None, params={}) -> LeverageTiers:
3482
+ """
3483
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#instruments
3484
+ retrieve information on the maximum leverage, for different trade sizes
3485
+ :param str[]|None symbols: a list of unified market symbols
3486
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3487
+ :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`, indexed by market symbols
3488
+ """
3489
+ await self.load_markets()
3490
+ response = await self.publicSwapGetPublicInstruments(params)
3491
+ #
3492
+ # {
3493
+ # "code": 0,
3494
+ # "data": [
3495
+ # {
3496
+ # "instrument_id": "BTCUSDTPERP",
3497
+ # "type": "REAL",
3498
+ # "contract_type": "PERPETUAL",
3499
+ # "base_currency": "BTC",
3500
+ # "quote_currency": "USDT",
3501
+ # "clear_currency": "USDT",
3502
+ # "contract_value": "0.001",
3503
+ # "contract_value_currency": "BTC",
3504
+ # "is_inverse": False,
3505
+ # "is_trading": True,
3506
+ # "status": "ONLINE",
3507
+ # "price_precision": 1,
3508
+ # "tick_size": "0.1",
3509
+ # "min_order_amount": 1,
3510
+ # "open_max_limits": [
3511
+ # {
3512
+ # "leverage": "50",
3513
+ # "max_limit": "1000000"
3514
+ # },
3515
+ # ]
3516
+ # },
3517
+ # ]
3518
+ # }
3519
+ #
3520
+ data = self.safe_value(response, 'data', [])
3521
+ symbols = self.market_symbols(symbols)
3522
+ return self.parse_leverage_tiers(data, symbols, 'instrument_id')
3523
+
3524
+ async def fetch_market_leverage_tiers(self, symbol: str, params={}) -> List[LeverageTier]:
3525
+ """
3526
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#instrument
3527
+ retrieve information on the maximum leverage, for different trade sizes for a single market
3528
+ :param str symbol: unified market symbol
3529
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3530
+ :returns dict: a `leverage tiers structure <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`
3531
+ """
3532
+ await self.load_markets()
3533
+ market = self.market(symbol)
3534
+ if not market['swap']:
3535
+ raise BadRequest(self.id + ' fetchMarketLeverageTiers() supports swap markets only')
3536
+ request: dict = {
3537
+ 'instrument_id': market['id'],
3538
+ }
3539
+ response = await self.publicSwapGetPublicInstrument(self.extend(request, params))
3540
+ #
3541
+ # {
3542
+ # "code": 0,
3543
+ # "data": {
3544
+ # "instrument_id": "BTCUSDTPERP",
3545
+ # "type": "REAL",
3546
+ # "contract_type": "PERPETUAL",
3547
+ # "base_currency": "BTC",
3548
+ # "quote_currency": "USDT",
3549
+ # "clear_currency": "USDT",
3550
+ # "contract_value": "0.001",
3551
+ # "contract_value_currency": "BTC",
3552
+ # "is_inverse": False,
3553
+ # "is_trading": True,
3554
+ # "status": "ONLINE",
3555
+ # "price_precision": 1,
3556
+ # "tick_size": "0.1",
3557
+ # "min_order_amount": 1,
3558
+ # "open_max_limits": [
3559
+ # {
3560
+ # "leverage": "50",
3561
+ # "max_limit": "1000000"
3562
+ # }
3563
+ # ]
3564
+ # }
3565
+ # }
3566
+ #
3567
+ data = self.safe_value(response, 'data', {})
3568
+ return self.parse_market_leverage_tiers(data, market)
3569
+
3570
+ def parse_market_leverage_tiers(self, info, market: Market = None) -> List[LeverageTier]:
3571
+ #
3572
+ # {
3573
+ # "instrument_id": "BTCUSDTPERP",
3574
+ # "type": "REAL",
3575
+ # "contract_type": "PERPETUAL",
3576
+ # "base_currency": "BTC",
3577
+ # "quote_currency": "USDT",
3578
+ # "clear_currency": "USDT",
3579
+ # "contract_value": "0.001",
3580
+ # "contract_value_currency": "BTC",
3581
+ # "is_inverse": False,
3582
+ # "is_trading": True,
3583
+ # "status": "ONLINE",
3584
+ # "price_precision": 1,
3585
+ # "tick_size": "0.1",
3586
+ # "min_order_amount": 1,
3587
+ # "open_max_limits": [
3588
+ # {
3589
+ # "leverage": "50",
3590
+ # "max_limit": "1000000"
3591
+ # }
3592
+ # ]
3593
+ # }
3594
+ #
3595
+ tiers = []
3596
+ brackets = self.safe_value(info, 'open_max_limits', {})
3597
+ for i in range(0, len(brackets)):
3598
+ tier = brackets[i]
3599
+ marketId = self.safe_string(info, 'instrument_id')
3600
+ market = self.safe_market(marketId)
3601
+ tiers.append({
3602
+ 'tier': self.sum(i, 1),
3603
+ 'currency': market['settle'],
3604
+ 'minNotional': None,
3605
+ 'maxNotional': self.safe_number(tier, 'max_limit'),
3606
+ 'maintenanceMarginRate': None,
3607
+ 'maxLeverage': self.safe_number(tier, 'leverage'),
3608
+ 'info': tier,
3609
+ })
3610
+ return tiers
3611
+
3612
+ def handle_margin_mode_and_params(self, methodName, params={}, defaultValue=None):
3613
+ """
3614
+ * @ignore
3615
+ marginMode specified by params["marginMode"], self.options["marginMode"], self.options["defaultMarginMode"], params["margin"] = True or self.options["defaultType"] = 'margin'
3616
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3617
+ :returns Array: the marginMode in lowercase
3618
+ """
3619
+ defaultType = self.safe_string(self.options, 'defaultType')
3620
+ isMargin = self.safe_bool(params, 'margin', False)
3621
+ marginMode = None
3622
+ marginMode, params = super(digifinex, self).handle_margin_mode_and_params(methodName, params, defaultValue)
3623
+ if marginMode is not None:
3624
+ if marginMode != 'cross':
3625
+ raise NotSupported(self.id + ' only cross margin is supported')
3626
+ else:
3627
+ if (defaultType == 'margin') or (isMargin is True):
3628
+ marginMode = 'cross'
3629
+ return [marginMode, params]
3630
+
3631
+ async def fetch_deposit_withdraw_fees(self, codes: Strings = None, params={}):
3632
+ """
3633
+ fetch deposit and withdraw fees
3634
+ :see: https://docs.digifinex.com/en-ww/spot/v3/rest.html#get-currency-deposit-and-withdrawal-information
3635
+ :param str[]|None codes: not used by fetchDepositWithdrawFees()
3636
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3637
+ :returns dict: a list of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>`
3638
+ """
3639
+ await self.load_markets()
3640
+ response = await self.publicSpotGetCurrencies(params)
3641
+ #
3642
+ # {
3643
+ # "data": [
3644
+ # {
3645
+ # "deposit_status": 0,
3646
+ # "min_withdraw_fee": 5,
3647
+ # "withdraw_fee_currency": "USDT",
3648
+ # "chain": "OMNI",
3649
+ # "withdraw_fee_rate": 0,
3650
+ # "min_withdraw_amount": 10,
3651
+ # "currency": "USDT",
3652
+ # "withdraw_status": 0,
3653
+ # "min_deposit_amount": 10
3654
+ # },
3655
+ # {
3656
+ # "deposit_status": 1,
3657
+ # "min_withdraw_fee": 5,
3658
+ # "withdraw_fee_currency": "USDT",
3659
+ # "chain": "ERC20",
3660
+ # "withdraw_fee_rate": 0,
3661
+ # "min_withdraw_amount": 10,
3662
+ # "currency": "USDT",
3663
+ # "withdraw_status": 1,
3664
+ # "min_deposit_amount": 10
3665
+ # },
3666
+ # ],
3667
+ # "code": 200,
3668
+ # }
3669
+ #
3670
+ data = self.safe_list(response, 'data')
3671
+ return self.parse_deposit_withdraw_fees(data, codes)
3672
+
3673
+ def parse_deposit_withdraw_fees(self, response, codes=None, currencyIdKey=None):
3674
+ #
3675
+ # [
3676
+ # {
3677
+ # "deposit_status": 0,
3678
+ # "min_withdraw_fee": 5,
3679
+ # "withdraw_fee_currency": "USDT",
3680
+ # "chain": "OMNI",
3681
+ # "withdraw_fee_rate": 0,
3682
+ # "min_withdraw_amount": 10,
3683
+ # "currency": "USDT",
3684
+ # "withdraw_status": 0,
3685
+ # "min_deposit_amount": 10
3686
+ # },
3687
+ # {
3688
+ # "deposit_status": 1,
3689
+ # "min_withdraw_fee": 5,
3690
+ # "withdraw_fee_currency": "USDT",
3691
+ # "chain": "ERC20",
3692
+ # "withdraw_fee_rate": 0,
3693
+ # "min_withdraw_amount": 10,
3694
+ # "currency": "USDT",
3695
+ # "withdraw_status": 1,
3696
+ # "min_deposit_amount": 10
3697
+ # },
3698
+ # ]
3699
+ #
3700
+ depositWithdrawFees: dict = {}
3701
+ codes = self.market_codes(codes)
3702
+ for i in range(0, len(response)):
3703
+ entry = response[i]
3704
+ currencyId = self.safe_string(entry, 'currency')
3705
+ code = self.safe_currency_code(currencyId)
3706
+ if (codes is None) or (self.in_array(code, codes)):
3707
+ depositWithdrawFee = self.safe_value(depositWithdrawFees, code)
3708
+ if depositWithdrawFee is None:
3709
+ depositWithdrawFees[code] = self.deposit_withdraw_fee({})
3710
+ depositWithdrawFees[code]['info'] = []
3711
+ depositWithdrawFees[code]['info'].append(entry)
3712
+ networkId = self.safe_string(entry, 'chain')
3713
+ withdrawFee = self.safe_value(entry, 'min_withdraw_fee')
3714
+ withdrawResult: dict = {
3715
+ 'fee': withdrawFee,
3716
+ 'percentage': False if (withdrawFee is not None) else None,
3717
+ }
3718
+ depositResult: dict = {
3719
+ 'fee': None,
3720
+ 'percentage': None,
3721
+ }
3722
+ if networkId is not None:
3723
+ networkCode = self.network_id_to_code(networkId)
3724
+ depositWithdrawFees[code]['networks'][networkCode] = {
3725
+ 'withdraw': withdrawResult,
3726
+ 'deposit': depositResult,
3727
+ }
3728
+ else:
3729
+ depositWithdrawFees[code]['withdraw'] = withdrawResult
3730
+ depositWithdrawFees[code]['deposit'] = depositResult
3731
+ depositWithdrawCodes = list(depositWithdrawFees.keys())
3732
+ for i in range(0, len(depositWithdrawCodes)):
3733
+ code = depositWithdrawCodes[i]
3734
+ currency = self.currency(code)
3735
+ depositWithdrawFees[code] = self.assign_default_deposit_withdraw_fees(depositWithdrawFees[code], currency)
3736
+ return depositWithdrawFees
3737
+
3738
+ async def add_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
3739
+ """
3740
+ add margin to a position
3741
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#positionmargin
3742
+ :param str symbol: unified market symbol
3743
+ :param float amount: amount of margin to add
3744
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3745
+ :param str params['side']: the position side: 'long' or 'short'
3746
+ :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=margin-structure>`
3747
+ """
3748
+ side = self.safe_string(params, 'side')
3749
+ self.check_required_argument('addMargin', side, 'side', ['long', 'short'])
3750
+ return await self.modify_margin_helper(symbol, amount, 1, params)
3751
+
3752
+ async def reduce_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
3753
+ """
3754
+ remove margin from a position
3755
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#positionmargin
3756
+ :param str symbol: unified market symbol
3757
+ :param float amount: the amount of margin to remove
3758
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3759
+ :param str params['side']: the position side: 'long' or 'short'
3760
+ :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=margin-structure>`
3761
+ """
3762
+ side = self.safe_string(params, 'side')
3763
+ self.check_required_argument('reduceMargin', side, 'side', ['long', 'short'])
3764
+ return await self.modify_margin_helper(symbol, amount, 2, params)
3765
+
3766
+ async def modify_margin_helper(self, symbol: str, amount, type, params={}) -> MarginModification:
3767
+ await self.load_markets()
3768
+ side = self.safe_string(params, 'side')
3769
+ market = self.market(symbol)
3770
+ request: dict = {
3771
+ 'instrument_id': market['id'],
3772
+ 'amount': self.number_to_string(amount),
3773
+ 'type': type,
3774
+ 'side': side,
3775
+ }
3776
+ response = await self.privateSwapPostAccountPositionMargin(self.extend(request, params))
3777
+ #
3778
+ # {
3779
+ # "code": 0,
3780
+ # "data": {
3781
+ # "instrument_id": "BTCUSDTPERP",
3782
+ # "side": "long",
3783
+ # "type": 1,
3784
+ # "amount": "3.6834"
3785
+ # }
3786
+ # }
3787
+ #
3788
+ code = self.safe_integer(response, 'code')
3789
+ status = 'ok' if (code == 0) else 'failed'
3790
+ data = self.safe_value(response, 'data', {})
3791
+ return self.extend(self.parse_margin_modification(data, market), {
3792
+ 'status': status,
3793
+ })
3794
+
3795
+ def parse_margin_modification(self, data: dict, market: Market = None) -> MarginModification:
3796
+ #
3797
+ # {
3798
+ # "instrument_id": "BTCUSDTPERP",
3799
+ # "side": "long",
3800
+ # "type": 1,
3801
+ # "amount": "3.6834"
3802
+ # }
3803
+ #
3804
+ marketId = self.safe_string(data, 'instrument_id')
3805
+ rawType = self.safe_integer(data, 'type')
3806
+ return {
3807
+ 'info': data,
3808
+ 'symbol': self.safe_symbol(marketId, market, None, 'swap'),
3809
+ 'type': 'add' if (rawType == 1) else 'reduce',
3810
+ 'marginMode': 'isolated',
3811
+ 'amount': self.safe_number(data, 'amount'),
3812
+ 'total': None,
3813
+ 'code': market['settle'],
3814
+ 'status': None,
3815
+ 'timestamp': None,
3816
+ 'datetime': None,
3817
+ }
3818
+
3819
+ async def fetch_funding_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
3820
+ """
3821
+ fetch the history of funding payments paid and received on self account
3822
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#funding-fee
3823
+ :param str [symbol]: unified market symbol
3824
+ :param int [since]: the earliest time in ms to fetch funding history for
3825
+ :param int [limit]: the maximum number of funding history structures to retrieve
3826
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3827
+ :param int [params.until]: timestamp in ms of the latest funding payment
3828
+ :returns dict: a `funding history structure <https://docs.ccxt.com/#/?id=funding-history-structure>`
3829
+ """
3830
+ await self.load_markets()
3831
+ request: dict = {}
3832
+ request, params = self.handle_until_option('end_timestamp', request, params)
3833
+ market = None
3834
+ if symbol is not None:
3835
+ market = self.market(symbol)
3836
+ request['instrument_id'] = market['id']
3837
+ if limit is not None:
3838
+ request['limit'] = limit
3839
+ if since is not None:
3840
+ request['start_timestamp'] = since
3841
+ response = await self.privateSwapGetAccountFundingFee(self.extend(request, params))
3842
+ #
3843
+ # {
3844
+ # "code": 0,
3845
+ # "data": [
3846
+ # {
3847
+ # "instrument_id": "BTCUSDTPERP",
3848
+ # "currency": "USDT",
3849
+ # "amount": "-0.000342814",
3850
+ # "timestamp": 1698768009440
3851
+ # }
3852
+ # ]
3853
+ # }
3854
+ #
3855
+ data = self.safe_list(response, 'data', [])
3856
+ return self.parse_incomes(data, market, since, limit)
3857
+
3858
+ def parse_income(self, income, market: Market = None):
3859
+ #
3860
+ # {
3861
+ # "instrument_id": "BTCUSDTPERP",
3862
+ # "currency": "USDT",
3863
+ # "amount": "-0.000342814",
3864
+ # "timestamp": 1698768009440
3865
+ # }
3866
+ #
3867
+ marketId = self.safe_string(income, 'instrument_id')
3868
+ currencyId = self.safe_string(income, 'currency')
3869
+ timestamp = self.safe_integer(income, 'timestamp')
3870
+ return {
3871
+ 'info': income,
3872
+ 'symbol': self.safe_symbol(marketId, market, None, 'swap'),
3873
+ 'code': self.safe_currency_code(currencyId),
3874
+ 'timestamp': timestamp,
3875
+ 'datetime': self.iso8601(timestamp),
3876
+ 'id': None,
3877
+ 'amount': self.safe_number(income, 'amount'),
3878
+ }
3879
+
3880
+ async def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
3881
+ """
3882
+ set margin mode to 'cross' or 'isolated'
3883
+ :see: https://docs.digifinex.com/en-ww/swap/v2/rest.html#positionmode
3884
+ :param str marginMode: 'cross' or 'isolated'
3885
+ :param str symbol: unified market symbol
3886
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3887
+ :returns dict: response from the exchange
3888
+ """
3889
+ if symbol is None:
3890
+ raise ArgumentsRequired(self.id + ' setMarginMode() requires a symbol argument')
3891
+ await self.load_markets()
3892
+ market = self.market(symbol)
3893
+ marginMode = marginMode.lower()
3894
+ if marginMode == 'cross':
3895
+ marginMode = 'crossed'
3896
+ request: dict = {
3897
+ 'instrument_id': market['id'],
3898
+ 'margin_mode': marginMode,
3899
+ }
3900
+ return await self.privateSwapPostAccountPositionMode(self.extend(request, params))
3901
+
3902
+ def sign(self, path, api=[], method='GET', params={}, headers=None, body=None):
3903
+ signed = api[0] == 'private'
3904
+ endpoint = api[1]
3905
+ pathPart = '/v3' if (endpoint == 'spot') else '/swap/v2'
3906
+ request = '/' + self.implode_params(path, params)
3907
+ payload = pathPart + request
3908
+ url = self.urls['api']['rest'] + payload
3909
+ query = self.omit(params, self.extract_params(path))
3910
+ urlencoded = None
3911
+ if signed and (pathPart == '/swap/v2') and (method == 'POST'):
3912
+ urlencoded = json.dumps(params)
3913
+ else:
3914
+ urlencoded = self.urlencode(self.keysort(query))
3915
+ if signed:
3916
+ auth = None
3917
+ nonce = None
3918
+ if pathPart == '/swap/v2':
3919
+ nonce = str(self.milliseconds())
3920
+ auth = nonce + method + payload
3921
+ if method == 'GET':
3922
+ if urlencoded:
3923
+ auth += '?' + urlencoded
3924
+ elif method == 'POST':
3925
+ auth += urlencoded
3926
+ else:
3927
+ nonce = str(self.nonce())
3928
+ auth = urlencoded
3929
+ signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256)
3930
+ if method == 'GET':
3931
+ if urlencoded:
3932
+ url += '?' + urlencoded
3933
+ elif method == 'POST':
3934
+ headers = {
3935
+ 'Content-Type': 'application/x-www-form-urlencoded',
3936
+ }
3937
+ if urlencoded:
3938
+ body = urlencoded
3939
+ headers = {
3940
+ 'ACCESS-KEY': self.apiKey,
3941
+ 'ACCESS-SIGN': signature,
3942
+ 'ACCESS-TIMESTAMP': nonce,
3943
+ }
3944
+ else:
3945
+ if urlencoded:
3946
+ url += '?' + urlencoded
3947
+ return {'url': url, 'method': method, 'body': body, 'headers': headers}
3948
+
3949
+ def handle_errors(self, statusCode: int, statusText: str, url: str, method: str, responseHeaders: dict, responseBody, response, requestHeaders, requestBody):
3950
+ if not response:
3951
+ return None # fall back to default error handler
3952
+ code = self.safe_string(response, 'code')
3953
+ if (code == '0') or (code == '200'):
3954
+ return None # no error
3955
+ feedback = self.id + ' ' + responseBody
3956
+ if code is None:
3957
+ raise BadResponse(feedback)
3958
+ unknownError = [ExchangeError, feedback]
3959
+ ExceptionClass, message = self.safe_value(self.exceptions['exact'], code, unknownError)
3960
+ raise ExceptionClass(message)