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